package provision

import (
	"context"
	"reflect"
	"testing"

	"sub2api-cn-relay-manager/internal/host/sub2api"
	"sub2api-cn-relay-manager/internal/pack"
)

func TestSuggestResourceNames(t *testing.T) {
	provider := sampleProviderManifest()

	names := SuggestResourceNames(provider)

	want := ResourceNames{
		Group:   "DeepSeek 默认分组",
		Channel: "DeepSeek 默认渠道",
		Plan:    "DeepSeek 默认套餐",
	}
	if !reflect.DeepEqual(names, want) {
		t.Fatalf("SuggestResourceNames() = %#v, want %#v", names, want)
	}
}

func TestSuggestResourceNamesIncludesAccessModeSuffix(t *testing.T) {
	provider := sampleProviderManifest()
	provider.GroupTemplate.Name = ""
	provider.ChannelTemplate.Name = ""
	provider.PlanTemplate.Name = ""

	names := SuggestResourceNamesForMode(provider, AccessModeSubscription)
	want := ResourceNames{
		Group:   "crm-deepseek-group-subscription",
		Channel: "crm-deepseek-channel-subscription",
		Plan:    "crm-deepseek-plan-subscription",
	}
	if !reflect.DeepEqual(names, want) {
		t.Fatalf("SuggestResourceNamesForMode() = %#v, want %#v", names, want)
	}
}

func TestPreviewServiceReportsCreateActionsWhenHostHasNoResources(t *testing.T) {
	host := &fakePreviewHost{}
	svc := NewPreviewService(host)

	report, err := svc.PreviewImport(context.Background(), PreviewRequest{
		Provider: sampleProviderManifest(),
		Mode:     ImportModeStrict,
		Keys:     []string{" key-1 ", "key-2", "key-1"},
	})
	if err != nil {
		t.Fatalf("PreviewImport() error = %v", err)
	}

	if !reflect.DeepEqual(report.AcceptedKeys, []string{"key-1", "key-2"}) {
		t.Fatalf("AcceptedKeys = %#v, want normalized deduped keys", report.AcceptedKeys)
	}
	if got := report.Decisions["group"]; got.Action != PreviewActionCreate {
		t.Fatalf("group action = %q, want %q", got.Action, PreviewActionCreate)
	}
	if got := report.Decisions["channel"]; got.Action != PreviewActionCreate {
		t.Fatalf("channel action = %q, want %q", got.Action, PreviewActionCreate)
	}
	if got := report.Decisions["plan"]; got.Action != PreviewActionCreate {
		t.Fatalf("plan action = %q, want %q", got.Action, PreviewActionCreate)
	}
}

func TestPreviewServiceIncludesMatchingHostOverlays(t *testing.T) {
	host := &fakePreviewHost{}
	svc := NewPreviewService(host)

	provider := sampleProviderManifest()
	provider.HostOverlays = []pack.HostOverlay{{
		OverlayID:      "sub2api-stock-v0129-kimi-a7m",
		DisplayName:    "sub2api stock v0.1.129 Kimi A7M overlay",
		TargetHost:     "sub2api",
		MinHostVersion: "0.1.129",
		MaxHostVersion: "0.1.129",
		Reason:         "stock host still routes chat traffic into unsupported Responses path",
	}}

	report, err := svc.PreviewImport(context.Background(), PreviewRequest{
		TargetHost:  "sub2api",
		HostVersion: "0.1.129",
		Provider:    provider,
		Mode:        ImportModePartial,
		Keys:        []string{"key-1"},
	})
	if err != nil {
		t.Fatalf("PreviewImport() error = %v", err)
	}
	if len(report.HostOverlays) != 1 || report.HostOverlays[0].OverlayID != "sub2api-stock-v0129-kimi-a7m" {
		t.Fatalf("HostOverlays = %+v, want matching overlay", report.HostOverlays)
	}
}

func TestPreviewServiceReportsReuseAndConflict(t *testing.T) {
	host := &fakePreviewHost{snapshot: sub2api.ManagedResourceSnapshot{
		Groups:   []sub2api.NamedResource{{ID: "group_1", Name: "DeepSeek 默认分组"}},
		Channels: []sub2api.NamedResource{{ID: "channel_1", Name: "DeepSeek 默认渠道"}, {ID: "channel_2", Name: "DeepSeek 默认渠道"}},
		Plans:    []sub2api.NamedResource{{ID: "plan_1", Name: "DeepSeek 默认套餐"}},
	}}
	svc := NewPreviewService(host)

	report, err := svc.PreviewImport(context.Background(), PreviewRequest{
		Provider: sampleProviderManifest(),
		Mode:     ImportModePartial,
		Keys:     []string{"key-1"},
	})
	if err != nil {
		t.Fatalf("PreviewImport() error = %v", err)
	}

	if got := report.Decisions["group"]; got.Action != PreviewActionReuse || got.ExistingID != "group_1" {
		t.Fatalf("group decision = %#v, want reuse group_1", got)
	}
	if got := report.Decisions["plan"]; got.Action != PreviewActionReuse || got.ExistingID != "plan_1" {
		t.Fatalf("plan decision = %#v, want reuse plan_1", got)
	}
	if got := report.Decisions["channel"]; got.Action != PreviewActionConflict {
		t.Fatalf("channel decision = %#v, want conflict", got)
	}
}

func TestPreviewServicePassesAccountNamePrefixToManagedResourceSnapshot(t *testing.T) {
	host := &fakePreviewHost{}
	svc := NewPreviewService(host)

	provider := sampleProviderManifest()
	provider.ProviderID = "openai-zhongzhuan"
	if _, err := svc.PreviewImport(context.Background(), PreviewRequest{
		Provider: provider,
		Mode:     ImportModePartial,
		Keys:     []string{"key-1"},
	}); err != nil {
		t.Fatalf("PreviewImport() error = %v", err)
	}
	if host.req.AccountNamePrefix != "openai-zhongzhuan-" {
		t.Fatalf("AccountNamePrefix = %q, want %q", host.req.AccountNamePrefix, "openai-zhongzhuan-")
	}
}

type fakePreviewHost struct {
	snapshot sub2api.ManagedResourceSnapshot
	req      sub2api.ListManagedResourcesRequest
}

func (f *fakePreviewHost) ListManagedResources(_ context.Context, req sub2api.ListManagedResourcesRequest) (sub2api.ManagedResourceSnapshot, error) {
	f.req = req
	return f.snapshot, nil
}
