package giftrecord

import (
	"context"
	"regexp"
	"testing"

	"github.com/DATA-DOG/go-sqlmock"
	"hyapp-admin-server/internal/modules/shared"
)

func TestListUsesWalletGiftSnapshotAndEnrichesBothUsers(t *testing.T) {
	walletDB, walletMock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("new wallet sqlmock: %v", err)
	}
	defer walletDB.Close()
	userDB, userMock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("new user sqlmock: %v", err)
	}
	defer userDB.Close()

	walletMock.ExpectQuery(regexp.QuoteMeta("SELECT COUNT(*) FROM wallet_transactions WHERE app_code = ? AND status = ? AND biz_type IN (?, ?)")).
		WithArgs("fami", walletStatusSucceeded, bizTypeGiftDebit, bizTypeDirectGiftDebit).
		WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
	walletMock.ExpectQuery("SELECT transaction_id, biz_type, COALESCE\\(CAST\\(metadata_json AS CHAR\\), '\\{\\}'\\), created_at_ms").
		WithArgs("fami", walletStatusSucceeded, bizTypeGiftDebit, bizTypeDirectGiftDebit, 30, 0).
		WillReturnRows(sqlmock.NewRows([]string{"transaction_id", "biz_type", "metadata_json", "created_at_ms"}).AddRow(
			"wallet-gift-1",
			bizTypeGiftDebit,
			`{"gift_id":"rose","gift_name":"玫瑰","gift_icon_url":"https://cdn.example/rose.webp","gift_count":3,"coin_price":100,"coin_spent":300,"sender_user_id":1001,"target_user_id":2002,"room_id":"room-9"}`,
			int64(1770000000000),
		))
	userMock.ExpectQuery("SELECT users.user_id,").
		WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), "fami", int64(1001), int64(2002)).
		WillReturnRows(sqlmock.NewRows([]string{"user_id", "current_display_user_id", "default_display_user_id", "pretty_display_user_id", "pretty_id", "username", "avatar"}).
			AddRow(int64(1001), "101", "101", "888888", "pretty-1", "送礼人", "sender.webp").
			AddRow(int64(2002), "202", "202", "", "", "收礼人", "receiver.webp"))

	items, total, err := NewService(userDB, walletDB).List(context.Background(), "fami", listQuery{Page: 1, PageSize: 30})
	if err != nil {
		t.Fatalf("list gift records: %v", err)
	}
	if total != 1 || len(items) != 1 {
		t.Fatalf("unexpected page total=%d items=%d", total, len(items))
	}
	item := items[0]
	if item.Scene != sceneRoom || item.RoomID != "room-9" {
		t.Fatalf("scene snapshot mismatch: %+v", item)
	}
	if item.Sender.Username != "送礼人" || item.Sender.PrettyDisplayUserID != "888888" || item.Receiver.Username != "收礼人" {
		t.Fatalf("user enrichment mismatch: %+v", item)
	}
	if item.Gift.Name != "玫瑰" || item.Gift.CoverURL == "" || item.GiftCount != 3 || item.UnitValue != 100 || item.GiftValue != 300 {
		t.Fatalf("gift snapshot mismatch: %+v", item)
	}
	if err := walletMock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
	if err := userMock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}

func TestRecordFromMetadataFallsBackToTotalValueForHistoricalUnitPrice(t *testing.T) {
	item := recordFromMetadata(recordDTO{}, bizTypeDirectGiftDebit, giftMetadata{
		GiftID:       "legacy-gift",
		GiftCount:    2,
		ChargeAmount: 240,
		SenderUserID: 1,
		TargetUserID: 2,
		DirectGift:   true,
	})
	if item.Scene != sceneDirect || item.Gift.Name != "legacy-gift" || item.UnitValue != 120 || item.GiftValue != 240 {
		t.Fatalf("historical fallback mismatch: %+v", item)
	}
}

func TestListResolvesCommonSenderIdentityFilterBeforeIndexedWalletPage(t *testing.T) {
	walletDB, walletMock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("new wallet sqlmock: %v", err)
	}
	defer walletDB.Close()
	userDB, userMock, err := sqlmock.New()
	if err != nil {
		t.Fatalf("new user sqlmock: %v", err)
	}
	defer userDB.Close()

	// 短 ID 先在 user owner 库解析为内部 user_id；钱包查询只使用生成列组合索引，不在 metadata JSON 上做运行时扫描。
	userMock.ExpectQuery("SELECT u.user_id").
		WithArgs("fami", "888888", "888888", sqlmock.AnyArg(), "888888").
		WillReturnRows(sqlmock.NewRows([]string{"user_id"}).AddRow(int64(1001)))
	walletMock.ExpectQuery(regexp.QuoteMeta("SELECT COUNT(*) FROM wallet_transactions WHERE app_code = ? AND status = ? AND biz_type IN (?, ?) AND gift_sender_user_id IN (?)")).
		WithArgs("fami", walletStatusSucceeded, bizTypeGiftDebit, bizTypeDirectGiftDebit, int64(1001)).
		WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0))
	walletMock.ExpectQuery("SELECT transaction_id, biz_type, COALESCE\\(CAST\\(metadata_json AS CHAR\\), '\\{\\}'\\), created_at_ms").
		WithArgs("fami", walletStatusSucceeded, bizTypeGiftDebit, bizTypeDirectGiftDebit, int64(1001), 30, 0).
		WillReturnRows(sqlmock.NewRows([]string{"transaction_id", "biz_type", "metadata_json", "created_at_ms"}))

	items, total, err := NewService(userDB, walletDB).List(context.Background(), "fami", listQuery{
		Page:     1,
		PageSize: 30,
		SenderFilter: shared.UserIdentityFilter{
			DisplayUserID: "888888",
		},
	})
	if err != nil {
		t.Fatalf("list gift records by sender: %v", err)
	}
	if total != 0 || len(items) != 0 {
		t.Fatalf("unexpected filtered page total=%d items=%d", total, len(items))
	}
	if err := walletMock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
	if err := userMock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}
