package entity

import (
	"database/sql/driver"
	"errors"
	"strings"
	"time"
)

type (
	DeployType string
	// Cloud is the cloud DBaaS runs in. The laptop is "local"
	CloudProviderStatus  string
	ProviderStatus       string
	RegionStatus         string
	ProfileStatus        string
	ComponentName        string
	ProfileVersionStatus string
)

const (
	//ClaimsKey        = "claims_key"
	ClaimsHasOrg     = "login_has_org"
	ClaimsOrgTypeKey = "login_org_type"
	ClaimsOrgIDKey   = "login_org_id"
	ClaimsSubKey     = "sub"
	ClaimsUsage      = "usage"

	ClaimsUsageTidbCloud   = "tidb_cloud"
	ClaimsUsageOtherSystem = "third_party"
)

const (
	//DeployTypeDedicated DeployType = "dedicated"
	//DeployTypeShared    DeployType = "shared"
	//
	//ProviderStatusActive   CloudProviderStatus = "active"
	//ProviderStatusInactive CloudProviderStatus = "inactive"
	//RegionStatusActive     RegionStatus        = "active"
	//RegionStatusInactive   RegionStatus        = "inactive"
	//
	//ProfileStatusActive   ProfileStatus = "active"
	//ProfileStatusInactive ProfileStatus = "inactive"
	//ProfileStatusDeleted  ProfileStatus = "deleted"

	PD      ComponentName = "pd"      // Placement Driver
	TiKV    ComponentName = "tikv"    // TiKV
	TiDB    ComponentName = "tidb"    // TiDB
	TiFlash ComponentName = "tiflash" // TiFlash
	TiCDC   ComponentName = "ticdc"   // TiCDC

	ProfileVersionStatusSyncing  ProfileVersionStatus = "syncing"  // this profile has been created but under syncing
	ProfileVersionStatusUsing    ProfileVersionStatus = "using"    // this profile is in use
	ProfileVersionStatusOutdated ProfileVersionStatus = "outdated" // this profile is outdated

	CloudAdminUser = "cloud_admin" // cloudadmin user for controlplane to access customer tidb cluster

	// cluster have Readable/Writeable status in db record
	// uint64 means we can use this flag to control 64 unrelative status
	// 1 (1 << 0) means cluster is read only (from cluster to db). 2 (1 << 1) means cluster need to force to read only (from db to cluster)
	ForceReadOnlyStatus uint64 = 1 << 1
	ReadOnlyStatus      uint64 = 1 << 0
)

func StringToComponentName(in string) (ComponentName, error) {
	var cn ComponentName
	switch strings.ToLower(in) {
	case "pd":
		cn = PD
	case "tikv", "kv":
		cn = TiKV
	case "tidb", "mysql":
		cn = TiDB
	case "tiflash":
		cn = TiFlash
	case "ticdc":
		cn = TiCDC
	default:
		return cn, errors.New("could not parse as ComponentName: " + in)
	}
	return cn, nil
}

type (
	// enum
	TenantStatus          string
	ProjectStatus         string
	TenantPlan            string
	NotificationScene     string
	TenantKind            string
	ClusterStatus         string
	UserStatus            string
	UserRole              string
	RestoreStatus         string
	ImportStatus          string
	ClusterConnectionType string
	BackupStatus          string
	BackupType            string
	BackupMethod          string
	CDCTaskStatus         string
	CDCDownStreamType     string
	PeeringType           string
	ReplicationType       string
	ReplicationStatus     string
	CDCStatus             string
	DetachType            string
	TrialType             string
	DevTierIdleStage      string // the idle stage of dev tier, such as: warning, shutdown
	DevTierTrialStage     string // the ending stage of dev tier, such as: one-month before end
	DataFormat            uint32
	DataSource            uint32
	PeeringStatus         string // the status of aws/gcp vpc peering
	CDCMeteringStatus     string

	ClusterOperationType         string
	ClusterOperationStatus       string
	ScaleOperationTrackingStatus string

	DiscountType      uint32
	KafkaProtocolType string
	// Cloud is the cloud DBaaS runs in. The laptop is "local"
	Cloud string

	// Integration types
	IntegrationType    string
	IntegrationStatus  string
	IntegrationPayload string
	DatadogSite        string

	PocQuestionType string
	CommandStatus   string
	CommandAction   string
	OrgKeyStatus    string

	UserTargetAction    string
	HistoryTarget       string
	HistoryIdentityType string
	HistoryTargetType   string
	HistoryEvent        string

	EntityStatus   string
	AuthMethodType string
	DomainStatus   string
	//AuthMethodName Auth0ConnectionType

	OrgType     string
	OrgTag      string
	PartnerType string

	//Auth0ConnectionType string
	AuthMethodName string

	SqlUserAuthMethod string
	EntityEventType   string

	CredentialType string

	ClusterUserTargetType string
)

func (s ImportStatus) String() string {
	return string(s)
}

// enums
const (
	ClusterConnectionTypePrivate ClusterConnectionType = "private"
	ClusterConnectionTypePublic  ClusterConnectionType = "public"

	// ClusterStatusInitializing initialize the infra.
	ClusterStatusInitializing ClusterStatus = "initializing"
	// ClusterStatusPreparing provisioning nodes
	ClusterStatusPreparing ClusterStatus = "preparing"
	// ClusterStatusLaunching set up the tidb cluster
	ClusterStatusLaunching ClusterStatus = "launching"
	ClusterStatusNormal    ClusterStatus = "normal"
	ClusterStatusScaling   ClusterStatus = "scaling"
	// ClusterStatusUpgrading  ClusterStatus = "upgrading"
	ClusterStatusRecovering ClusterStatus = "recovering"
	// ClusterStatusDeleted indicate cluster is deleting, cluster
	// worker will list cluster in deleted status, then delete all resources
	ClusterStatusDeleted ClusterStatus = "deleted"
	// ClusterStatusCleared indicate all reosurce already clean up
	ClusterStatusCleared ClusterStatus = "cleared"
	// ClusterStatusDeletecomplete indicate cluster resources already deleted, but backup cleanup worker still in the process
	ClusterStatusDeletecomplete ClusterStatus = "deletecomplete"

	TenantStatusPending  TenantStatus = "pending"
	TenantStatusActive   TenantStatus = "active"
	TenantStatusInactive TenantStatus = "inactive"
	TenantStatusDeleted  TenantStatus = "deleted"
	TenantStatusCleared  TenantStatus = "cleared"

	TenantPlanNewUser   TenantPlan = "new_user"
	TenantPlanFreeTrial TenantPlan = "free_trial"
	TenantPlanPOC       TenantPlan = "poc"
	TenantPlanOnDemand  TenantPlan = "on_demand"

	ProjectStatusActive  ProjectStatus = "active"
	ProjectStatusDeleted ProjectStatus = "deleted"
	ProjectStatusCleared ProjectStatus = "cleared"

	NotificationDevDierReminder           NotificationScene = "dev_tier_reminder"
	NotificationSceneCustomerStatusUpdate NotificationScene = "customer_status_update"
	NotificationSceneWelcome              NotificationScene = "welcome"
	NotificationSceneInvite               NotificationScene = "invite"
	NotificationSceneAutoInvite           NotificationScene = "auto_invite"
	NotificationSceneVerification         NotificationScene = "verification"

	UserStatusActive   UserStatus = "active"
	UserStatusPending  UserStatus = "pending"
	UserStatusInactive UserStatus = "inactive"
	// UserStatusPendingSignup is a fake status indicating that a user is registered but has not
	// activated the account via email. It's for RPC and not used in the database.
	UserStatusPendingSignup UserStatus = "pending_signup"

	// FE use
	UserRoleOwner                      UserRole = "owner"
	UserRoleMember                     UserRole = "member"
	UserRoleBillingAdmin               UserRole = "billing_admin"
	UserRoleBillingViewer              UserRole = "billing_viewer"
	UserRoleAuditAdmin                 UserRole = "audit_admin"
	UserRoleOrgClusterCreator          UserRole = "org_cluster_creator"
	UserRoleImpersonated               UserRole = "impersonated"
	UserRoleProjectOwner               UserRole = "project_owner"
	UserRoleProjectDev                 UserRole = "project_developer"
	UserRoleProjectReadOnly            UserRole = "project_readonly"
	UserRoleProjectCtlPlaneViewer      UserRole = "project_ctl_plane_viewer"
	UserRoleClusterAdmin               UserRole = "cluster_admin"
	UserRoleClusterViewer              UserRole = "cluster_viewer"
	UserRoleClusterOperator            UserRole = "cluster_operator"
	UserRoleClusterDataAccessReadOnly  UserRole = "cluster_data_access_readonly"
	UserRoleClusterDataAccessReadWrite UserRole = "cluster_data_access_readwrite"

	PingCAPTenantID ID = 1

	PocQuestionTypeRadio       PocQuestionType = "RADIO"
	PocQuestionTypeCheckbox    PocQuestionType = "CHECKBOX"
	PocQuestionTypeText        PocQuestionType = "TEXT"
	PocQuestionTypeUnspecified PocQuestionType = "UNSPECIFIED"

	// in rolebinding the inactive  is pending
	RoleBindingStatusActive   = "active"
	RoleBindingStatusInactive = "inactive"
	RoleBindingStatusPending  = "pending"
	RoleBindingStatusDelete   = "delete"

	CommandStatusWaiting        CommandStatus = "waiting"
	CommandStatusIgnore         CommandStatus = "ignore"
	CommandStatusComplete       CommandStatus = "complete"
	CommandStatusFail           CommandStatus = "fail"
	CommandStatusFailClusterKey CommandStatus = "fail-cluster-key"

	OrgKeyStatusActive OrgKeyStatus = "active"
	OrgKeyStatusDelete OrgKeyStatus = "delete"

	CommandActionCreate CommandAction = "create"
	CommandActionDelete CommandAction = "delete"
	CommandActionUpdate CommandAction = "update"
	CommandActionCheck  CommandAction = "check"

	Active  EntityStatus = "active"
	Delete  EntityStatus = "delete"
	Pending EntityStatus = "pending"

	// auth_method status
	Enable  EntityStatus = "enable"
	Disable EntityStatus = "disable"

	DefaultClusterInOrgAction     UserTargetAction = "DefaultClusterInOrgAction"
	DefaultClusterInProjectAction UserTargetAction = "DefaultClusterInProjectAction"
	DefaultCreateClusterAction    UserTargetAction = "DefaultCreateCluster"
	CreateClusterAction           UserTargetAction = "CreateCluster"
	RegisterChannelAction         UserTargetAction = "Register-Form-Channel"
	NewUserAction                 UserTargetAction = "NewUserRegister"

	HistoryEventLogin            HistoryEvent = "LOGIN"
	HistoryEventVisitProject     HistoryEvent = "VISIT_PROJECT"
	HistoryEventVisitOrg         HistoryEvent = "VISIT_ORG"
	HistoryEventVisitClusterMode HistoryEvent = "VISIT_CLUSTER_MODE"

	IdentityTypeUser   HistoryIdentityType = "USER"
	IdentityTypeAPIKey HistoryIdentityType = "API_KEY"

	HistoryTargetTypeOrg         HistoryTargetType = "ORG"
	HistoryTargetTypeProject     HistoryTargetType = "PROJECT"
	HistoryTargetTypeClusterMode HistoryTargetType = "CLUSTER_MODE"

	OrgTypePersonal   OrgType = "personal"
	OrgTypeEnterprise OrgType = "enterprise"

	// org tag
	PartnerTypeMsp      PartnerType = "MSP"
	PartnerTypeResale   PartnerType = "RESALE"
	PartnerTypeCppo     PartnerType = "CPPO"
	PartnerTypeMCPO     PartnerType = "MCPO"
	PartnerTypeAlicloud PartnerType = "ALICLOUD"

	// msp partner
	OrgTagMsp         OrgTag = "msp"
	OrgTagMspCustomer OrgTag = "msp_customer"

	// resale partner
	OrgTagResalePartner  OrgTag = "resale_partner"
	OrgTagResaleCustomer OrgTag = "resale_customer"

	// tcpn asw cppo partner
	OrgTagAwsCppo         OrgTag = "aws_cppo"
	OrgTagAwsCppoCustomer OrgTag = "aws_cppo_customer"

	OrgTagGcpMCPOReseller OrgTag = "gcp_mcpo_reseller"
	OrgTagGcpMCPOCustomer OrgTag = "gcp_mcpo_customer"

	OrgTagAlicloud         OrgTag = "alicloud"
	OrgTagAlicloudCustomer OrgTag = "alicloud_customer"

	AuthMethodTypePassword AuthMethodType = "Password"
	AuthMethodTypeSocial   AuthMethodType = "Social"
	AuthMethodTypeOIDC     AuthMethodType = "OIDC"
	AuthMethodTypeSAML     AuthMethodType = "SAML"

	DomainStatusUnverified     DomainStatus = "unverified"
	DomainStatusOwnerConfirmed DomainStatus = "owner_confirmed"
	DomainStatusVerified       DomainStatus = "verified"

	// oidc name is variable
	// for email/password login, auth0 return the sub is 'auth0|64a3959ce75de1eae0668264'
	AuthMethodNameEmail     AuthMethodName = "auth0"
	AuthMethodNameGoogle    AuthMethodName = "google-oauth2"
	AuthMethodNameGitHub    AuthMethodName = "github"
	AuthMethodNameMicrosoft AuthMethodName = "windowslive"

	// SqlUser
	//AuthMethodPassword SqlUserAuthMethod = "password"
	//AuthMethodLdap     SqlUserAuthMethod = "ldap"
	MspThirdPartyAccountProvider           = "msp_account_provider"
	ResaleThirdPartyAccountProvider        = "resale_account_provider" // only for registration
	CommaSeparator                  string = ","

	// org create,  status  is pending
	EntityEventTypeCreate EntityEventType = "create"

	// new user click to activate email ,  org status is active
	EntityEventTypeActivate EntityEventType = "activate"
	EntityEventTypeUpdate   EntityEventType = "update"
	EntityEventTypeDelete   EntityEventType = "delete"

	// msp customer org conver to customer , table [msp_customer]  status=pending
	EntityEventTypeSchedule EntityEventType = "schedule"

	// msp customer org conver to customer , table [msp_customer]  status=active
	EntityEventTypeScheduleActivate EntityEventType = "schedule_activate"

	// msp customer org cancel  conver to customer
	EntityEventTypeScheduleCancel EntityEventType = "schedule_cancel"

	CredentialTypePassword CredentialType = "password"
	CredentialTypeToken    CredentialType = "token"

	TenantKindInternal TenantKind = "internal"
	TenantKindExternal TenantKind = "external"

	InviteTokenValidityPeriod = 7 * 24 * time.Hour
)

const (
	ApiKeyTypeBearerToken string = "bearer_token"
	ApiKeyTypeNormalKey   string = "normal"

	OperatorTypeApiKey int32 = 2
)

const (
	ProjectTypeDedicated    string = "dedicated"
	ProjectTypeTiDBX        string = "tidbx"
	ProjectTypeTiDBXVirtual string = "tidbx_virtual"
)

const (
	DbRoleAdmin     = "role_admin"
	DbRoleReadWrite = "role_readwrite"
	DbRoleReadOnly  = "role_readonly"
)

const (
	InviteUserSuccess     = 0
	InviteUserRepeated    = 10
	InviteUserInternalErr = 20
)

const (
	// Gcp is the GCP cloud
	Gcp = Cloud("gcp")

	// Aws is the AWS cloud
	Aws = Cloud("aws")
)
const (
	// the org's system
	SystemUserFirstName = "system"
	SystemUserLastName  = "user"
)

// Scan is for gorm
func (u *Cloud) Scan(value interface{}) error {
	*u = Cloud(value.([]byte))
	return nil
}

// Value is for gorm
func (u Cloud) Value() (driver.Value, error) { return string(u), nil }

func (u Cloud) String() string {
	return string(u)
}

func IsValidProvider(provider Cloud) bool {
	switch provider {
	case Aws, Gcp:
		return true
	default:
		return false
	}
}

// Encode old-style role into RoleBindings role name
func (r UserRole) Encode() string {
	return UserRoleEncode(string(r))
}

// Role binding roles
const (
	RoleBindingFixedRoleImpersonated = "impersonated"
	RoleOrgOwner                     = "org:owner"
	RoleOrgMember                    = "org:member"
	RoleOrgBillingAdmin              = "org:billing_admin"
	RoleOrgBillingViewer             = "org:billing_viewer"
	RoleOrgAuditAdmin                = "org:audit_admin"
	RoleOrgClusterCreator            = "org:cluster_creator"
	RoleOrgImpersonated              = "org:impersonated"
	RoleImpersonateOrgOwner          = "impersonate:org:owner"
	RolePartnerAdmin                 = "partner:admin"
	RoleProjectOwner                 = "project:owner"
	RoleProjectDev                   = "project:dev"              // Project Data Access Read Write
	RoleProjectReadOnly              = "project:readonly"         // Project Data Access Read Only
	RoleProjectCtlPlaneViewer        = "project:ctl_plane_viewer" // Project Viewer
	RoleClusterAdmin                 = "cluster:admin"
	RoleClusterViewer                = "cluster:viewer"
	//RoleClusterOperator              = "cluster:operator"
	//RoleClusterDataAccessReadOnly    = "cluster:data_access_readonly"
	//RoleClusterDataAccessReadWrite   = "cluster:data_access_readwrite"
	// RoleApiKeyOrgOwner deprecated, will be replaced by org:owner later
	RoleApiKeyOrgOwner             = "api:org:owner"
	RoleBearerTokenApiKeyScimOwner = "api:org:scim:owner"
)

// Mail Labels
const (
	MailLabelOrgCreator       = "MAIL_CREATOR"
	MailLabelOrgOwner         = "MAIL_OWNER"
	MailLabelOrgMembers       = "MAIL_MEMBERS"
	MailLabelOrgBillingAdmins = "MAIL_BILLING_ADMINS"
	MailLabelOrgAuditAdmins   = "MAIL_AUDIT_ADMINS"
	MailLabelOrgManager       = "MAIL_MANAGER"
)

// Map const
var (
	AuthMethodNameMap = map[AuthMethodName]AuthMethodType{
		AuthMethodNameEmail:     AuthMethodTypePassword,
		AuthMethodNameGoogle:    AuthMethodTypeSocial,
		AuthMethodNameGitHub:    AuthMethodTypeSocial,
		AuthMethodNameMicrosoft: AuthMethodTypeSocial,
	}

	// the method is support now
	AuthMethodArr = []string{
		string(AuthMethodNameEmail),
		string(AuthMethodNameGoogle),
		string(AuthMethodNameGitHub),
		string(AuthMethodNameMicrosoft),
		DefaultOidcAuthMethodName,
		DefaultSamlAuthMethodName,
	}
)

const (
	DefaultOidcAuthMethodName = "OIDC"
	DefaultSamlAuthMethodName = "SAML"
)

//var (
//	AuthMethodNameMap = map[AuthMethodName]AuthMethodType{
//		AuthMethodNameEmail:     AuthMethodTypePassword,
//		AuthMethodNameGoogle:    AuthMethodTypeSocial,
//		AuthMethodNameGitHub:    AuthMethodTypeSocial,
//		AuthMethodNameMicrosoft: AuthMethodTypeSocial,
//		AuthMethodNameOIDC:      AuthMethodTypeOIDC,
//	}
//)

const (
	// ClusterUserTargetApiKey and ClusterUserTargetUser just for backward compatibility, No longer use
	ClusterUserTargetApiKey       ClusterUserTargetType = "APIKEY"
	ClusterUserTargetUser         ClusterUserTargetType = "USER"
	ClusterUserTargetCloudApiKey  ClusterUserTargetType = "CloudApiKey"
	ClusterUserTargetCloudUser    ClusterUserTargetType = "CloudUser"
	ClusterUserTargetCloudSqlUser ClusterUserTargetType = "CloudSqlUser"
	ClusterUserTargetLimitedUser  ClusterUserTargetType = "LimitedUser"
	ClusterUserTargetBuiltinUser  ClusterUserTargetType = "BuiltinUser"
)
