package oci

import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"oci-portal/internal/model"
)

// testKeyDir 指向仓库根的真实 API Key 测试资料目录。
const testKeyDir = "../../../test-api-key"

// keyCase 把测试 key 文件名映射到期望账户类别；expect 为空表示只打印不断言。
type keyCase struct {
	name   string
	expect string
}

func integrationKeyCases(t *testing.T) []keyCase {
	t.Helper()
	all := []keyCase{
		{name: "试用期", expect: model.AccountTypeTrial},
		{name: "付费", expect: model.AccountTypePaid},
		{name: "免费01", expect: model.AccountTypeFree},
		{name: "免费02", expect: model.AccountTypeFree},
		{name: "未知01"},
		{name: "未知02"},
	}
	if name := os.Getenv("OCI_TEST_KEY"); name != "" {
		for _, k := range all {
			if k.name == name {
				return []keyCase{k}
			}
		}
		t.Fatalf("OCI_TEST_KEY=%q not found in test-api-key", name)
	}
	if os.Getenv("OCI_TEST_ALL_KEYS") == "1" {
		return all
	}
	// 默认只使用试用期 key，避免不必要地触碰其他真实账号
	return all[:1]
}

func loadTestCredentials(t *testing.T, name string) Credentials {
	t.Helper()
	iniPath := filepath.Join(testKeyDir, name+"-api-key.ini")
	pemPath := filepath.Join(testKeyDir, name+"-api-key.pem")
	iniText, err := os.ReadFile(iniPath)
	if err != nil {
		t.Fatalf("read %s: %v", iniPath, err)
	}
	pem, err := os.ReadFile(pemPath)
	if err != nil {
		t.Fatalf("read %s: %v", pemPath, err)
	}
	cred, err := ParseConfigINI(string(iniText))
	if err != nil {
		t.Fatalf("parse %s: %v", iniPath, err)
	}
	cred.PrivateKey = string(pem)
	if err := cred.Validate(); err != nil {
		t.Fatalf("validate credentials of %s: %v", name, err)
	}
	return cred
}

// TestRealOCITenantRegionsAndLimits 用试用期 key 验证区域订阅列表和
// 配额查询（均为只读调用）。订阅新区域不可撤销，不做真实测试。
func TestRealOCITenantRegionsAndLimits(t *testing.T) {
	if os.Getenv("OCI_INTEGRATION_TEST") != "1" {
		t.Skip("set OCI_INTEGRATION_TEST=1 to run real OCI tests")
	}
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
	defer cancel()
	cred := loadTestCredentials(t, "试用期")
	client := NewClient()

	subs, err := client.ListRegionSubscriptions(ctx, cred)
	if err != nil {
		t.Fatalf("ListRegionSubscriptions: %v", err)
	}
	if len(subs) == 0 {
		t.Fatal("ListRegionSubscriptions returned empty list, want at least home region")
	}
	hasHome := false
	for _, sub := range subs {
		t.Logf("region key=%s name=%s status=%s home=%v", sub.Key, sub.Name, sub.Status, sub.IsHomeRegion)
		hasHome = hasHome || sub.IsHomeRegion
	}
	if !hasHome {
		t.Error("no home region in subscriptions")
	}

	values, err := client.ListLimits(ctx, cred, LimitsQuery{
		Service:          "compute",
		Name:             "standard-a1-core-count",
		WithAvailability: true,
	})
	if err != nil {
		t.Fatalf("ListLimits: %v", err)
	}
	if len(values) == 0 {
		t.Fatal("ListLimits returned empty list for standard-a1-core-count")
	}
	for _, v := range values {
		used, available := int64(-1), int64(-1)
		if v.Used != nil {
			used = *v.Used
		}
		if v.Available != nil {
			available = *v.Available
		}
		t.Logf("limit name=%s scope=%s ad=%s value=%d used=%d available=%d",
			v.Name, v.ScopeType, v.AvailabilityDomain, v.Value, used, available)
	}

	// 模糊过滤应比精确名命中更多配额（a1 与 e2 等系列都含 core-count）
	fuzzy, err := client.ListLimits(ctx, cred, LimitsQuery{Service: "compute", Name: "core-count"})
	if err != nil {
		t.Fatalf("ListLimits fuzzy: %v", err)
	}
	t.Logf("fuzzy core-count matched %d entries", len(fuzzy))
	if len(fuzzy) <= len(values) {
		t.Errorf("fuzzy matches = %d, want more than exact matches %d", len(fuzzy), len(values))
	}

	services, err := client.ListLimitServices(ctx, cred, "")
	if err != nil {
		t.Fatalf("ListLimitServices: %v", err)
	}
	if len(services) == 0 {
		t.Fatal("ListLimitServices returned empty list")
	}
	hasCompute := false
	for _, s := range services {
		hasCompute = hasCompute || s.Name == "compute"
	}
	if !hasCompute {
		t.Errorf("services (%d) missing compute", len(services))
	}
	t.Logf("limit services: %d entries, first=%+v", len(services), services[0])
}

// TestRealOCISubscriptions 用试用期 key 验证订阅列表与订阅详情（只读）。
func TestRealOCISubscriptions(t *testing.T) {
	if os.Getenv("OCI_INTEGRATION_TEST") != "1" {
		t.Skip("set OCI_INTEGRATION_TEST=1 to run real OCI tests")
	}
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
	defer cancel()
	cred := loadTestCredentials(t, "试用期")
	client := NewClient()

	subs, err := client.ListSubscriptions(ctx, cred)
	if err != nil {
		t.Fatalf("ListSubscriptions: %v", err)
	}
	if len(subs) == 0 {
		t.Fatal("ListSubscriptions returned empty list")
	}
	cloudcmID := ""
	for _, sub := range subs {
		t.Logf("subscription id=%s service=%s created=%v", sub.ID, sub.ServiceName, sub.TimeCreated)
		if strings.EqualFold(sub.ServiceName, cloudcmServiceName) {
			cloudcmID = sub.ID
		}
	}
	if cloudcmID == "" {
		t.Fatal("no CLOUDCM subscription in list")
	}

	detail, err := client.GetSubscription(ctx, cred, cloudcmID)
	if err != nil {
		t.Fatalf("GetSubscription: %v", err)
	}
	if detail.ID != cloudcmID {
		t.Errorf("detail.ID = %q, want %q", detail.ID, cloudcmID)
	}
	t.Logf("detail service=%s paymentModel=%q tier=%q state=%s currency=%s region=%s promotions=%d",
		detail.ServiceName, detail.PaymentModel, detail.SubscriptionTier,
		detail.LifecycleState, detail.CloudAmountCurrency, detail.RegionAssignment, len(detail.Promotions))
	for _, p := range detail.Promotions {
		t.Logf("promotion status=%s amount=%.2f %s expires=%v intentToPay=%v",
			p.Status, p.Amount, p.CurrencyUnit, p.TimeExpired, p.IsIntentToPay)
	}
	if len(detail.Promotions) == 0 {
		t.Error("trial subscription has no promotions, want at least one")
	}
}

// TestRealOCIVerifyAndClassify 走真实 OCI 验证测活与账户类别判定，
// 必须显式设置 OCI_INTEGRATION_TEST=1 才会执行。
func TestRealOCIVerifyAndClassify(t *testing.T) {
	if os.Getenv("OCI_INTEGRATION_TEST") != "1" {
		t.Skip("set OCI_INTEGRATION_TEST=1 to run real OCI tests")
	}
	client := NewClient()
	for _, tc := range integrationKeyCases(t) {
		t.Run(tc.name, func(t *testing.T) {
			ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
			defer cancel()
			cred := loadTestCredentials(t, tc.name)

			info, err := client.ValidateKey(ctx, cred)
			if err != nil {
				t.Fatalf("ValidateKey: %v", err)
			}
			t.Logf("tenancy=%s homeRegion=%s", info.Name, info.HomeRegionKey)

			profile, err := client.FetchAccountProfile(ctx, cred)
			if err != nil {
				t.Fatalf("FetchAccountProfile: %v", err)
			}
			t.Logf("type=%s paymentModel=%q tier=%q promo=%q amount=%.2f service=%s",
				profile.AccountType, profile.PaymentModel, profile.SubscriptionTier,
				profile.PromotionStatus, profile.PromotionAmount, profile.ServiceName)
			if !strings.EqualFold(profile.ServiceName, cloudcmServiceName) {
				t.Errorf("ServiceName = %q, want %q", profile.ServiceName, cloudcmServiceName)
			}
			if tc.expect != "" && profile.AccountType != tc.expect {
				t.Errorf("AccountType = %q, want %q", profile.AccountType, tc.expect)
			}
		})
	}
}
