package auth

import (
	"context"
	"testing"

	. "github.com/onsi/gomega"
	"github.com/tidbcloud/pkgv2/auth/auth0"
	"github.com/tidbcloud/serverless-service/internal/config"
	"google.golang.org/grpc/metadata"
)

func TestGetAuthHandler(t *testing.T) {
	g := NewGomegaWithT(t)
	testCases := []struct {
		uri     string
		openApi bool
	}{
		{"/api/internal/health", true},
		{"/api/internal/projects/*any", true},
		{"/api/internal/*any", true},
		{"/api/devtier/*any", false},
		{"/api/v1/devtier/*any", false},
		{"/api/v1beta/devtier/*any", true},
	}

	for _, tc := range testCases {
		ctx := context.Background()
		ctx = metadata.NewIncomingContext(ctx, metadata.Pairs("x-http-uri", tc.uri))
		handler := GetAuthHandler(ctx)
		g.Expect(handler).ToNot(BeNil())
		if tc.openApi {
			g.Expect(handler).To(Equal(openApiSingleton))
		} else {
			g.Expect(handler).To(Equal(consoleApiSingleton))
		}
	}
}

func TestFilterHttpRequest(t *testing.T) {
	g := NewGomegaWithT(t)
	testCases := []struct {
		url    string
		method string
		ok     bool
	}{
		{"", "GET", false},
		{"", "DELETE", true},
		{"/orgs/1234567", "OPTIONS", false},
		{"/orgs/1234567", "POST", true},
		{"/query", "POST", false},
		{"/query?id=1234567", "POST", true},
		{"/api/v1/orgs/1234567/query", "POST", false},
	}

	for _, tc := range testCases {
		ok := FilterHttpRequest(tc.url, tc.method)
		g.Expect(ok).To(Equal(tc.ok))
	}
}

func TestSkipLoopBack(t *testing.T) {
	g := NewGomegaWithT(t)
	testCases := []struct {
		stage    string
		clientIP string
		uri      string
		authType string
		ok       bool
	}{
		{
			stage:    config.StageStaging,
			clientIP: "127.0.0.1",
			ok:       false,
		}, {
			stage:    config.StageProd,
			clientIP: "127.0.0.1",
			ok:       false,
		}, {
			stage:    config.StageDev,
			clientIP: "127.0.0.2",
			ok:       false,
		}, {
			stage:    config.StageDev,
			clientIP: "127.0.0.1",
			uri:      "/api/internal/projects/0",
			authType: config.ApiKeyAuthType,
			ok:       true,
		}, {
			stage:    config.StageDev,
			clientIP: "127.0.0.1",
			uri:      "/api/v1/devtier/orgs/1234567/query",
			authType: config.MailAuthType,
			ok:       true,
		}, {
			stage:    config.StageDev,
			clientIP: "127.0.0.1",
			uri:      "/api/v1/test/query",
			authType: config.MailAuthType,
			ok:       true,
		},
	}

	for _, tc := range testCases {
		config.Global().ServerConfig.Stage = tc.stage
		ctx := metadata.NewIncomingContext(context.TODO(),
			metadata.Pairs(
				"x-forwarded-for", tc.clientIP,
				"x-http-uri", tc.uri,
			))
		newCtx, ok := skipLoopback(ctx)
		g.Expect(ok).To(Equal(tc.ok))
		if tc.ok {
			g.Expect(newCtx.Value(auth0.AuthTypeKey).(string)).To(Equal(tc.authType))
			g.Expect(newCtx.Value(auth0.AuthUserIDKey).(string)).To(Equal("loopback@host"))
		} else {
			g.Expect(newCtx).To(Equal(ctx))
		}
	}
}
