package mysql

import (
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"hyapp/pkg/walletmq"
)

func TestResourceOutboxEventsUseStableEventIDAsTransactionID(t *testing.T) {
	// 这些是当前所有通过 resourceOutboxEvent 创建的资源事实；helper 对事件类型
	// 本身无分支，因此该约束也自动覆盖以后接入同一入口的新资源事实。
	eventTypes := []string{
		"GiftConfigChanged",
		"ResourceChanged",
		"ResourceGrantRevoked",
		"ResourceGranted",
		"ResourceGroupChanged",
		"ResourceGroupGranted",
		"UserResourceChanged",
		"VipEffectiveChanged",
		"VipTrialCardGranted",
	}
	for _, eventType := range eventTypes {
		t.Run(eventType, func(t *testing.T) {
			first := resourceOutboxEvent(eventType, "command-1", 1001, 2001, map[string]any{"source": "test"}, 1_700_000_000_000)
			second := resourceOutboxEvent(eventType, "command-1", 1001, 2001, map[string]any{"source": "retry"}, 1_700_000_000_999)
			if first.TransactionID == "" || first.TransactionID != first.EventID {
				t.Fatalf("resource correlation ids mismatch: event_id=%q transaction_id=%q", first.EventID, first.TransactionID)
			}
			if second.EventID != first.EventID || second.TransactionID != first.TransactionID {
				t.Fatalf("resource correlation id changed on retry: first=%+v second=%+v", first, second)
			}
			if len(first.TransactionID) > 96 {
				t.Fatalf("resource transaction_id exceeds wallet_outbox column: %d", len(first.TransactionID))
			}
			if _, err := walletmq.EncodeWalletOutboxMessage(walletmq.WalletOutboxMessage{
				AppCode:       "lalu",
				EventID:       first.EventID,
				EventType:     first.EventType,
				TransactionID: first.TransactionID,
				CommandID:     first.CommandID,
				UserID:        first.UserID,
				AssetType:     first.AssetType,
				PayloadJSON:   `{"source":"test"}`,
				OccurredAtMS:  first.CreatedAtMS,
			}); err != nil {
				t.Fatalf("resource event is still rejected by wallet MQ encoder: %v", err)
			}
		})
	}
}

func TestResourceOutboxHistoricalRetryIsOptInAndNarrowlyScoped(t *testing.T) {
	_, file, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("resolve test source path")
	}
	path := filepath.Join(filepath.Dir(file), "../../../deploy/mysql/maintenance/20260711_retry_incomplete_resource_outbox.sql")
	body, err := os.ReadFile(path)
	if err != nil {
		t.Fatalf("read resource outbox maintenance SQL: %v", err)
	}
	sql := string(body)
	for _, required := range []string{
		"COALESCE(@execute_wallet_resource_outbox_retry, 0)",
		"WHERE @execute_wallet_resource_outbox_retry = 1",
		"AND wo.asset_type = 'RESOURCE'",
		"AND wo.transaction_id = ''",
		"AND BINARY wo.last_error = BINARY 'wallet outbox message is incomplete'",
		"AND wo.status IN ('failed', 'retryable')",
		"LIMIT 100",
		"SET wo.transaction_id = wo.event_id",
		"wo.status = 'pending'",
	} {
		if !strings.Contains(sql, required) {
			t.Fatalf("maintenance SQL misses safety contract %q", required)
		}
	}
	for _, eventType := range []string{
		"GiftConfigChanged",
		"ResourceChanged",
		"ResourceGrantRevoked",
		"ResourceGranted",
		"ResourceGroupChanged",
		"ResourceGroupGranted",
		"UserResourceChanged",
		"VipEffectiveChanged",
		"VipTrialCardGranted",
	} {
		if !strings.Contains(sql, "'"+eventType+"'") {
			t.Fatalf("maintenance SQL misses resource event type %q", eventType)
		}
	}
}
