package activityapi

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	activityv1 "hyapp.local/api/proto/activity/v1"
	userv1 "hyapp.local/api/proto/user/v1"
	"hyapp/pkg/appcode"
)

func TestListInviteActivityLeaderboardEnrichesUsers(t *testing.T) {
	inviteClient := &fakeInviteActivityRewardClient{
		leaderboardResp: &activityv1.ListInviteActivityLeaderboardResponse{
			Entries: []*activityv1.InviteActivityLeaderboardEntry{{
				RankNo:                  1,
				UserId:                  1001,
				ValidInviteCount:        12,
				TotalRechargeCoinAmount: 880000,
			}},
			Total:        1,
			CycleKey:     "2026-06",
			ServerTimeMs: 1781179200000,
		},
	}
	userClient := &fakeInviteActivityUserProfileClient{
		users: map[int64]*userv1.User{
			1001: {
				UserId:        1001,
				DisplayUserId: "L1001",
				Username:      "hanneem",
				Avatar:        "https://cdn.example/avatar.png",
			},
		},
	}
	handler := New(Config{InviteActivityReward: inviteClient, UserProfileClient: userClient})
	request := httptest.NewRequest(http.MethodGet, "/api/v1/activities/invite-reward/leaderboard?page=1&page_size=20", nil)
	request = request.WithContext(appcode.WithContext(request.Context(), "lalu"))
	recorder := httptest.NewRecorder()

	handler.listInviteActivityLeaderboard(recorder, request)

	if recorder.Code != http.StatusOK {
		t.Fatalf("status mismatch: %d body=%s", recorder.Code, recorder.Body.String())
	}
	if inviteClient.lastLeaderboard == nil || inviteClient.lastLeaderboard.GetPage() != 1 || inviteClient.lastLeaderboard.GetPageSize() != 20 {
		t.Fatalf("leaderboard request mismatch: %+v", inviteClient.lastLeaderboard)
	}
	if len(userClient.lastBatch.GetUserIds()) != 1 || userClient.lastBatch.GetUserIds()[0] != 1001 {
		t.Fatalf("batch users request mismatch: %+v", userClient.lastBatch)
	}
	var envelope struct {
		Code string `json:"code"`
		Data struct {
			Entries []struct {
				RankNo           int32  `json:"rank_no"`
				UserID           string `json:"user_id"`
				ValidInviteCount int64  `json:"valid_invite_count"`
				User             struct {
					Username string `json:"username"`
					Avatar   string `json:"avatar"`
				} `json:"user"`
			} `json:"entries"`
			Total    int64  `json:"total"`
			CycleKey string `json:"cycle_key"`
		} `json:"data"`
	}
	if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
		t.Fatalf("decode response: %v", err)
	}
	if envelope.Code != "OK" || envelope.Data.Total != 1 || envelope.Data.CycleKey != "2026-06" {
		t.Fatalf("response header mismatch: %+v", envelope)
	}
	if len(envelope.Data.Entries) != 1 || envelope.Data.Entries[0].RankNo != 1 || envelope.Data.Entries[0].UserID != "1001" || envelope.Data.Entries[0].ValidInviteCount != 12 {
		t.Fatalf("entry mismatch: %+v", envelope.Data.Entries)
	}
	if envelope.Data.Entries[0].User.Username != "hanneem" || envelope.Data.Entries[0].User.Avatar != "https://cdn.example/avatar.png" {
		t.Fatalf("user enrichment mismatch: %+v", envelope.Data.Entries[0].User)
	}
}

type fakeInviteActivityRewardClient struct {
	leaderboardResp *activityv1.ListInviteActivityLeaderboardResponse
	lastLeaderboard *activityv1.ListInviteActivityLeaderboardRequest
}

func (f *fakeInviteActivityRewardClient) GetInviteActivityRewardStatus(context.Context, *activityv1.GetInviteActivityRewardStatusRequest) (*activityv1.GetInviteActivityRewardStatusResponse, error) {
	return &activityv1.GetInviteActivityRewardStatusResponse{}, nil
}

func (f *fakeInviteActivityRewardClient) ClaimInviteActivityReward(context.Context, *activityv1.ClaimInviteActivityRewardRequest) (*activityv1.ClaimInviteActivityRewardResponse, error) {
	return &activityv1.ClaimInviteActivityRewardResponse{}, nil
}

func (f *fakeInviteActivityRewardClient) ListInviteActivityLeaderboard(_ context.Context, req *activityv1.ListInviteActivityLeaderboardRequest) (*activityv1.ListInviteActivityLeaderboardResponse, error) {
	f.lastLeaderboard = req
	if f.leaderboardResp != nil {
		return f.leaderboardResp, nil
	}
	return &activityv1.ListInviteActivityLeaderboardResponse{}, nil
}

type fakeInviteActivityUserProfileClient struct {
	users     map[int64]*userv1.User
	user      *userv1.User
	lastBatch *userv1.BatchGetUsersRequest
	getCalls  int
}

func (f *fakeInviteActivityUserProfileClient) BatchGetUsers(_ context.Context, req *userv1.BatchGetUsersRequest) (*userv1.BatchGetUsersResponse, error) {
	f.lastBatch = req
	return &userv1.BatchGetUsersResponse{Users: f.users}, nil
}

func (f *fakeInviteActivityUserProfileClient) BatchGetRoomBasicUsers(context.Context, *userv1.BatchGetRoomBasicUsersRequest) (*userv1.BatchGetRoomBasicUsersResponse, error) {
	return &userv1.BatchGetRoomBasicUsersResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) GetUser(context.Context, *userv1.GetUserRequest) (*userv1.GetUserResponse, error) {
	f.getCalls++
	return &userv1.GetUserResponse{User: f.user}, nil
}

func (f *fakeInviteActivityUserProfileClient) BusinessUserLookup(context.Context, *userv1.BusinessUserLookupRequest) (*userv1.BusinessUserLookupResponse, error) {
	return &userv1.BusinessUserLookupResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) GetMyProfileStats(context.Context, *userv1.GetMyProfileStatsRequest) (*userv1.GetMyProfileStatsResponse, error) {
	return &userv1.GetMyProfileStatsResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) CompleteOnboarding(context.Context, *userv1.CompleteOnboardingRequest) (*userv1.CompleteOnboardingResponse, error) {
	return &userv1.CompleteOnboardingResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) UpdateUserProfile(context.Context, *userv1.UpdateUserProfileRequest) (*userv1.UpdateUserProfileResponse, error) {
	return &userv1.UpdateUserProfileResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) UpdateUserProfileBackground(context.Context, *userv1.UpdateUserProfileBackgroundRequest) (*userv1.UpdateUserProfileBackgroundResponse, error) {
	return &userv1.UpdateUserProfileBackgroundResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) UpdateUserContactInfo(context.Context, *userv1.UpdateUserContactInfoRequest) (*userv1.UpdateUserContactInfoResponse, error) {
	return &userv1.UpdateUserContactInfoResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) UpdateUserWithdrawAddress(context.Context, *userv1.UpdateUserWithdrawAddressRequest) (*userv1.UpdateUserWithdrawAddressResponse, error) {
	return &userv1.UpdateUserWithdrawAddressResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) ChangeUserCountry(context.Context, *userv1.ChangeUserCountryRequest) (*userv1.ChangeUserCountryResponse, error) {
	return &userv1.ChangeUserCountryResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) AdminChangeUserCountry(context.Context, *userv1.AdminChangeUserCountryRequest) (*userv1.ChangeUserCountryResponse, error) {
	return &userv1.ChangeUserCountryResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) CreateManagerUserBlock(context.Context, *userv1.CreateManagerUserBlockRequest) (*userv1.CreateManagerUserBlockResponse, error) {
	return &userv1.CreateManagerUserBlockResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) ListManagerUserBlocks(context.Context, *userv1.ListManagerUserBlocksRequest) (*userv1.ListManagerUserBlocksResponse, error) {
	return &userv1.ListManagerUserBlocksResponse{}, nil
}

func (f *fakeInviteActivityUserProfileClient) UnblockManagerUser(context.Context, *userv1.UnblockManagerUserRequest) (*userv1.UnblockManagerUserResponse, error) {
	return &userv1.UnblockManagerUserResponse{}, nil
}
