package runner

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/acceptanceemulator"
	"github.com/easyai/easyai-ai-gateway/apps/api/internal/clients"
	"github.com/easyai/easyai-ai-gateway/apps/api/internal/store"
)

func TestLocalAcceptanceObjectStorageFailoverMatrix(t *testing.T) {
	emulator := httptest.NewServer(acceptanceemulator.New(acceptanceemulator.Config{}).Handler())
	defer emulator.Close()
	service := &Service{}
	payload := FileUploadPayload{
		Bytes: []byte("acceptance-object"), ContentType: "image/png", Scene: store.FileStorageSceneRequestAsset,
	}

	tests := []struct {
		name        string
		channels    []store.FileStorageChannel
		winner      string
		wantErrCode string
	}{
		{
			name: "oss_auth_to_s3",
			channels: []store.FileStorageChannel{
				acceptanceStorageChannel("aliyun_oss", emulator.URL+"/storage/oss-auth/bucket", "oss-auth", false),
				acceptanceStorageChannel("s3", emulator.URL+"/storage/s3", "s3-ok", false),
			},
			winner: "s3-ok",
		},
		{
			name: "s3_auth_to_oss",
			channels: []store.FileStorageChannel{
				acceptanceStorageChannel("s3", emulator.URL+"/storage/s3-auth", "s3-auth", false),
				acceptanceStorageChannel("aliyun_oss", emulator.URL+"/storage/oss/bucket", "oss-ok", false),
			},
			winner: "oss-ok",
		},
		{
			name: "same_channel_transient_retry",
			channels: []store.FileStorageChannel{
				acceptanceStorageChannel("s3", emulator.URL+"/storage/s3-transient", "s3-transient", true),
				acceptanceStorageChannel("aliyun_oss", emulator.URL+"/storage/oss/bucket", "oss-unused", false),
			},
			winner: "s3-transient",
		},
		{
			name: "all_channels_failed",
			channels: []store.FileStorageChannel{
				acceptanceStorageChannel("aliyun_oss", emulator.URL+"/storage/oss-fail/bucket", "oss-fail", false),
				acceptanceStorageChannel("s3", emulator.URL+"/storage/s3-fail", "s3-fail", false),
			},
			wantErrCode: "storage_write_failed",
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			result, err := service.uploadFileWithFailover(t.Context(), payload, test.channels)
			if test.wantErrCode != "" {
				if clients.ErrorCode(err) != test.wantErrCode {
					t.Fatalf("error=%v code=%s", err, clients.ErrorCode(err))
				}
				return
			}
			if err != nil {
				t.Fatal(err)
			}
			channel, _ := result["storageChannel"].(map[string]any)
			if got := stringFromAny(channel["channelKey"]); got != test.winner {
				t.Fatalf("winner=%q, want %q", got, test.winner)
			}
		})
	}

	response, err := http.Get(emulator.URL + "/report")
	if err != nil {
		t.Fatal(err)
	}
	defer response.Body.Close()
	var report acceptanceemulator.Report
	if err := json.NewDecoder(response.Body).Decode(&report); err != nil {
		t.Fatal(err)
	}
	if report.StoragePuts != 3 || report.StorageFailures != 5 {
		t.Fatalf("unexpected storage acceptance report: %+v", report)
	}
}

func acceptanceStorageChannel(provider string, endpoint string, key string, retry bool) store.FileStorageChannel {
	channel := testObjectStorageChannel(provider, endpoint, key)
	channel.Config["publicBaseUrl"] = ""
	channel.RetryPolicy = map[string]any{"enabled": retry, "maxRetries": 0}
	if retry {
		channel.RetryPolicy = map[string]any{"enabled": true, "maxRetries": 1, "backoffSeconds": []any{0.001}}
	}
	return channel
}
