package config

import (
	"fmt"
	"time"

	"github.com/tidbcloud/core-svc/idl/pbgen/proto/core"
	entity "github.com/tidbcloud/core-svc/model"
	"github.com/tidbcloud/pkgv2/auth/util"
	"github.com/tidbcloud/tiinf/sdk/rbac/common"
)

const (
	TierTypeDedicated  string = "dedicated"
	TierTypeServerless string = "serverless"
)

func GetClusterTierType(isDevTier bool) string {
	if isDevTier {
		return TierTypeServerless
	}
	return TierTypeDedicated
}

type (
	Auth0ConnectionType string
)

const (
	Auth0SocialConnectionGoogle Auth0ConnectionType = "google-oauth2"
	Auth0SocialConnectionGithub Auth0ConnectionType = "github"
)

func (c Auth0ConnectionType) String() string {
	return string(c)
}

func (c Auth0ConnectionType) IsAuth0SocialConnection() bool {
	if c == Auth0SocialConnectionGoogle || c == Auth0SocialConnectionGithub {
		return true
	}
	return false
}

const (
	// SystemEmail is the email used for autonomous operations
	SystemEmail = "system@pingcap.com"

	ProfileMngApiKeyName = "profile_mng"

	DefaultDBOperationTimeout = 30 * time.Second

	SetAuditLogRedactStatusClause = "SET @@GLOBAL.tidb_audit_redact_log = %s"
	SetAuditLogMaxSize            = "SET @@GLOBAL.tidb_audit_log_max_size = 10485760"
	EnableAuditPluginClause       = "admin plugins enable audit"
	DisableAuditPluginClause      = "admin plugins disable audit"
	GetAllAuditLogAccessClause    = "SELECT id, user, db, tbl, access_type FROM mysql.tidb_audit_table_access ORDER BY id"
	DeleteAuditLogAccessClause    = "DELETE FROM mysql.tidb_audit_table_access WHERE id=%d"
	CreateAuditLogAccessClause    = "INSERT INTO mysql.tidb_audit_table_access (`user`, `db`, `tbl`, `access_type`, `create_time`) VALUES ('%s', '%s', '%s', '%s', NOW())"
	FlushAuditLogAccessClause     = "FLUSH tidb plugins audit"

	// audit log
	AuditRedactLogStatusON  = "ON"
	AuditRedactLogStatusOFF = "OFF"

	// cluster proxy
	DefaultClusterProxyTimeout  = 8
	AuditLogClusterproxyTimeout = 30

	// cluster tier
	RecommendedNodeCpuNum        int32 = 8
	RecommendedTiFlashNodeCpuNum int32 = 16

	MinAWSProjectCIDRMaskBits = 11
	MinGCPProjectCIDRMaskBits = 8
	MaxProjectCIDRMaskBits    = 17
	DefaultProjectCIDR        = "172.30.0.0/16"

	CtxGRPCGatewayTokenKey   util.ContextKey = common.METADATA_GRPC_GATEWAY_TOKEN
	CtxGRPCGatewayTokenValue                 = common.METADATA_GRPC_GATEWAY_VALUE

	CtxIdentityKey util.ContextKey = "ctxIdentityKey"
)

const (
	ErrImpersonatedUser = "impersonated user is a read only user"
	ErrProjectCIDRExist = "Project CIDR already exist"
)

var (
	UserVisibleClusterComponents = []core.ComponentType{
		core.ComponentType_COMPONENT_TYPE_TIDB,
		core.ComponentType_COMPONENT_TYPE_TIKV,
		core.ComponentType_COMPONENT_TYPE_TIFLASH,
	}
	CreatingClusterStatusSet = map[entity.ClusterStatus]bool{
		entity.ClusterStatusInitializing: true,
		entity.ClusterStatusPreparing:    true,
		entity.ClusterStatusLaunching:    true,
	}
	ClusterStatusPb2model = map[core.ClusterStatus]entity.ClusterStatus{
		core.ClusterStatus_CLUSTER_STATUS_INITIALIZING:              entity.ClusterStatusInitializing,
		core.ClusterStatus_CLUSTER_STATUS_PREPARING:                 entity.ClusterStatusPreparing,
		core.ClusterStatus_CLUSTER_STATUS_VOLUME_SNAPSHOT_RESTORING: entity.ClusterStatusVolumeSnapshotRestoring,
		core.ClusterStatus_CLUSTER_STATUS_LAUNCHING:                 entity.ClusterStatusLaunching,
		core.ClusterStatus_CLUSTER_STATUS_NORMAL:                    entity.ClusterStatusNormal,
		core.ClusterStatus_CLUSTER_STATUS_HIBERNATED:                entity.ClusterStatusHibernated,
		core.ClusterStatus_CLUSTER_STATUS_PAUSING:                   entity.ClusterStatusPausing,
		core.ClusterStatus_CLUSTER_STATUS_PAUSED:                    entity.ClusterStatusPaused,
		core.ClusterStatus_CLUSTER_STATUS_RESUMING:                  entity.ClusterStatusResuming,
		core.ClusterStatus_CLUSTER_STATUS_SCALING:                   entity.ClusterStatusScaling,
		core.ClusterStatus_CLUSTER_STATUS_RECOVERING:                entity.ClusterStatusRecovering,
		core.ClusterStatus_CLUSTER_STATUS_DELETED:                   entity.ClusterStatusDeleted,
		core.ClusterStatus_CLUSTER_STATUS_DELETECOMPLETE:            entity.ClusterStatusDeletecomplete,
		core.ClusterStatus_CLUSTER_STATUS_CLEARED:                   entity.ClusterStatusCleared,
	}
)

// checkClusterStatusPb2model ensure all statuses have mapping
func checkClusterStatusPb2model() {
	for key := range core.ClusterStatus_name {
		status := core.ClusterStatus(key)
		if status == core.ClusterStatus_CLUSTER_STATUS_UNSPECIFIED {
			continue
		}

		if _, ok := ClusterStatusPb2model[status]; !ok {
			panic(fmt.Sprintf("[checkClusterStatusPb2model]missing status mapping in ClusterStatusPb2model: %s", status))
		}
	}
}

func init() {
	checkClusterStatusPb2model()
}

func UserVisibleClusterComponentsContains(c core.ComponentType) bool {
	for _, v := range UserVisibleClusterComponents {
		if v == c {
			return true
		}
	}
	return false
}

var (
	// audit log
	ValidAuditLogAccessTypeOption = map[string]bool{
		"AlterTable":        true,
		"AnalyzeTable":      true,
		"Begin":             true,
		"Change":            true,
		"Commit":            true,
		"CreateDatabase":    true,
		"CreateIndex":       true,
		"CreateTable":       true,
		"CreateView":        true,
		"CreateUser":        true,
		"Delete":            true,
		"DropDatabase":      true,
		"DropIndex":         true,
		"DropView":          true,
		"DropTable":         true,
		"DescTable":         true,
		"ExplainAnalyzeSQL": true,
		"ExplainSQL":        true,
		"Replace":           true,
		"Insert":            true,
		"LoadData":          true,
		"RollBack":          true,
		"Select":            true,
		"Set":               true,
		"Show":              true,
		"TruncateTable":     true,
		"Update":            true,
		"Grant":             true,
		"Revoke":            true,
		"Deallocate":        true,
		"Execute":           true,
		"Prepare":           true,
		"Use":               true,
		"CreateBinding":     true,
		"IndexAdvise":       true,
		"DropBinding":       true,
		"Trace":             true,
		"Shutdown":          true,
		"other":             true,
	}
)

// RBAC
var (
	// NOTE1: proxy APIs don't pass through this middleware
	DefaultRBACPathPattern2ResourceMap = map[string]string{
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cloud_providers/query":                             "orgs/{org_id}/projects/{project_id}/cloud_providers/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/node_profiles/query":                               "orgs/{org_id}/projects/{project_id}/node_profiles/list",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/secondary_cluster_profiles": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/secondary_cluster_profiles/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cluster_fee/query":                                 "orgs/{org_id}/projects/{project_id}/cluster_fee/query",

		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clustersv2":                           "orgs/{org_id}/projects/{project_id}/clusters/create",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)":               "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/get",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)":            "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/delete",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/tidb_nodes":    "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tidb_nodes/list",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/tikv_nodes":    "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tikv_nodes/list",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/tiflash_nodes": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/tiflash_nodes/list",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters":                              "orgs/{org_id}/projects/{project_id}/clusters/list",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/recycle-bin":                           "orgs/{org_id}/projects/{project_id}/recycle-bin/list",
		"put:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/password":      "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/password/update",
		"patch:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/writable":    "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/update",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/pause":        "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/update",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/resume":       "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/update",
		"put:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clustersv2/([0-9A-Za-z]+)/components":  "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/update",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/names":                       "orgs/{org_id}/projects/{project_id}/clusters/names/get",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws_vpc_peerings":                   "orgs/{org_id}/projects/{project_id}/aws_vpc_peerings/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws_vpc_peerings":                  "orgs/{org_id}/projects/{project_id}/aws_vpc_peerings/create",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws_vpc_peerings/([0-9A-Za-z]+)":    "orgs/{org_id}/projects/{project_id}/aws_vpc_peerings/{id}/get",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws_vpc_peerings/([0-9A-Za-z]+)": "orgs/{org_id}/projects/{project_id}/aws_vpc_peerings/{id}/delete",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/gcp_vpc_peerings":                   "orgs/{org_id}/projects/{project_id}/gcp_vpc_peerings/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/gcp_vpc_peerings":                  "orgs/{org_id}/projects/{project_id}/gcp_vpc_peerings/create",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/gcp_vpc_peerings/([0-9A-Za-z]+)":    "orgs/{org_id}/projects/{project_id}/gcp_vpc_peerings/{id}/get",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/gcp_vpc_peerings/([0-9A-Za-z]+)": "orgs/{org_id}/projects/{project_id}/gcp_vpc_peerings/{id}/delete",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/connections":  "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/connections/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/connections": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/connections/create",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/traffic_filter":  "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/traffic_filter/get",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/traffic_filter": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/traffic_filter/update",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/[0-9A-Za-z]+/[a-zA-Z0-9_-]+/cidr":    "orgs/{org_id}/projects/{project_id}/provider/region/cidr/get",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/[0-9A-Za-z]+/cidr":                   "orgs/{org_id}/projects/{project_id}/provider/cidr/get",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/[0-9A-Za-z]+/cidr":                  "orgs/{org_id}/projects/{project_id}/provider/cidr/create",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/[0-9A-Za-z]+/cidr/validation/query": "orgs/{org_id}/projects/{project_id}/provider/cidr/validation/query",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cidr/regions":                        "orgs/{org_id}/projects/{project_id}/cidr/regions/list",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log":                                "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/get",
		"put:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log":                                "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/update",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log/precheck":                      "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/precheck",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log/plugin_status":                  "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/plugin_status/get",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log/access_records":                 "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/access_records/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log/access_records":                "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/access_records/create",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/audit_log/access_records/[0-9A-Za-z]+": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/audit_log/access_records/delete",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cross_account_deployments":                   "orgs/{org_id}/projects/{project_id}/cross_account_deployments/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cross_account_deployments":                  "orgs/{org_id}/projects/{project_id}/cross_account_deployments/create",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cross_account_deployments/delegation_info":   "orgs/{org_id}/projects/{project_id}/cross_account_deployments/delegation_info/get",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cross_account_deployments/([0-9A-Za-z]+)": "orgs/{org_id}/projects/{project_id}/cross_account_deployments/{id}/delete",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/iam_roles":                                   "orgs/{org_id}/projects/{project_id}/iam_roles/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/iam_roles":                                  "orgs/{org_id}/projects/{project_id}/iam_roles/create",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/iam_roles/([0-9A-Za-z]+)":                 "orgs/{org_id}/projects/{project_id}/iam_roles/{id}/delete",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/ca_cert": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/ca_cert/get",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/privatelink_service":                     "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/privatelink_service/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/privatelink_service":                    "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/privatelink_service/create",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/privatelink_service":                  "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/privatelink_service/delete",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/privatelink_endpoints":                  "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/privatelink_endpoints/create",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/privatelink_endpoints/[0-9A-Za-z_-]+": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/privatelink_endpoints/delete",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/privatelink_endpoints":                                           "orgs/{org_id}/projects/{project_id}/privatelink_endpoints/list",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/maintenance-window":                      "orgs/{org_id}/projects/{project_id}/maintenance-window/get",
		"put:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/maintenance-window":                      "orgs/{org_id}/projects/{project_id}/maintenance-window/update",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/maintenance-tasks":                       "orgs/{org_id}/projects/{project_id}/maintenance-tasks/list",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/maintenance-tasks/([0-9A-Za-z]+)/defer": "orgs/{org_id}/projects/{project_id}/maintenance-tasks/{id}/defer",

		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws_account": "orgs/{org_id}/projects/{project_id}/aws_account/get",
		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws-cmek":   "orgs/{org_id}/projects/{project_id}/aws-cmek/create",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/aws-cmek":    "orgs/{org_id}/projects/{project_id}/aws-cmek/list",

		"post:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cidrs":                               "orgs/{org_id}/projects/{project_id}/cidrs/create",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cidrs":                                "orgs/{org_id}/projects/{project_id}/cidrs/list",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cidrs/([0-9A-Za-z]+)":                 "orgs/{org_id}/projects/{project_id}/cidrs/{cidr_id}/get",
		"patch:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cidrs/([0-9A-Za-z]+)":               "orgs/{org_id}/projects/{project_id}/cidrs/{cidr_id}/update",
		"delete:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/cidrs/([0-9A-Za-z]+)":              "orgs/{org_id}/projects/{project_id}/cidrs/{cidr_id}/delete",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/defaultCidr":                          "orgs/{org_id}/projects/{project_id}/defaultCidr/get",
		"get:/api/v1/orgs/([0-9A-Za-z]+)/projects/([0-9A-Za-z]+)/clusters/([0-9A-Za-z]+)/accesspoints": "orgs/{org_id}/projects/{project_id}/clusters/{cluster_id}/accesspoints/list",
	}

	RBACPathWhitelist = []string{
		"/health_check",
		"/ping",
		"/api/v1/test-token",
	}
)
