package v1alpha1

import (
	"github.com/crossplane/crossplane-runtime/pkg/meta"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type VPCPhase string

const (
	VPCPhasePending        VPCPhase = "Pending"
	VPCPhaseReadyForCreate VPCPhase = "ReadyForCreate"
	VPCPhaseCreating       VPCPhase = "Creating"
	VPCPhaseFailed         VPCPhase = "Failed"
	VPCPhaseActive         VPCPhase = "Active"
	VPCPhaseReadyForDelete VPCPhase = "ReadyForDelete"
	VPCPhaseDeleting       VPCPhase = "Deleting"
	VPCPhaseDeleted        VPCPhase = "Deleted"
)

const (
	// for aws
	// subnet name is derived from vpc name
	AnnotationKeyOwnCrossplaneNameVPC           = "cloud.pingcap.com/own-crossplane-name-vpc"
	AnnotationKeyOwnCrossplaneNameSecurityGroup = "cloud.pingcap.com/own-crossplane-name-securitygroup"
	// for gcp
	// subnetwork name is derived from network
	AnnotationKeyOwnCrossplaneNameNetwork     = "cloud.pingcap.com/own-crossplane-name-network"
	AnnotationKeyOwnCrossplaneNamePSCFirewall = "cloud.pingcap.com/own-crossplane-name-pscfirewall"
)

// 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"
// VPC is the Schema for the VPC API
type VPC struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   VPCSpec   `json:"spec,omitempty"`
	Status VPCStatus `json:"status,omitempty"`
}

type VPCSpec struct {
	Provider string `json:"provider"`
	Region   string `json:"region"`
	CIDR     string `json:"cidr"`
	// +optional
	// for aws, default is empty.
	// If this field is set, the zones will be used in this vpc, otherwise, use the regionalserver config.
	Zones []string `json:"zones,omitempty"`

	AccountRef *AccountReference `json:"accountRef,omitempty"`
	// +optional
	// for aws, default is empty.
	// If this field is set, the secondary cidrs will be used in this vpc.
	SecondaryCidrs []string `json:"secondaryCidrs,omitempty"`
}

// AccountReference is a reference to an Account CR.
// It can be extended to use other types of references, like label selector.
type AccountReference struct {
	ProviderConfigName string `json:"providerConfigName"`
	// aws account id, gcp project id or azure subscription id
	AccountID string `json:"accountId"`
	// +optional
	Role string `json:"role,omitempty"`
}

type VPCStatus struct {
	// +optional
	Phase VPCPhase `json:"phase,omitempty"`
	// +optional
	Reason string `json:"reason,omitempty"`
	// +optional
	VPC VPCRes `json:"vpc,omitempty"`
	// +optional
	SecurityGroup SecurityGroup `json:"securityGroup,omitempty"`
	// +optional
	NodeSubnets []Subnet `json:"nodeSubnets,omitempty"`
	// +optional
	// ControlPlaneSubnets stores dedicated control-plane subnets, including AKS API server VNet integration subnets.
	ControlPlaneSubnets []Subnet `json:"controlPlaneSubnets,omitempty"`
	// +optional
	PublicSubnets []Subnet `json:"publicSubnets,omitempty"`
	// +optional
	PrivateSubnets []Subnet `json:"privateSubnets,omitempty"`
	// +optional
	PSCFirewall Firewall `json:"pscFirewall,omitempty"`
	// ResourceGroup is used for azure
	// +optional
	ResourceGroup ResourceGroup `json:"resourceGroup,omitempty"`
	// PodSubnets is used for aks
	// +optional
	PodSubnets []Subnet `json:"podSubnets,omitempty"`
	// PLSNatSubnets is used for aks
	// +optional
	PLSNATSubnets []Subnet `json:"plsNatSubnets,omitempty"`
	// SecondaryNodeSubnets is used for eks
	// +optional
	SecondaryNodeSubnets []Subnet `json:"secondaryNodeSubnets,omitempty"`
}

type ResourceGroup struct {
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	ID string `json:"id,omitempty"`
}

type Firewall struct {
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	FirewallID uint64 `json:"firewallId,omitempty"`
	// +optional
	SourceRanges []string `json:"sourceRanges,omitempty"`
}

type VPCRes struct {
	// +optional
	VPCID string `json:"vpcId,omitempty"`
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	// for azure
	ResourceID string `json:"resourceId,omitempty"`
}

type SecurityGroup struct {
	// +optional
	SecurityGroupID string `json:"securityGroupId,omitempty"`
	// +optional
	Name string `json:"name,omitempty"`
}

type Subnet struct {
	// +optional
	SubnetID string `json:"subnetId,omitempty"`
	// +optional
	Name string `json:"name,omitempty"`
	// +optional
	AvailabilityZone string `json:"availabilityZone,omitempty"`
	// +optional
	AvailabilityZoneID string `json:"availabilityZoneId,omitempty"`
	// +optional
	CIDRBlock string `json:"cidrBlock,omitempty"`
}

func FindSubnetByZone(subnets []Subnet, zone string) *Subnet {
	for _, subnet := range subnets {
		if subnet.AvailabilityZone == zone {
			return &subnet
		}
	}
	return nil
}

func SetExternalName(obj metav1.Object, name string) {
	if obj.GetAnnotations() == nil {
		obj.SetAnnotations(map[string]string{})
	}
	if name == "" {
		panic("empty name")
	}
	obj.GetAnnotations()[meta.AnnotationKeyExternalName] = name
}

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

func init() {
	SchemeBuilder.Register(&VPC{}, &VPCList{})
}
