package v1alpha1

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

type PrivateLinkServicePhase string

const (
	PrivateLinkServicePhasePending        PrivateLinkServicePhase = "Pending"
	PrivateLinkServicePhaseReadyForCreate PrivateLinkServicePhase = "ReadyForCreate"
	PrivateLinkServicePhaseCreating       PrivateLinkServicePhase = "Creating"
	PrivateLinkServicePhaseFailed         PrivateLinkServicePhase = "Failed"
	PrivateLinkServicePhaseActive         PrivateLinkServicePhase = "Active"
	PrivateLinkServicePhaseReadyForDelete PrivateLinkServicePhase = "ReadyForDelete"
	PrivateLinkServicePhaseDeleting       PrivateLinkServicePhase = "Deleting"
	PrivateLinkServicePhaseDeleted        PrivateLinkServicePhase = "Deleted"
)

const (
	LabelKeyOwnedBy            = "cloud.pingcap.com/owned-by"
	LabelValOwnedByPrivateLink = "private-link"

	DefaultPrivateSQLEndpointPort = int32(4000)
)

const (
	// for aws
	// for vpcendpointserviceconfiguration
	AnnotationKeyOwnCrossplaneNameVPCEService       = "cloud.pingcap.com/own-crossplane-name-vpcesvc"
	AnnotationKeyOwnCrossplaneNameResourceRecordSet = "cloud.pingcap.com/own-crossplane-name-rrset"
	// AnnotationKeyPrivateLinkServiceName is set on a PrivateLinkService CR to indicate that an
	// existing cloud resource should be adopted. The value is the provider-specific
	// service name:
	//   EKS: full AWS service name, e.g. com.amazonaws.vpce.us-east-1.vpce-svc-0abc1234
	AnnotationKeyPrivateLinkServiceName = "cloud.pingcap.com/private-link-service-name"
	// for gcp
	// there is no xp resource for the follwong name, they are created by gcp client
	AnnotationKeyOwnCrossplaneNamePSCNATSubenet        = "cloud.pingcap.com/own-crossplane-name-pscnatsubnet"
	AnnotationKeyOwnCrossplaneNamePSCServiceAttachment = "cloud.pingcap.com/own-crossplane-name-pscserviceattchment"
	AnnotationKeyOwnCrossplaneNamePSCDomain            = "cloud.pingcap.com/own-crossplane-name-pscdomain"
)

// EDIT THIS FILE!  THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.

// +kubebuilder:object:root=true
// +kubebuilder:resource:categories=regionserver
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="PHASE",type="string",JSONPath=".status.phase"
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"
// PrivateLinkService is the Schema for the PrivateLinkService API
type PrivateLinkService struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   PrivateLinkServiceSpec   `json:"spec,omitempty"`
	Status PrivateLinkServiceStatus `json:"status,omitempty"`
}

// +kubebuilder:validation:XValidation:rule="has(self.ownership) == has(oldSelf.ownership) && (!has(self.ownership) || self.ownership == oldSelf.ownership)",message="ownership is immutable"
type PrivateLinkServiceSpec struct {
	Provider         string    `json:"provider"`
	Region           string    `json:"region"`
	VPCRef           Reference `json:"vpcRef"`
	LoadBalancerName string    `json:"loadBalancerName"`
	// +optional
	Tags map[string]string `json:"tags"`
	// +optional
	Connections []Connection `json:"Connections,omitempty"`
	// +optional
	Ownership *ResourceOwnership `json:"ownership,omitempty"`
}

type Connection struct {
	Endpoint string `json:"endpoint"`
	// +optional
	// IPs is the ips of the endpoint, it is used to create dns record.
	// Used in Azure.
	IPs []string `json:"ips,omitempty"`

	// DefaultDomainName is the default domain name for the endpoint.
	// Used in AliCloud.
	// +optional
	DefaultDomainName string `json:"defaultDomainName,omitempty"`
}

type PrivateLinkServiceStatus struct {
	// +optional
	Phase PrivateLinkServicePhase `json:"phase,omitempty"`
	// +optional
	Message string `json:"message,omitempty"`
	// +optional
	VPCID string `json:"vpcId,omitempty"`
	// +optional
	EndpointService EndpointServiceStatus `json:"endpointServices,omitempty"`
	// +optional
	AllowedPrincipals []string `json:"allowedPrincipals,omitempty"`
	// +optional
	DNSSubIdentify string `json:"dnsSubIdentify,omitempty"`
	// +optional
	DNSIdentify string `json:"dnsIdentify,omitempty"`
	// +optional
	LoadBalancer LoadBalancerInfo `json:"loadBalancerStatuses,omitempty"`
	// +optional
	Connections []ConnectionStatus `json:"connectionStatuses,omitempty"`
	// +optional
	DNSRecord DNSRecordStatus `json:"dnsStatus,omitempty"`
	// +optional
	DNSOwnership string `json:"verifyDnsOwnership,omitempty"`
	// +optional
	NATSubnet NATSubnetStatus `json:"natSubnetStatus,omitempty"`
	// +optional
	ServiceAttachment ServiceAttachmentStatus `json:"serviceAttachmentStatus,omitempty"`
	// +optional
	AzurePrivateLinkService AzurePrivateLinkServiceStatus `json:"azurePrivateLinkServiceStatus,omitempty"`
}

type AzurePrivateLinkServiceStatus struct {
	// +optional
	Name string `json:"name,omitempty"`
	// A globally unique DNS Name for your Private Link Service. You can use this alias to request a connection to your Private Link Service.
	// +optional
	Alias string `json:"alias,omitempty"`
	// +optional
	ID string `json:"id,omitempty"`
	// +optional
	ServiceDNSName string `json:"serviceDnsName,omitempty"`
}

type ServiceAttachmentStatus struct {
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	ServiceAttachment string `json:"serviceAttachment,omitempty"`
	// +optional
	ConnectDomain string `json:"connectDomain,omitempty"`
	// +optional
	Port int32 `json:"port,omitempty"`
}

type NATSubnetStatus struct {
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	IPCidrRange string `json:"ipCidrRange,omitempty"`
}

type EndpointServiceStatus struct {
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	PrivateDNSName string `json:"privateDnsName,omitempty"`
	// Port is the primary listener port surfaced for backward compatibility.
	// For multi-port LoadBalancers it equals the first entry of Ports.
	// +optional
	Port int32 `json:"port,omitempty"`
	// Ports lists every listener port of the underlying LoadBalancer. Empty
	// for legacy single-port LBs (Port carries the value).
	// +optional
	Ports []int32 `json:"ports,omitempty"`
	// +optional
	ServiceName string `json:"serviceName,omitempty"`
	// +optional
	ServiceID string `json:"serviceId,omitempty"`
	// +optional
	AvailabilityZones []string `json:"availabilityZones,omitempty"`
}

type LoadBalancerInfo struct {
	// Port is the primary listener port for backward compatibility. For
	// multi-port LoadBalancers it equals the first entry of Ports.
	// +optional
	Port int32 `json:"port,omitempty"`
	// Ports lists every listener port of the underlying LoadBalancer. Empty
	// for legacy single-port LBs (Port carries the value).
	// +optional
	Ports []int32 `json:"ports,omitempty"`
	// +optional
	CloudResourceId string `json:"cloudResourceId"`
}

type DNSRecordStatus struct {
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	Status string `json:"status,omitempty"`
	// +optional
	Type string `json:"type,omitempty"`
	// +optional
	Value string `json:"value,omitempty"`
}

type ConnectionStatus struct {
	Endpoint string          `json:"endpoint"`
	Phase    ConnectionPhase `json:"phase"`
	// +optional
	Message string `json:"message,omitempty"`
	// +optional
	// DNSName is the dns name of the endpoint.
	// Used in GCP and Azure.
	DNSName string `json:"dnsName,omitempty"`
	// +optional
	// IPs is the ips of the endpoint, it is used to create dns record.
	// Used in Azure.
	IPs []string `json:"ips,omitempty"`
}

type ConnectionPhase string

const (
	ConnectionPhasePending  ConnectionPhase = "Pending"
	ConnectionPhaseActive   ConnectionPhase = "Active"
	ConnectionPhaseDeleting ConnectionPhase = "Deleting"
	ConnectionPhaseFailed   ConnectionPhase = "Failed"
)

// +kubebuilder:object:root=true
type PrivateLinkServiceList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []PrivateLinkService `json:"items"`
}

func init() {
	SchemeBuilder.Register(&PrivateLinkService{}, &PrivateLinkServiceList{})
}
