package service

import (
	"context"
	"testing"

	"oci-portal/internal/model"
	"oci-portal/internal/oci"
)

func multiScopeClient() *fakeClient {
	return &fakeClient{
		tenancy: oci.TenancyInfo{Name: "t", HomeRegionKey: "FRA"},
		regionSubs: []oci.RegionSubscription{
			{Key: "FRA", Name: "eu-frankfurt-1", Status: "READY", IsHomeRegion: true},
			{Key: "AMS", Name: "eu-amsterdam-1", Status: "READY"},
		},
		compartments: []oci.Compartment{
			{ID: "ocid1.compartment..a", Name: "instances", LifecycleState: "ACTIVE"},
		},
	}
}

func importMultiConfig(t *testing.T, svc *OciConfigService) *model.OciConfig {
	t.Helper()
	in := trialImportInput()
	in.MultiRegion = true
	in.MultiCompartment = true
	cfg, err := svc.Import(context.Background(), in)
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	return cfg
}

func TestImportSyncsScopeCaches(t *testing.T) {
	client := multiScopeClient()
	svc := newTestService(t, client)
	cfg := importMultiConfig(t, svc)

	if !cfg.MultiRegion || !cfg.MultiCompartment {
		t.Fatalf("cfg switches = %v/%v, want true/true", cfg.MultiRegion, cfg.MultiCompartment)
	}
	var regions []model.RegionCache
	svc.db.Where("oci_config_id = ?", cfg.ID).Find(&regions)
	if len(regions) != 2 {
		t.Errorf("region cache rows = %d, want 2", len(regions))
	}
	var comps []model.CompartmentCache
	svc.db.Where("oci_config_id = ?", cfg.ID).Find(&comps)
	if len(comps) != 1 || comps[0].OCID != "ocid1.compartment..a" {
		t.Errorf("compartment cache = %+v, want 1 row ocid1.compartment..a", comps)
	}
}

func TestImportWithoutSwitchesSkipsCaches(t *testing.T) {
	client := multiScopeClient()
	svc := newTestService(t, client)
	cfg := importAliveConfig(t, svc)

	var count int64
	svc.db.Model(&model.RegionCache{}).Where("oci_config_id = ?", cfg.ID).Count(&count)
	if count != 0 {
		t.Errorf("region cache rows = %d, want 0（未开启不入库）", count)
	}
}

func TestCachedRegions(t *testing.T) {
	tests := []struct {
		name      string
		prepare   func(svc *OciConfigService, cfg *model.OciConfig, client *fakeClient)
		wantNames []string
		wantCalls int // 缓存读取阶段期望的 SDK 调用次数
	}{
		{
			name:      "全 READY 直接用缓存",
			prepare:   func(*OciConfigService, *model.OciConfig, *fakeClient) {},
			wantNames: []string{"eu-frankfurt-1", "eu-amsterdam-1"},
			wantCalls: 0,
		},
		{
			name: "存在非 READY 强制实时刷新",
			prepare: func(svc *OciConfigService, cfg *model.OciConfig, client *fakeClient) {
				svc.db.Model(&model.RegionCache{}).
					Where("oci_config_id = ? AND key = ?", cfg.ID, "AMS").
					Update("status", "IN_PROGRESS")
				client.regionSubs[1].Status = "READY" // SDK 已完成
			},
			wantNames: []string{"eu-frankfurt-1", "eu-amsterdam-1"},
			wantCalls: 1,
		},
		{
			name: "缓存为空实时拉取入库",
			prepare: func(svc *OciConfigService, cfg *model.OciConfig, client *fakeClient) {
				svc.db.Where("oci_config_id = ?", cfg.ID).Delete(&model.RegionCache{})
			},
			wantNames: []string{"eu-frankfurt-1", "eu-amsterdam-1"},
			wantCalls: 1,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			client := multiScopeClient()
			svc := newTestService(t, client)
			cfg := importMultiConfig(t, svc)
			tt.prepare(svc, cfg, client)
			client.regionSubsCalls = 0

			views, err := svc.CachedRegions(context.Background(), cfg.ID)
			if err != nil {
				t.Fatalf("CachedRegions: %v", err)
			}
			got := make([]string, 0, len(views))
			for _, v := range views {
				got = append(got, v.Name)
			}
			if len(got) != len(tt.wantNames) {
				t.Fatalf("regions = %v, want %v", got, tt.wantNames)
			}
			if client.regionSubsCalls != tt.wantCalls {
				t.Errorf("SDK calls = %d, want %d", client.regionSubsCalls, tt.wantCalls)
			}
		})
	}
}

func TestCachedRegionsWithoutMultiRegion(t *testing.T) {
	client := multiScopeClient()
	svc := newTestService(t, client)
	cfg := importAliveConfig(t, svc)
	client.regionSubsCalls = 0

	views, err := svc.CachedRegions(context.Background(), cfg.ID)
	if err != nil {
		t.Fatalf("CachedRegions: %v", err)
	}
	if len(views) != 1 || views[0].Name != "eu-frankfurt-1" || !views[0].IsHomeRegion {
		t.Errorf("views = %+v, want 仅默认区域且标记主区域", views)
	}
	if client.regionSubsCalls != 0 {
		t.Errorf("SDK calls = %d, want 0（未开启不实时请求）", client.regionSubsCalls)
	}
}

func TestCachedCompartments(t *testing.T) {
	client := multiScopeClient()
	svc := newTestService(t, client)
	multiCfg := importMultiConfig(t, svc)

	comps, err := svc.CachedCompartments(context.Background(), multiCfg.ID)
	if err != nil {
		t.Fatalf("CachedCompartments: %v", err)
	}
	if len(comps) != 1 || comps[0].ID != "ocid1.compartment..a" {
		t.Errorf("comps = %+v, want 缓存中的 1 项", comps)
	}

	in := trialImportInput()
	in.Alias = "未开启"
	plainCfg, err := svc.Import(context.Background(), in)
	if err != nil {
		t.Fatalf("Import: %v", err)
	}
	comps, err = svc.CachedCompartments(context.Background(), plainCfg.ID)
	if err != nil {
		t.Fatalf("CachedCompartments: %v", err)
	}
	if len(comps) != 0 {
		t.Errorf("comps = %+v, want 空（未开启多区间）", comps)
	}
}

func TestRegionSubscriptionsReconcilesCache(t *testing.T) {
	client := multiScopeClient()
	svc := newTestService(t, client)
	cfg := importMultiConfig(t, svc)

	// SDK 侧新订阅一个区域，订阅 Tab 实时读取后缓存应跟进
	client.regionSubs = append(client.regionSubs,
		oci.RegionSubscription{Key: "ICN", Name: "ap-seoul-1", Status: "IN_PROGRESS"})
	if _, err := svc.RegionSubscriptions(context.Background(), cfg.ID); err != nil {
		t.Fatalf("RegionSubscriptions: %v", err)
	}
	var rows []model.RegionCache
	svc.db.Where("oci_config_id = ?", cfg.ID).Find(&rows)
	if len(rows) != 3 {
		t.Fatalf("cache rows = %d, want 3（diff 后跟进）", len(rows))
	}

	// 关闭开关的配置不应回写缓存
	off := false
	if _, _, err := svc.Update(context.Background(), cfg.ID, UpdateInput{MultiRegion: &off}); err != nil {
		t.Fatalf("Update: %v", err)
	}
	var count int64
	svc.db.Model(&model.RegionCache{}).Where("oci_config_id = ?", cfg.ID).Count(&count)
	if count != 0 {
		t.Errorf("cache rows = %d, want 0（关闭开关清空缓存）", count)
	}
}
