package oci

import (
	"context"
	"fmt"
	"os"
	"strings"
	"testing"
	"time"
)

// TestRealOCITenantUsers 验证用户管理全链路：新增 → 重置密码 →
// 清 MFA → 清 API Key → 删除，全部只操作新建的测试用户。
func TestRealOCITenantUsers(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(), 5*time.Minute)
	defer cancel()
	cred := loadTestCredentials(t, "试用期")
	client := NewClient()
	homeRegion := cred.Region

	users, err := client.ListTenantUsers(ctx, cred, homeRegion, "")
	if err != nil {
		t.Fatalf("ListTenantUsers: %v", err)
	}
	if len(users) == 0 {
		t.Fatal("no tenant users, want at least the current one")
	}
	currentSeen := false
	for _, u := range users {
		if u.IsCurrentUser {
			currentSeen = true
		}
	}
	if !currentSeen {
		t.Error("current user not flagged in list")
	}
	t.Logf("tenant users: %d", len(users))

	name := fmt.Sprintf("oci-portal-e2e-user-%d", time.Now().Unix())
	user, err := client.CreateTenantUser(ctx, cred, homeRegion, "", CreateTenantUserInput{
		Name: name, Description: "e2e temp user", Email: name + "@example.com",
		GivenName: "E2E", FamilyName: "Temp",
	})
	if err != nil {
		t.Fatalf("CreateTenantUser: %v", err)
	}
	t.Logf("created user %s (%s)", user.Name, user.ID)
	defer func() {
		if err := client.DeleteTenantUser(ctx, cred, homeRegion, "", user.ID); err != nil {
			t.Errorf("cleanup: DeleteTenantUser: %v", err)
		} else {
			t.Log("cleanup: user deleted")
		}
	}()

	newDesc, newEmail, newGiven := "e2e updated", name+"+upd@example.com", "E2E2"
	updated, err := client.UpdateTenantUser(ctx, cred, homeRegion, "", user.ID, UpdateTenantUserInput{
		Description: &newDesc, Email: &newEmail, GivenName: &newGiven,
	})
	if err != nil {
		t.Fatalf("UpdateTenantUser: %v", err)
	}
	if updated.Description != newDesc {
		t.Errorf("updated description = %q, want %q", updated.Description, newDesc)
	}
	t.Logf("updated user desc=%q email=%q", updated.Description, updated.Email)

	password, err := client.ResetTenantUserPassword(ctx, cred, homeRegion, "", user.ID)
	if err != nil {
		t.Fatalf("ResetTenantUserPassword: %v", err)
	}
	if password == "" {
		t.Error("reset password returned empty password")
	}
	t.Logf("password reset ok (len=%d)", len(password))

	mfaDeleted, err := client.DeleteTenantUserMfaDevices(ctx, cred, homeRegion, "", user.ID)
	if err != nil {
		t.Fatalf("DeleteTenantUserMfaDevices: %v", err)
	}
	t.Logf("mfa devices deleted: %d", mfaDeleted)

	keysDeleted, err := client.DeleteTenantUserApiKeys(ctx, cred, homeRegion, user.ID, false)
	if err != nil {
		t.Fatalf("DeleteTenantUserApiKeys: %v", err)
	}
	t.Logf("api keys deleted: %d", keysDeleted)
}

// TestRealOCIDomainSettings 验证通知收件人与密码策略的改后恢复。
func TestRealOCIDomainSettings(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(), 5*time.Minute)
	defer cancel()
	cred := loadTestCredentials(t, "试用期")
	client := NewClient()
	region := cred.Region

	original, err := client.GetNotificationRecipients(ctx, cred, region, "")
	if err != nil {
		t.Fatalf("GetNotificationRecipients: %v", err)
	}
	t.Logf("original recipients=%v testMode=%v", original.Recipients, original.TestModeEnabled)
	updated, err := client.UpdateNotificationRecipients(ctx, cred, region, "", []string{"e2e@example.com"})
	if err != nil {
		t.Fatalf("UpdateNotificationRecipients: %v", err)
	}
	if !updated.TestModeEnabled || len(updated.Recipients) != 1 {
		t.Errorf("updated = %+v, want test mode with 1 recipient", updated)
	}
	restoreRecipients := original.Recipients
	if !original.TestModeEnabled {
		restoreRecipients = nil
	}
	if _, err := client.UpdateNotificationRecipients(ctx, cred, region, "", restoreRecipients); err != nil {
		t.Errorf("restore recipients: %v", err)
	} else {
		t.Log("recipients restored")
	}

	policies, err := client.ListPasswordPolicies(ctx, cred, region, "")
	if err != nil {
		t.Fatalf("ListPasswordPolicies: %v", err)
	}
	target, ok := pickCustomPolicy(policies)
	if !ok {
		t.Fatalf("no Custom password policy among %d policies (built-ins are read-only)", len(policies))
	}
	t.Logf("policies: %d, patch target %s strength=%s expires=%v", len(policies), target.Name, target.PasswordStrength, target.PasswordExpiresAfter)
	days := 350
	patched, err := client.UpdatePasswordPolicy(ctx, cred, region, "", target.ID, UpdatePasswordPolicyInput{PasswordExpiresAfter: &days})
	if err != nil {
		t.Fatalf("UpdatePasswordPolicy: %v", err)
	}
	if patched.PasswordExpiresAfter == nil || *patched.PasswordExpiresAfter != days {
		t.Errorf("passwordExpiresAfter = %v, want %d", patched.PasswordExpiresAfter, days)
	}
	restore := 0
	if target.PasswordExpiresAfter != nil {
		restore = *target.PasswordExpiresAfter
	}
	if _, err := client.UpdatePasswordPolicy(ctx, cred, region, "", target.ID, UpdatePasswordPolicyInput{PasswordExpiresAfter: &restore}); err != nil {
		t.Errorf("restore password policy: %v", err)
	} else {
		t.Logf("policy restored to %d", restore)
	}
}

// pickCustomPolicy 返回 Custom 强度的密码策略；Simple/Standard 内置策略只读不可改。
func pickCustomPolicy(policies []PasswordPolicyInfo) (PasswordPolicyInfo, bool) {
	for _, p := range policies {
		if strings.EqualFold(p.PasswordStrength, "custom") {
			return p, true
		}
	}
	return PasswordPolicyInfo{}, false
}

// TestRealOCIUsageAndTraffic 验证成本分析与实例流量统计：
// 成本查最近 7 天；流量需要真实 VNIC，无实例时创建一台临时 Micro 实例。
func TestRealOCIUsageAndTraffic(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(), 15*time.Minute)
	defer cancel()
	cred := loadTestCredentials(t, "试用期")
	client := NewClient()

	end := time.Now().UTC().Truncate(24*time.Hour).AddDate(0, 0, 1)
	items, err := client.SummarizeCosts(ctx, cred, CostQuery{
		StartTime:   end.AddDate(0, 0, -7),
		EndTime:     end,
		Granularity: "DAILY",
		QueryType:   "COST",
		GroupBy:     "service",
	})
	if err != nil {
		t.Fatalf("SummarizeCosts: %v", err)
	}
	t.Logf("cost items: %d", len(items))
	for i, item := range items {
		if i >= 3 {
			break
		}
		t.Logf("  %s %s %.4f %s", item.TimeStart, item.GroupValue, item.ComputedAmount, item.Currency)
	}

	instanceID := ensureTrafficInstance(ctx, t, client, cred)
	traffic, err := client.SummarizeInstanceTraffic(ctx, cred, TrafficQuery{
		InstanceID: instanceID,
		StartTime:  end.AddDate(0, 0, -7),
		EndTime:    end,
	})
	if err != nil {
		t.Fatalf("SummarizeInstanceTraffic: %v", err)
	}
	t.Logf("traffic vnics=%d in=%.0fB out=%.0fB", len(traffic.Vnics), traffic.InboundBytes, traffic.OutboundBytes)
	if len(traffic.Vnics) == 0 {
		t.Error("no vnic in traffic result, want at least one")
	}
}

// ensureTrafficInstance 返回一个可查流量的实例：已有实例直接用，
// 否则创建一台临时 E2 Micro（测试结束删除）。
func ensureTrafficInstance(ctx context.Context, t *testing.T, client *RealClient, cred Credentials) string {
	t.Helper()
	instances, err := client.ListInstances(ctx, cred, "")
	if err != nil {
		t.Fatalf("ListInstances: %v", err)
	}
	for _, in := range instances {
		if in.LifecycleState == "RUNNING" || in.LifecycleState == "STOPPED" {
			t.Logf("using existing instance %s", in.ID)
			return in.ID
		}
	}
	images, err := client.ListImages(ctx, cred, ImagesQuery{OperatingSystem: "Canonical Ubuntu", Shape: "VM.Standard.E2.1.Micro"})
	if err != nil || len(images) == 0 {
		t.Skipf("no micro image available: %v", err)
	}
	instance, err := client.LaunchInstance(ctx, cred, CreateInstanceInput{
		DisplayName:    fmt.Sprintf("oci-portal-e2e-traffic-%d", time.Now().Unix()),
		Shape:          "VM.Standard.E2.1.Micro",
		ImageID:        images[0].ID,
		AssignPublicIP: false,
		SSHPublicKey:   "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEfake+e2e+key oci-portal-e2e",
	})
	if err != nil {
		if strings.Contains(err.Error(), "capacity") || strings.Contains(err.Error(), "LimitExceeded") {
			t.Skipf("micro capacity unavailable: %v", err)
		}
		t.Fatalf("LaunchInstance: %v", err)
	}
	t.Cleanup(func() {
		terminateAndWait(t, client, cred, instance.ID)
		cleanupAutoVCNIfAny(t, client, cred)
	})
	// VNIC attachment 在实例 RUNNING 后才就绪，否则流量查询列不到 VNIC
	if err := waitInstanceState(ctx, client, cred, instance.ID, "RUNNING"); err != nil {
		t.Fatalf("wait instance running: %v", err)
	}
	return instance.ID
}

// cleanupAutoVCNIfAny 清理临时实例触发自动建网留下的 auto-vcn。
func cleanupAutoVCNIfAny(t *testing.T, client *RealClient, cred Credentials) {
	t.Helper()
	ctx, cancel := context.WithTimeout(context.Background(), 3*time.Minute)
	defer cancel()
	vcns, err := client.ListVCNs(ctx, cred, "")
	if err != nil {
		return
	}
	for _, v := range vcns {
		if v.DisplayName == autoVcnName {
			cleanupVCN(t, client, cred, v.ID)
		}
	}
}
