package utils

import (
	"context"
	"errors"
	"testing"

	. "github.com/onsi/gomega"
	"github.com/tidbcloud/pkgv2/auth/auth0"
	"github.com/tidbcloud/pkgv2/auth/util"
	"github.com/tidbcloud/serverless-service/internal/config"
	"github.com/tidbcloud/serverless-service/internal/domain/facade"
)

func TestGetUserFromContext(t *testing.T) {
	g := NewGomegaWithT(t)
	testCases := []struct {
		key         util.ContextKey
		user        any
		expectedErr error
	}{
		{
			key:         auth0.AuthTypeKey,
			user:        nil,
			expectedErr: errors.New("user not in context"),
		}, {
			key:         auth0.AuthTokenClaimKey,
			user:        nil,
			expectedErr: errors.New("user not in context"),
		}, {
			key:         auth0.AuthTokenClaimKey,
			user:        "test",
			expectedErr: errors.New("expect type facade.User in context"),
		}, {
			key: auth0.AuthTokenClaimKey,
			user: &facade.User{
				TenantID:       123,
				IsImpersonated: true,
			},
			expectedErr: nil,
		},
	}

	for _, tc := range testCases {
		ctx := context.Background()
		ctx = context.WithValue(ctx, tc.key, tc.user)
		u, err := GetUserFromContext(ctx)
		if tc.expectedErr == nil {
			g.Expect(err).To(BeNil())
			g.Expect(u).To(Equal(tc.user))
		} else {
			g.Expect(err).To(Equal(tc.expectedErr))
		}
	}
}

func TestGetAuthTypeFromContext(t *testing.T) {
	g := NewGomegaWithT(t)
	testCases := []struct {
		key      util.ContextKey
		authType any
		expected string
	}{
		{
			key:      auth0.AuthTokenClaimKey,
			authType: config.MailAuthType,
			expected: config.MailAuthType,
		}, {
			key:      auth0.AuthTypeKey,
			authType: nil,
			expected: config.MailAuthType,
		}, {
			key:      auth0.AuthTypeKey,
			authType: int64(1),
			expected: config.MailAuthType,
		}, {
			key:      auth0.AuthTypeKey,
			authType: config.MailAuthType,
			expected: config.MailAuthType,
		}, {
			key:      auth0.AuthTypeKey,
			authType: config.ApiKeyAuthType,
			expected: config.ApiKeyAuthType,
		},
	}

	for _, tc := range testCases {
		ctx := context.Background()
		ctx = context.WithValue(ctx, tc.key, tc.authType)
		authType := GetAuthTypeFromContext(ctx)
		g.Expect(authType).To(Equal(tc.expected))
	}
}

func TestGetGrpcGatewayValueFromContext(t *testing.T) {
	g := NewGomegaWithT(t)
	testCases := []struct {
		key      config.ContextKey
		value    any
		expected string
	}{
		{
			key:      config.CtxGRPCGatewayTokenKey,
			value:    nil,
			expected: "",
		}, {
			key:      config.CtxGRPCGatewayTokenKey,
			value:    struct{}{},
			expected: "",
		}, {
			key:      config.CtxGRPCGatewayTokenKey,
			value:    "test",
			expected: "test",
		},
	}

	for _, tc := range testCases {
		ctx := context.Background()
		ctx = context.WithValue(ctx, tc.key, tc.value)
		v := GetGrpcGatewayValueFromContext(ctx)
		g.Expect(v).To(Equal(tc.expected))
	}
}
