package gamemanagement

import (
	"context"
	"errors"
	"reflect"
	"strconv"
	"testing"

	"hyapp-admin-server/internal/integration/userclient"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
)

type fakeGameWhitelistUserResolver struct {
	users      map[int64]*userclient.User
	identities map[string]*userclient.UserIdentity
	calls      []string
}

func (f *fakeGameWhitelistUserResolver) GetUser(_ context.Context, req userclient.GetUserRequest) (*userclient.User, error) {
	f.calls = append(f.calls, "get:"+strconv.FormatInt(req.UserID, 10))
	if profile := f.users[req.UserID]; profile != nil {
		return profile, nil
	}
	return nil, status.Error(codes.NotFound, "user not found")
}

func (f *fakeGameWhitelistUserResolver) ResolveDisplayUserID(_ context.Context, req userclient.ResolveDisplayUserIDRequest) (*userclient.UserIdentity, error) {
	f.calls = append(f.calls, "resolve:"+req.DisplayUserID)
	if identity := f.identities[req.DisplayUserID]; identity != nil {
		return identity, nil
	}
	return nil, status.Error(codes.NotFound, "display_user_id not found")
}

func TestResolveGameWhitelistUserAcceptsShortAndPrettyDisplayIDs(t *testing.T) {
	for _, keyword := range []string{"163001", "VIP2026"} {
		t.Run(keyword, func(t *testing.T) {
			resolver := &fakeGameWhitelistUserResolver{
				users:      map[int64]*userclient.User{88: {UserID: 88, DisplayUserID: keyword, Username: "matched"}},
				identities: map[string]*userclient.UserIdentity{keyword: {UserID: 88, DisplayUserID: keyword}},
			}
			profile, kind, err := resolveGameWhitelistUser(context.Background(), resolver, "req", keyword)
			if err != nil || profile == nil || profile.UserID != 88 || kind != "display_user_id" {
				t.Fatalf("resolve %q = profile=%+v kind=%q err=%v", keyword, profile, kind, err)
			}
			if want := []string{"resolve:" + keyword, "get:88"}; !reflect.DeepEqual(resolver.calls, want) {
				t.Fatalf("calls = %v, want %v", resolver.calls, want)
			}
		})
	}
}

func TestResolveGameWhitelistUserKeepsLongInternalIDAndFallsBackForLongPrettyID(t *testing.T) {
	const internalID = int64(312899006709637120)
	resolver := &fakeGameWhitelistUserResolver{
		users:      map[int64]*userclient.User{internalID: {UserID: internalID}},
		identities: map[string]*userclient.UserIdentity{},
	}
	profile, kind, err := resolveGameWhitelistUser(context.Background(), resolver, "req", strconv.FormatInt(internalID, 10))
	if err != nil || profile.UserID != internalID || kind != "user_id" {
		t.Fatalf("internal ID resolve = profile=%+v kind=%q err=%v", profile, kind, err)
	}
	if want := []string{"get:312899006709637120"}; !reflect.DeepEqual(resolver.calls, want) {
		t.Fatalf("calls = %v, want %v", resolver.calls, want)
	}

	resolver = &fakeGameWhitelistUserResolver{
		users: map[int64]*userclient.User{77: {UserID: 77, DisplayUserID: "312899006709637120"}},
		identities: map[string]*userclient.UserIdentity{
			"312899006709637120": {UserID: 77, DisplayUserID: "312899006709637120"},
		},
	}
	profile, kind, err = resolveGameWhitelistUser(context.Background(), resolver, "req", "312899006709637120")
	if err != nil || profile.UserID != 77 || kind != "display_user_id" {
		t.Fatalf("long pretty ID resolve = profile=%+v kind=%q err=%v", profile, kind, err)
	}
	wantCalls := []string{"get:312899006709637120", "resolve:312899006709637120", "get:77"}
	if !reflect.DeepEqual(resolver.calls, wantCalls) {
		t.Fatalf("calls = %v, want %v", resolver.calls, wantCalls)
	}
}

func TestResolveGameWhitelistUserReportsMissingTarget(t *testing.T) {
	resolver := &fakeGameWhitelistUserResolver{users: map[int64]*userclient.User{}, identities: map[string]*userclient.UserIdentity{}}
	_, _, err := resolveGameWhitelistUser(context.Background(), resolver, "req", "VIP404")
	if !errors.Is(err, errGameWhitelistUserNotFound) {
		t.Fatalf("error = %v, want errGameWhitelistUserNotFound", err)
	}
}
