package roomrps

import (
	"context"
	"testing"
	"time"

	gamev1 "hyapp.local/api/proto/game/v1"
	walletv1 "hyapp.local/api/proto/wallet/v1"
)

func TestUpdateConfigEnrichesStakeGiftsFromWalletCatalog(t *testing.T) {
	catalog := newFakeGiftCatalog(map[string]*walletv1.GiftConfig{
		"2001": roomRPSWalletGift("2001", "Rose", "https://cdn.example.test/rose.png", "", "", 100),
		"2002": roomRPSWalletGift("2002", "Bell", "", "https://cdn.example.test/bell-preview.png", "", 300),
		"2003": roomRPSWalletGift("2003", "Crown", "", "", "https://cdn.example.test/crown.svga", 500),
		"2004": roomRPSWalletGift("2004", "Cup", "https://cdn.example.test/cup.png", "", "", 1000),
	})
	svc := New(Config{}, nil, nil, catalog)
	svc.now = func() time.Time { return time.UnixMilli(1770000000000) }

	config, _, err := svc.UpdateConfig(context.Background(), "lalu", &gamev1.RoomRPSConfig{
		Status:             "active",
		ChallengeTimeoutMs: 600000,
		RevealCountdownMs:  3000,
		StakeGifts: []*gamev1.RoomRPSStakeGift{
			{GiftIdText: "2001", Enabled: true, SortOrder: 1},
			{GiftIdText: "2002", Enabled: true, SortOrder: 2},
			{GiftIdText: "2003", Enabled: true, SortOrder: 3},
			{GiftIdText: "2004", Enabled: true, SortOrder: 4},
		},
	})
	if err != nil {
		t.Fatalf("UpdateConfig() error = %v", err)
	}

	if got := config.GetStakeGifts()[0]; got.GetGiftName() != "Rose" || got.GetGiftIconUrl() != "https://cdn.example.test/rose.png" || got.GetGiftPriceCoin() != 100 {
		t.Fatalf("first gift was not enriched from wallet catalog: %+v", got)
	}
	if got := config.GetStakeGifts()[1]; got.GetGiftIconUrl() != "https://cdn.example.test/bell-preview.png" {
		t.Fatalf("second gift should use preview_url when asset_url is empty: %+v", got)
	}
	if got := config.GetStakeGifts()[2]; got.GetGiftIconUrl() != "https://cdn.example.test/crown.svga" {
		t.Fatalf("third gift should use animation_url as last display fallback: %+v", got)
	}
	if len(catalog.requests) != 4 {
		t.Fatalf("expected one exact catalog lookup per missing gift, got %d", len(catalog.requests))
	}
	if req := catalog.requests[0]; req.GetAppCode() != "lalu" || req.GetKeyword() != "2001" || req.GetPage() != 1 || req.GetPageSize() != 100 {
		t.Fatalf("catalog lookup request mismatch: %+v", req)
	}
	if got := config.GetStakeGifts()[0]; got.GetGiftIdText() != "2001" || got.GetGiftId() != 2001 {
		t.Fatalf("numeric gift should keep string primary ID and legacy number: %+v", got)
	}
}

func TestGetConfigBackfillsLegacyEmptyGiftSnapshot(t *testing.T) {
	catalog := newFakeGiftCatalog(map[string]*walletv1.GiftConfig{
		"Gifi-3": roomRPSWalletGift("Gifi-3", "Rocket", "https://cdn.example.test/rocket.png", "", "", 900),
	})
	svc := New(Config{}, nil, nil, catalog)
	svc.now = func() time.Time { return time.UnixMilli(1770000000000) }
	svc.configs["lalu"] = &gamev1.RoomRPSConfig{
		AppCode:            "lalu",
		GameId:             GameID,
		Status:             "active",
		ChallengeTimeoutMs: 600000,
		RevealCountdownMs:  3000,
		StakeGifts: []*gamev1.RoomRPSStakeGift{
			{GiftIdText: "Gifi-3", Enabled: true, SortOrder: 1},
			{GiftId: 10002, Enabled: true, SortOrder: 2},
			{GiftId: 10003, Enabled: true, SortOrder: 3},
			{GiftId: 10004, Enabled: true, SortOrder: 4},
		},
		CreatedAtMs: 1000,
		UpdatedAtMs: 2000,
	}

	config, _, err := svc.GetConfig(context.Background(), "lalu")
	if err != nil {
		t.Fatalf("GetConfig() error = %v", err)
	}

	if got := config.GetStakeGifts()[0]; got.GetGiftName() != "Rocket" || got.GetGiftIconUrl() != "https://cdn.example.test/rocket.png" || got.GetGiftPriceCoin() != 900 {
		t.Fatalf("legacy config response was not enriched: %+v", got)
	}
	if cached := svc.configs["lalu"].GetStakeGifts()[0]; cached.GetGiftIconUrl() == "" {
		t.Fatalf("legacy config was not backfilled into service cache: %+v", cached)
	}
}

func TestCreateChallengeMatchesStringGiftID(t *testing.T) {
	catalog := newFakeGiftCatalog(map[string]*walletv1.GiftConfig{
		"Gifi-3": roomRPSWalletGift("Gifi-3", "Tiger", "https://cdn.example.test/tiger.png", "", "", 1),
		"Gifi-2": roomRPSWalletGift("Gifi-2", "Cowboy", "https://cdn.example.test/cowboy.png", "", "", 1),
		"Gifi-1": roomRPSWalletGift("Gifi-1", "Warrior", "https://cdn.example.test/warrior.png", "", "", 1),
		"lw1":    roomRPSWalletGift("lw1", "Lucky Wheel", "https://cdn.example.test/lw1.png", "", "", 111),
	})
	svc := New(Config{}, nil, nil, catalog)
	svc.now = func() time.Time { return time.UnixMilli(1770000000000) }

	_, _, err := svc.UpdateConfig(context.Background(), "lalu", &gamev1.RoomRPSConfig{
		Status:             "active",
		ChallengeTimeoutMs: 600000,
		RevealCountdownMs:  3000,
		StakeGifts: []*gamev1.RoomRPSStakeGift{
			{GiftIdText: "Gifi-3", Enabled: true, SortOrder: 1},
			{GiftIdText: "Gifi-2", Enabled: true, SortOrder: 2},
			{GiftIdText: "Gifi-1", Enabled: true, SortOrder: 3},
			{GiftIdText: "lw1", Enabled: true, SortOrder: 4},
		},
	})
	if err != nil {
		t.Fatalf("UpdateConfig() error = %v", err)
	}

	challenge, _, err := svc.CreateChallenge(context.Background(), &gamev1.CreateRoomRPSChallengeRequest{
		Meta:       &gamev1.RequestMeta{AppCode: "lalu"},
		UserId:     42,
		RoomId:     "room-1",
		RegionId:   1001,
		GiftIdText: "Gifi-3",
		Gesture:    "rock",
	})
	if err != nil {
		t.Fatalf("CreateChallenge() error = %v", err)
	}
	if challenge.GetStakeGiftIdText() != "Gifi-3" || challenge.GetStakeGiftId() != 0 || challenge.GetStakeCoin() != 1 {
		t.Fatalf("string gift challenge mismatch: %+v", challenge)
	}
}

type fakeGiftCatalog struct {
	gifts    map[string]*walletv1.GiftConfig
	requests []*walletv1.ListGiftConfigsRequest
}

func newFakeGiftCatalog(gifts map[string]*walletv1.GiftConfig) *fakeGiftCatalog {
	return &fakeGiftCatalog{gifts: gifts}
}

func (f *fakeGiftCatalog) ListGiftConfigs(_ context.Context, req *walletv1.ListGiftConfigsRequest) (*walletv1.ListGiftConfigsResponse, error) {
	f.requests = append(f.requests, req)
	if gift := f.gifts[req.GetKeyword()]; gift != nil {
		return &walletv1.ListGiftConfigsResponse{Gifts: []*walletv1.GiftConfig{gift}, Total: 1}, nil
	}
	return &walletv1.ListGiftConfigsResponse{Gifts: []*walletv1.GiftConfig{}, Total: 0}, nil
}

func roomRPSWalletGift(giftID string, name string, assetURL string, previewURL string, animationURL string, coinPrice int64) *walletv1.GiftConfig {
	return &walletv1.GiftConfig{
		AppCode:   "lalu",
		GiftId:    giftID,
		Name:      name,
		Status:    "active",
		CoinPrice: coinPrice,
		Resource: &walletv1.Resource{
			ResourceId:   100,
			ResourceType: "gift",
			Name:         name,
			Status:       "active",
			AssetUrl:     assetURL,
			PreviewUrl:   previewURL,
			AnimationUrl: animationURL,
		},
	}
}
