package auth

import (
	"context"
	"fmt"
	"regexp"
	"strconv"

	"github.com/form3tech-oss/jwt-go"
	"github.com/pingcap/errcode"
	entity "github.com/tidbcloud/core-svc/model"
	"github.com/tidbcloud/pkgv2/auth/auth0"
)

func NewGetClaim() auth0.GetClaim {
	return getClaim
}

func getClaim(ctx context.Context, claims jwt.MapClaims) (interface{}, error) {
	email, err := auth0.GetEmailClaim(claims)
	if err != nil {
		return nil, errcode.NewNotAuthenticatedErr(err)
	}

	subClaim, err := auth0.GetSubjectClaim(claims)
	if err != nil {
		return nil, errcode.NewNotAuthenticatedErr(err)
	}

	httpURI := ctx.Value(auth0.AuthHttpURI).(string)
	orgID, _, err := ParseOrgIDAndClusterID(httpURI)
	if err != nil {
		return nil, errcode.NewInvalidInputErr(err)
	}

	// The kubernetes dashboard proxy is currently only open to the management portal.
	if IsK8sDashboardPath(httpURI) {
		orgID = entity.PingCAPTenantID
	}
	return GetUser(ctx, email, subClaim, orgID.Uint64())
}

var (
	BaseProxyAPIPrefix          = `^orgs/(\d+)/clusters/(\d+)/`
	TiDBMetricsProxyAPIPrefix   = fmt.Sprintf("%sprometheus/", BaseProxyAPIPrefix)
	TiDBDashboardProxyAPIPrefix = fmt.Sprintf("%spd/dashboard/", BaseProxyAPIPrefix)
	K8sDashboardProxyAPIPrefix  = fmt.Sprintf("%skubernetes_dashboard/", BaseProxyAPIPrefix)
)

var (
	RegexpBaseProxyAPI          = regexp.MustCompile(BaseProxyAPIPrefix)
	RegexpTiDBMetricsProxyAPI   = regexp.MustCompile(TiDBMetricsProxyAPIPrefix)
	RegexpTiDBDashboardProxyAPI = regexp.MustCompile(TiDBDashboardProxyAPIPrefix)
	RegexpK8sDashboardProxyAPI  = regexp.MustCompile(K8sDashboardProxyAPIPrefix)
)

func ParseOrgIDAndClusterID(urlPath string) (orgID entity.ID, clusterID entity.ID, err error) {
	matches := RegexpBaseProxyAPI.FindStringSubmatch(urlPath)
	if matches == nil {
		return 0, 0, fmt.Errorf("invalid proxy URL: %s", urlPath)
	}

	orgIDUint64, err := strconv.ParseUint(matches[1], 10, 64)
	if err != nil {
		return 0, 0, fmt.Errorf("invalid proxy URL: %s", urlPath)
	}

	clusterIDUint64, err := strconv.ParseUint(matches[2], 10, 64)
	if err != nil {
		return 0, 0, fmt.Errorf("invalid proxy URL: %s", urlPath)
	}

	orgID = entity.ID(orgIDUint64)
	clusterID = entity.ID(clusterIDUint64)
	return
}

func IsMetricsPath(urlPath string) bool {
	return RegexpTiDBMetricsProxyAPI.MatchString(urlPath)
}

func IsDashboardPath(urlPath string) bool {
	return RegexpTiDBDashboardProxyAPI.MatchString(urlPath)
}

func IsK8sDashboardPath(urlPath string) bool {
	return RegexpK8sDashboardProxyAPI.MatchString(urlPath)
}
