package idempotency_test

import (
	"context"
	"sync"
	"testing"

	"github.com/break/junhong_cmp_fiber/internal/testutil"
	"github.com/break/junhong_cmp_fiber/pkg/idempotency"
)

func TestPostgresUniqueConstraintArbitratesConcurrentFirstSubmission(t *testing.T) {
	db := testutil.NewPostgresTransaction(t)
	if err := db.Exec(`
		CREATE TEMP TABLE test_command_idempotency (
			subject varchar(100) NOT NULL,
			operation varchar(100) NOT NULL,
			request_id varchar(100) NOT NULL,
			fingerprint varchar(128) NOT NULL,
			result_id bigint NOT NULL,
			UNIQUE (subject, operation, request_id)
		) ON COMMIT DROP`).Error; err != nil {
		t.Fatalf("创建幂等契约测试表失败：%v", err)
	}

	fingerprint, err := idempotency.Fingerprint(map[string]any{"amount": 100})
	if err != nil {
		t.Fatalf("计算指纹失败：%v", err)
	}

	start := make(chan struct{})
	results := make(chan int64, 2)
	errs := make(chan error, 2)
	var wait sync.WaitGroup
	for _, resultID := range []int64{101, 102} {
		wait.Add(1)
		go func(id int64) {
			defer wait.Done()
			<-start
			result := db.WithContext(context.Background()).Exec(`
				INSERT INTO test_command_idempotency
					(subject, operation, request_id, fingerprint, result_id)
				VALUES (?, ?, ?, ?, ?)
				ON CONFLICT (subject, operation, request_id) DO NOTHING`,
				"account:7", "agent-recharge.create", "request-1", fingerprint.Value, id,
			)
			results <- result.RowsAffected
			errs <- result.Error
		}(resultID)
	}
	close(start)
	wait.Wait()
	close(results)
	close(errs)

	var inserted int64
	for resultErr := range errs {
		if resultErr != nil {
			t.Fatalf("并发写入失败：%v", resultErr)
		}
	}
	for affected := range results {
		inserted += affected
	}
	if inserted != 1 {
		t.Fatalf("并发首写必须只有一个数据库事实，实际插入：%d", inserted)
	}

	var count int64
	if err := db.Table("test_command_idempotency").Count(&count).Error; err != nil {
		t.Fatalf("统计幂等事实失败：%v", err)
	}
	if count != 1 {
		t.Fatalf("幂等事实数量错误：%d", count)
	}
}

func TestIdempotencyScopeDoesNotDependOnRedis(t *testing.T) {
	t.Parallel()

	scope := idempotency.Scope{Subject: "account:7", Operation: "example.create"}
	if !idempotency.ValidateScope(scope, "request-1") {
		t.Fatal("完整作用域和请求 ID 应通过校验")
	}
	// 公共幂等契约没有 Redis 参数；Redis 仅可由业务作为削峰优化，不能参与最终裁决。
}
