package app

import (
	"encoding/json"
	"testing"

	"hyapp/pkg/walletmq"
)

func TestUserLeaderboardGiftEventFromWalletMessage(t *testing.T) {
	body := mustWalletOutboxMessage(t, "WalletGiftDebited", map[string]any{
		"sender_user_id": 10001,
		"target_user_id": 20002,
		"heat_value":     900,
		"coin_spent":     1200,
		"charge_amount":  1200,
		"gift_count":     3,
	})

	event, ok, err := userLeaderboardGiftEventFromWalletMessage(body)
	if err != nil || !ok {
		t.Fatalf("gift event should parse: ok=%v err=%v", ok, err)
	}
	if event.AppCode != "hyapp_room" || event.EventID != "evt-1" || event.SenderUserID != 10001 || event.TargetUserID != 20002 {
		t.Fatalf("event identity mismatch: %+v", event)
	}
	if event.GiftValue != 900 || event.GiftCount != 3 || event.OccurredAtMS != 1782461920000 {
		t.Fatalf("event aggregate fields mismatch: %+v", event)
	}
}

func TestUserLeaderboardGiftEventSkipsDirectGift(t *testing.T) {
	body := mustWalletOutboxMessage(t, "WalletGiftDebited", map[string]any{
		"sender_user_id": 10001,
		"target_user_id": 20002,
		"heat_value":     900,
		"gift_count":     1,
		"direct_gift":    true,
	})

	_, ok, err := userLeaderboardGiftEventFromWalletMessage(body)
	if err != nil {
		t.Fatalf("direct gift parse failed: %v", err)
	}
	if ok {
		t.Fatal("direct gift must keep the old gift_debit SQL scope and skip user leaderboard")
	}
}

func TestUserLeaderboardGiftEventKeepsSQLCoalesceSemantics(t *testing.T) {
	fallbackBody := mustWalletOutboxMessage(t, "WalletGiftDebited", map[string]any{
		"sender_user_id": 10001,
		"target_user_id": 20002,
		"coin_spent":     1200,
		"charge_amount":  1500,
		"gift_count":     1,
	})
	fallback, ok, err := userLeaderboardGiftEventFromWalletMessage(fallbackBody)
	if err != nil || !ok {
		t.Fatalf("fallback gift event should parse: ok=%v err=%v", ok, err)
	}
	if fallback.GiftValue != 1200 {
		t.Fatalf("missing heat_value should fall back to coin_spent, got %+v", fallback)
	}

	zeroHeatBody := mustWalletOutboxMessage(t, "WalletGiftDebited", map[string]any{
		"sender_user_id": 10001,
		"target_user_id": 20002,
		"heat_value":     0,
		"coin_spent":     1200,
		"charge_amount":  1500,
		"gift_count":     1,
	})
	_, ok, err = userLeaderboardGiftEventFromWalletMessage(zeroHeatBody)
	if err != nil {
		t.Fatalf("zero heat gift event parse failed: %v", err)
	}
	if ok {
		t.Fatal("heat_value=0 should not fall back to coin_spent because old SQL COALESCE treats zero as present")
	}
}

func mustWalletOutboxMessage(t *testing.T, eventType string, payload map[string]any) []byte {
	t.Helper()
	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		t.Fatalf("marshal payload failed: %v", err)
	}
	body, err := walletmq.EncodeWalletOutboxMessage(walletmq.WalletOutboxMessage{
		AppCode:        "hyapp_room",
		EventID:        "evt-1",
		EventType:      eventType,
		TransactionID:  "tx-1",
		CommandID:      "cmd-1",
		UserID:         10001,
		AssetType:      "COIN",
		AvailableDelta: -1200,
		PayloadJSON:    string(payloadBytes),
		OccurredAtMS:   1782461920000,
	})
	if err != nil {
		t.Fatalf("encode wallet outbox failed: %v", err)
	}
	return body
}
