package userapi

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

	userv1 "hyapp.local/api/proto/user/v1"
	"hyapp/services/gateway-service/internal/auth"
)

type fakeCPRelationshipListClient struct {
	lastList *userv1.ListCPRelationshipsRequest
}

func (f *fakeCPRelationshipListClient) ListCPApplications(context.Context, *userv1.ListCPApplicationsRequest) (*userv1.ListCPApplicationsResponse, error) {
	return &userv1.ListCPApplicationsResponse{}, nil
}

func (f *fakeCPRelationshipListClient) AcceptCPApplication(context.Context, *userv1.AcceptCPApplicationRequest) (*userv1.AcceptCPApplicationResponse, error) {
	return &userv1.AcceptCPApplicationResponse{}, nil
}

func (f *fakeCPRelationshipListClient) RejectCPApplication(context.Context, *userv1.RejectCPApplicationRequest) (*userv1.RejectCPApplicationResponse, error) {
	return &userv1.RejectCPApplicationResponse{}, nil
}

func (f *fakeCPRelationshipListClient) ListCPRelationships(_ context.Context, req *userv1.ListCPRelationshipsRequest) (*userv1.ListCPRelationshipsResponse, error) {
	f.lastList = req
	return &userv1.ListCPRelationshipsResponse{}, nil
}

func (f *fakeCPRelationshipListClient) ListCPIntimacyLeaderboard(context.Context, *userv1.ListCPIntimacyLeaderboardRequest) (*userv1.ListCPIntimacyLeaderboardResponse, error) {
	return &userv1.ListCPIntimacyLeaderboardResponse{}, nil
}

func (f *fakeCPRelationshipListClient) PrepareBreakCPRelationship(context.Context, *userv1.PrepareBreakCPRelationshipRequest) (*userv1.PrepareBreakCPRelationshipResponse, error) {
	return &userv1.PrepareBreakCPRelationshipResponse{}, nil
}

func (f *fakeCPRelationshipListClient) ConfirmBreakCPRelationship(context.Context, *userv1.ConfirmBreakCPRelationshipRequest) (*userv1.ConfirmBreakCPRelationshipResponse, error) {
	return &userv1.ConfirmBreakCPRelationshipResponse{}, nil
}

func (f *fakeCPRelationshipListClient) CancelBreakCPRelationship(context.Context, *userv1.CancelBreakCPRelationshipRequest) (*userv1.CancelBreakCPRelationshipResponse, error) {
	return &userv1.CancelBreakCPRelationshipResponse{}, nil
}

func TestListCPRelationshipsQueryUserIDOverrideAndFallback(t *testing.T) {
	cases := []struct {
		name       string
		target     string
		wantUserID int64
	}{
		{
			name:       "valid query user id",
			target:     "/api/v1/cp/relationships?user_id=10002&relation_type=brother&page=3&page_size=7",
			wantUserID: 10002,
		},
		{
			name:       "missing query user id keeps current user",
			target:     "/api/v1/cp/relationships?relation_type=brother&page=3&page_size=7",
			wantUserID: 10001,
		},
		{
			name:       "invalid query user id keeps current user",
			target:     "/api/v1/cp/relationships?user_id=abc&relation_type=brother&page=3&page_size=7",
			wantUserID: 10001,
		},
		{
			name:       "non positive query user id keeps current user",
			target:     "/api/v1/cp/relationships?user_id=0&relation_type=brother&page=3&page_size=7",
			wantUserID: 10001,
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			client := &fakeCPRelationshipListClient{}
			handler := New(Config{UserCPClient: client})
			request := httptest.NewRequest(http.MethodGet, tc.target, nil)
			request = request.WithContext(auth.WithUserID(request.Context(), 10001))
			recorder := httptest.NewRecorder()

			handler.listCPRelationships(recorder, request)

			if recorder.Code != http.StatusOK {
				t.Fatalf("status = %d body=%s", recorder.Code, recorder.Body.String())
			}
			if client.lastList == nil {
				t.Fatalf("ListCPRelationships was not called")
			}
			if client.lastList.GetUserId() != tc.wantUserID {
				t.Fatalf("user_id = %d, want %d", client.lastList.GetUserId(), tc.wantUserID)
			}
			if client.lastList.GetRelationType() != "brother" || client.lastList.GetPage() != 3 || client.lastList.GetPageSize() != 7 {
				t.Fatalf("query fields not preserved: relation_type=%q page=%d page_size=%d", client.lastList.GetRelationType(), client.lastList.GetPage(), client.lastList.GetPageSize())
			}
		})
	}
}

func TestCPRelationshipFromProtoIncludesLevelProgress(t *testing.T) {
	item := &userv1.CPRelationship{
		RelationshipId:        "cp_rel:1:2",
		RelationType:          "brother",
		Status:                "active",
		IntimacyValue:         180,
		Level:                 2,
		CurrentLevelThreshold: 100,
		NextLevelThreshold:    300,
		NeededForNextLevel:    120,
		LevelProgressPercent:  40,
		MaxLevel:              false,
		BreakupCostCoins:      88,
		FormedAtMs:            1700000000000,
		EndedAtMs:             1700000002000,
		UpdatedAtMs:           1700000001000,
	}

	got := cpRelationshipFromProto(item)
	if got.CurrentLevelThreshold != 100 ||
		got.NextLevelThreshold != 300 ||
		got.NeededForNextLevel != 120 ||
		got.LevelProgressPercent != 40 ||
		got.MaxLevel ||
		got.BreakupCostCoins != 88 ||
		got.EndedAtMS != 1700000002000 {
		t.Fatalf("relationship progress fields not mapped: %+v", got)
	}
}

func TestCPIntimacyLeaderboardItemFromProtoIncludesBothUsersAndAvatarFrames(t *testing.T) {
	item := &userv1.CPIntimacyLeaderboardItem{
		Rank:           3,
		RelationshipId: "cp_rel:7101:7102",
		RelationType:   "cp",
		IntimacyValue:  9527,
		Level:          6,
		UserA: &userv1.CPIntimacyLeaderboardUser{
			UserId:        7101,
			DisplayUserId: "1007101",
			Username:      "Alice",
			Avatar:        "alice.png",
			AvatarFrame: &userv1.CPAvatarFrameSnapshot{
				ResourceId:   9101,
				ResourceCode: "frame_gold",
				Name:         "Gold",
				AssetUrl:     "gold.webp",
			},
		},
		UserB: &userv1.CPIntimacyLeaderboardUser{
			UserId:        7102,
			DisplayUserId: "1007102",
			Username:      "Bob",
			Avatar:        "bob.png",
			AvatarFrame: &userv1.CPAvatarFrameSnapshot{
				ResourceId:   9102,
				ResourceCode: "frame_blue",
				Name:         "Blue",
				PreviewUrl:   "blue-preview.webp",
			},
		},
		FormedAtMs:  1700000000000,
		UpdatedAtMs: 1700000005000,
	}

	got := cpIntimacyLeaderboardItemFromProto(item)
	if got.Rank != 3 ||
		got.RelationshipID != "cp_rel:7101:7102" ||
		got.IntimacyValue != 9527 ||
		got.Level != 6 ||
		got.UserA == nil ||
		got.UserA.UserID != "7101" ||
		got.UserA.DisplayUserID != "1007101" ||
		got.UserA.AvatarFrame == nil ||
		got.UserA.AvatarFrame.ResourceCode != "frame_gold" ||
		got.UserB == nil ||
		got.UserB.UserID != "7102" ||
		got.UserB.AvatarFrame == nil ||
		got.UserB.AvatarFrame.PreviewURL != "blue-preview.webp" ||
		got.FormedAtMS != 1700000000000 ||
		got.UpdatedAtMS != 1700000005000 {
		t.Fatalf("leaderboard item fields not mapped: %+v", got)
	}
}
