package app

import (
	"testing"
	"time"

	"hyapp/pkg/walletmq"
	"hyapp/services/wallet-service/internal/config"
	mysqlstorage "hyapp/services/wallet-service/internal/storage/mysql"
)

func TestWalletOutboxSingleRecordLeaseCoversPublishAndStateWrite(t *testing.T) {
	if got := walletOutboxSingleRecordLease(3 * time.Second); got != 9*time.Second {
		t.Fatalf("single-record lease = %s, want 9s", got)
	}
	if got := walletOutboxSingleRecordLease(0); got != 9*time.Second {
		t.Fatalf("default single-record lease = %s, want 9s", got)
	}
}

func TestWalletOutboxRocketMessageUsesConfiguredTagMode(t *testing.T) {
	tests := []struct {
		name    string
		mode    config.WalletEventTagMode
		wantTag string
	}{
		{
			name:    "missing config remains legacy",
			mode:    "",
			wantTag: walletmq.TagWalletOutboxEvent,
		},
		{
			name:    "phase a publishes legacy",
			mode:    config.WalletEventTagModeLegacy,
			wantTag: walletmq.TagWalletOutboxEvent,
		},
		{
			name:    "phase b publishes event type",
			mode:    config.WalletEventTagModeEventType,
			wantTag: walletmq.EventTypeWalletGiftDebited,
		},
	}
	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			message, err := walletOutboxRocketMessage("hyapp_wallet_outbox", test.mode, validWalletOutboxRecord())
			if err != nil {
				t.Fatalf("walletOutboxRocketMessage failed: %v", err)
			}
			if message.Tag != test.wantTag {
				t.Fatalf("message tag = %q, want %q", message.Tag, test.wantTag)
			}
			decoded, err := walletmq.DecodeWalletOutboxMessage(message.Body)
			if err != nil {
				t.Fatalf("DecodeWalletOutboxMessage failed: %v", err)
			}
			if decoded.EventType != walletmq.EventTypeWalletGiftDebited {
				t.Fatalf("body event_type = %q", decoded.EventType)
			}
			if message.Topic != "hyapp_wallet_outbox" || len(message.Keys) != 3 {
				t.Fatalf("message routing metadata mismatch: %+v", message)
			}
		})
	}
}

func TestWalletOutboxRocketMessageRejectsUnsupportedTagMode(t *testing.T) {
	_, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagMode("all"), validWalletOutboxRecord())
	if err == nil {
		t.Fatal("walletOutboxRocketMessage unexpectedly accepted an unsupported tag mode")
	}
}

func TestWalletOutboxRocketMessageRejectsUnsafeEventTypeTag(t *testing.T) {
	record := validWalletOutboxRecord()
	record.EventType = "WalletGiftDebited || *"
	_, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeLegacy, record)
	if err == nil {
		t.Fatal("walletOutboxRocketMessage unexpectedly accepted an unsafe event_type")
	}
}

func TestWalletOutboxRocketMessageRestoresHistoricalResourceCorrelationID(t *testing.T) {
	for _, eventType := range []string{
		"GiftConfigChanged",
		"ResourceChanged",
		"ResourceGrantRevoked",
		"ResourceGranted",
		"ResourceGroupChanged",
		"ResourceGroupGranted",
		"UserResourceChanged",
		"VipEffectiveChanged",
		"VipTrialCardGranted",
	} {
		t.Run(eventType, func(t *testing.T) {
			record := validWalletOutboxRecord()
			record.EventID = "wev-historical-resource"
			record.EventType = eventType
			record.TransactionID = ""
			record.AssetType = "RESOURCE"

			message, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeEventType, record)
			if err != nil {
				t.Fatalf("historical resource fact was rejected: %v", err)
			}
			decoded, err := walletmq.DecodeWalletOutboxMessage(message.Body)
			if err != nil {
				t.Fatalf("DecodeWalletOutboxMessage failed: %v", err)
			}
			if decoded.TransactionID != record.EventID || message.Keys[1] != record.EventID {
				t.Fatalf("correlation id mismatch: decoded=%q keys=%v", decoded.TransactionID, message.Keys)
			}
		})
	}
}

func TestWalletOutboxRocketMessageDoesNotInventFinancialTransactionID(t *testing.T) {
	record := validWalletOutboxRecord()
	record.TransactionID = ""
	if _, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeEventType, record); err == nil {
		t.Fatal("financial fact without transaction_id must remain invalid")
	}
	record.EventType = "UnknownResourceEvent"
	record.AssetType = "RESOURCE"
	if _, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeEventType, record); err == nil {
		t.Fatal("unknown resource fact must not receive a synthetic transaction_id")
	}
}

func validWalletOutboxRecord() mysqlstorage.WalletOutboxRecord {
	return mysqlstorage.WalletOutboxRecord{
		AppCode:        "lalu",
		EventID:        "event-1",
		EventType:      "  " + walletmq.EventTypeWalletGiftDebited + "  ",
		TransactionID:  "transaction-1",
		CommandID:      "command-1",
		UserID:         1001,
		AssetType:      "COIN",
		AvailableDelta: -100,
		PayloadJSON:    `{"gift_id":"gift-1"}`,
		CreatedAtMS:    1_700_000_000_000,
	}
}
