package cp

import (
	"context"
	"testing"

	"hyapp/pkg/appcode"
	cpdomain "hyapp/services/user-service/internal/domain/cp"
)

func TestRefreshIntimacyLeaderboardHydratesAvatarFrames(t *testing.T) {
	repo := &fakeLeaderboardRepo{
		entries: []cpdomain.IntimacyLeaderboardEntry{{
			RelationshipID: "rank_cp_1",
			RelationType:   cpdomain.RelationTypeCP,
			IntimacyValue:  300,
			Level:          2,
			UserA:          cpdomain.IntimacyLeaderboardUser{UserID: 7101, DisplayUserID: "7101", Username: "A", Avatar: "a.png"},
			UserB:          cpdomain.IntimacyLeaderboardUser{UserID: 7102, DisplayUserID: "7102", Username: "B", Avatar: "b.png"},
		}},
	}
	store := &fakeLeaderboardStore{}
	frames := &fakeAvatarFrameReader{frames: map[int64]cpdomain.AvatarFrameSnapshot{
		7101: {ResourceID: 9101, ResourceCode: "frame_gold", Name: "Gold", AssetURL: "gold.png"},
		7102: {ResourceID: 9102, ResourceCode: "frame_blue", Name: "Blue", AssetURL: "blue.png"},
	}}
	svc := New(repo, WithIntimacyLeaderboardStore(store), WithAvatarFrameReader(frames))

	processed, err := svc.RefreshIntimacyLeaderboard(appcode.WithContext(context.Background(), appcode.Default), 100)
	if err != nil {
		t.Fatalf("refresh leaderboard failed: %v", err)
	}
	if processed != 1 || len(store.entries) != 1 {
		t.Fatalf("processed/store mismatch: processed=%d entries=%+v", processed, store.entries)
	}
	entry := store.entries[0]
	if entry.UserA.AvatarFrame == nil || entry.UserA.AvatarFrame.ResourceID != 9101 ||
		entry.UserB.AvatarFrame == nil || entry.UserB.AvatarFrame.ResourceCode != "frame_blue" {
		t.Fatalf("avatar frames must be hydrated before zset replace: %+v", entry)
	}
	if len(frames.userIDs) != 2 || frames.userIDs[0] != 7101 || frames.userIDs[1] != 7102 {
		t.Fatalf("avatar frame reader should receive both users once: %+v", frames.userIDs)
	}
}

type fakeLeaderboardRepo struct {
	entries []cpdomain.IntimacyLeaderboardEntry
}

func (r *fakeLeaderboardRepo) ListApplications(context.Context, int64, string, string, int32, int32, int64) ([]cpdomain.Application, int64, error) {
	return nil, 0, nil
}

func (r *fakeLeaderboardRepo) AcceptApplication(context.Context, int64, string, int64) (cpdomain.Application, cpdomain.Relationship, error) {
	return cpdomain.Application{}, cpdomain.Relationship{}, nil
}

func (r *fakeLeaderboardRepo) RejectApplication(context.Context, int64, string, string, int64) (cpdomain.Application, error) {
	return cpdomain.Application{}, nil
}

func (r *fakeLeaderboardRepo) ListRelationships(context.Context, int64, string, int32, int32) ([]cpdomain.Relationship, int64, error) {
	return nil, 0, nil
}

func (r *fakeLeaderboardRepo) PrepareBreakRelationship(context.Context, int64, string, string, int64) (cpdomain.RelationshipBreakup, cpdomain.Relationship, error) {
	return cpdomain.RelationshipBreakup{}, cpdomain.Relationship{}, nil
}

func (r *fakeLeaderboardRepo) ConfirmBreakRelationship(context.Context, int64, string, string, string, int64, int64, int64) (cpdomain.RelationshipBreakup, cpdomain.Relationship, error) {
	return cpdomain.RelationshipBreakup{}, cpdomain.Relationship{}, nil
}

func (r *fakeLeaderboardRepo) CancelBreakRelationship(context.Context, int64, string, string, string, int64) (cpdomain.RelationshipBreakup, error) {
	return cpdomain.RelationshipBreakup{}, nil
}

func (r *fakeLeaderboardRepo) ConsumeGiftEvent(context.Context, cpdomain.GiftEvent, int64) (cpdomain.ConsumeResult, error) {
	return cpdomain.ConsumeResult{}, nil
}

func (r *fakeLeaderboardRepo) ListActiveIntimacyLeaderboardEntries(context.Context, int) ([]cpdomain.IntimacyLeaderboardEntry, error) {
	return r.entries, nil
}

func (r *fakeLeaderboardRepo) ListWeeklyRankEntries(context.Context, string, int64, int64, int) ([]cpdomain.WeeklyRankEntry, error) {
	return nil, nil
}

type fakeLeaderboardStore struct {
	entries []cpdomain.IntimacyLeaderboardEntry
}

func (s *fakeLeaderboardStore) ReplaceIntimacyLeaderboard(_ context.Context, _ string, entries []cpdomain.IntimacyLeaderboardEntry) error {
	s.entries = append([]cpdomain.IntimacyLeaderboardEntry(nil), entries...)
	return nil
}

func (s *fakeLeaderboardStore) ListIntimacyLeaderboard(_ context.Context, _ string, _ string, page int32, pageSize int32, nowMs int64) (cpdomain.IntimacyLeaderboardPage, error) {
	return cpdomain.IntimacyLeaderboardPage{Items: s.entries, Total: int64(len(s.entries)), Page: page, PageSize: pageSize, ServerTimeMS: nowMs}, nil
}

type fakeAvatarFrameReader struct {
	frames  map[int64]cpdomain.AvatarFrameSnapshot
	userIDs []int64
}

func (r *fakeAvatarFrameReader) BatchGetAvatarFrames(_ context.Context, _ string, userIDs []int64) (map[int64]cpdomain.AvatarFrameSnapshot, error) {
	r.userIDs = append([]int64(nil), userIDs...)
	return r.frames, nil
}
