package prettyid

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

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

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

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

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

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

func TestResolveGrantTargetUserIDUsesShortDisplayID(t *testing.T) {
	resolver := &fakeGrantTargetResolver{
		users: map[int64]*userclient.User{},
		displays: map[string]*userclient.UserIdentity{
			"163001": {UserID: 312899006709637120, DisplayUserID: "163001"},
		},
	}

	userID, kind, err := resolveGrantTargetUserID(context.Background(), resolver, "req", "163001")
	if err != nil {
		t.Fatalf("resolveGrantTargetUserID returned error: %v", err)
	}
	if userID != 312899006709637120 || kind != "display_user_id" {
		t.Fatalf("target mismatch: userID=%d kind=%s", userID, kind)
	}
	if want := []string{"resolve:163001"}; !reflect.DeepEqual(resolver.calls, want) {
		t.Fatalf("calls mismatch: got %v want %v", resolver.calls, want)
	}
}

func TestResolveGrantTargetUserIDKeepsLongInternalID(t *testing.T) {
	resolver := &fakeGrantTargetResolver{
		users: map[int64]*userclient.User{
			312899006709637120: {UserID: 312899006709637120, DisplayUserID: "163001"},
		},
		displays: map[string]*userclient.UserIdentity{},
	}

	userID, kind, err := resolveGrantTargetUserID(context.Background(), resolver, "req", "312899006709637120")
	if err != nil {
		t.Fatalf("resolveGrantTargetUserID returned error: %v", err)
	}
	if userID != 312899006709637120 || kind != "user_id" {
		t.Fatalf("target mismatch: userID=%d kind=%s", userID, kind)
	}
	if want := []string{"get:312899006709637120"}; !reflect.DeepEqual(resolver.calls, want) {
		t.Fatalf("calls mismatch: got %v want %v", resolver.calls, want)
	}
}

func TestResolveGrantTargetUserIDFallsBackForLongDisplayID(t *testing.T) {
	resolver := &fakeGrantTargetResolver{
		users: map[int64]*userclient.User{},
		displays: map[string]*userclient.UserIdentity{
			"312899006709637120": {UserID: 411, DisplayUserID: "312899006709637120"},
		},
	}

	userID, kind, err := resolveGrantTargetUserID(context.Background(), resolver, "req", "312899006709637120")
	if err != nil {
		t.Fatalf("resolveGrantTargetUserID returned error: %v", err)
	}
	if userID != 411 || kind != "display_user_id" {
		t.Fatalf("target mismatch: userID=%d kind=%s", userID, kind)
	}
	if want := []string{"get:312899006709637120", "resolve:312899006709637120"}; !reflect.DeepEqual(resolver.calls, want) {
		t.Fatalf("calls mismatch: got %v want %v", resolver.calls, want)
	}
}

func TestResolveGrantTargetUserIDAcceptsPrettyDisplayID(t *testing.T) {
	resolver := &fakeGrantTargetResolver{
		users: map[int64]*userclient.User{},
		displays: map[string]*userclient.UserIdentity{
			"VIP2026": {UserID: 88, DisplayUserID: "VIP2026"},
		},
	}

	userID, kind, err := resolveGrantTargetUserID(context.Background(), resolver, "req", "VIP2026")
	if err != nil {
		t.Fatalf("resolveGrantTargetUserID returned error: %v", err)
	}
	if userID != 88 || kind != "display_user_id" {
		t.Fatalf("target mismatch: userID=%d kind=%s", userID, kind)
	}
	if want := []string{"resolve:VIP2026"}; !reflect.DeepEqual(resolver.calls, want) {
		t.Fatalf("calls mismatch: got %v want %v", resolver.calls, want)
	}
}

func TestResolveGrantTargetUserIDReportsMissingTarget(t *testing.T) {
	resolver := &fakeGrantTargetResolver{
		users:    map[int64]*userclient.User{},
		displays: map[string]*userclient.UserIdentity{},
	}

	_, _, err := resolveGrantTargetUserID(context.Background(), resolver, "req", "163001")
	if err != errGrantTargetNotFound {
		t.Fatalf("error mismatch: got %v want %v", err, errGrantTargetNotFound)
	}
}
