/*
Copyright © The ESO Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package v1

import (
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ClusterExternalSecretSpec defines the desired state of ClusterExternalSecret.
type ClusterExternalSecretSpec struct {
	// The spec for the ExternalSecrets to be created
	ExternalSecretSpec ExternalSecretSpec `json:"externalSecretSpec"`

	// The name of the external secrets to be created.
	// Defaults to the name of the ClusterExternalSecret
	// +optional
	// +kubebuilder:validation:MinLength:=1
	// +kubebuilder:validation:MaxLength:=253
	// +kubebuilder:validation:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
	ExternalSecretName string `json:"externalSecretName,omitempty"`

	// The metadata of the external secrets to be created
	// +optional
	ExternalSecretMetadata ExternalSecretMetadata `json:"externalSecretMetadata,omitempty"`

	// The labels to select by to find the Namespaces to create the ExternalSecrets in.
	//
	// Deprecated: Use NamespaceSelectors instead.
	// +optional
	NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`

	// A list of labels to select by to find the Namespaces to create the ExternalSecrets in. The selectors are ORed.
	// +optional
	NamespaceSelectors []*metav1.LabelSelector `json:"namespaceSelectors,omitempty"`

	// Choose namespaces by name. This field is ORed with anything that NamespaceSelectors ends up choosing.
	//
	// Deprecated: Use NamespaceSelectors instead.
	// +optional
	// +kubebuilder:validation:items:MinLength:=1
	// +kubebuilder:validation:items:MaxLength:=63
	// +kubebuilder:validation:items:Pattern:=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
	Namespaces []string `json:"namespaces,omitempty"`

	// The time in which the controller should reconcile its objects and recheck namespaces for labels.
	RefreshInterval *metav1.Duration `json:"refreshTime,omitempty"`
}

// ExternalSecretMetadata defines metadata fields for the ExternalSecret generated by the ClusterExternalSecret.
type ExternalSecretMetadata struct {
	// +optional
	Annotations map[string]string `json:"annotations,omitempty"`

	// +optional
	Labels map[string]string `json:"labels,omitempty"`
}

// ClusterExternalSecretConditionType defines a value type for ClusterExternalSecret conditions.
type ClusterExternalSecretConditionType string

// ClusterExternalSecretReady is a ClusterExternalSecretConditionType set when the ClusterExternalSecret is ready.
const ClusterExternalSecretReady ClusterExternalSecretConditionType = "Ready"

// ClusterExternalSecretStatusCondition defines the observed state of a ClusterExternalSecret resource.
type ClusterExternalSecretStatusCondition struct {
	Type   ClusterExternalSecretConditionType `json:"type"`
	Status corev1.ConditionStatus             `json:"status"`

	// +optional
	Message string `json:"message,omitempty"`
}

// ClusterExternalSecretNamespaceFailure represents a failed namespace deployment and it's reason.
type ClusterExternalSecretNamespaceFailure struct {

	// Namespace is the namespace that failed when trying to apply an ExternalSecret
	Namespace string `json:"namespace"`

	// Reason is why the ExternalSecret failed to apply to the namespace
	// +optional
	Reason string `json:"reason,omitempty"`
}

// ClusterExternalSecretStatus defines the observed state of ClusterExternalSecret.
type ClusterExternalSecretStatus struct {
	// ExternalSecretName is the name of the ExternalSecrets created by the ClusterExternalSecret
	ExternalSecretName string `json:"externalSecretName,omitempty"`

	// Failed namespaces are the namespaces that failed to apply an ExternalSecret
	// +optional
	FailedNamespaces []ClusterExternalSecretNamespaceFailure `json:"failedNamespaces,omitempty"`

	// ProvisionedNamespaces are the namespaces where the ClusterExternalSecret has secrets
	// +optional
	ProvisionedNamespaces []string `json:"provisionedNamespaces,omitempty"`

	// +optional
	Conditions []ClusterExternalSecretStatusCondition `json:"conditions,omitempty"`
}

// ClusterExternalSecret is the Schema for the clusterexternalsecrets API.
// +kubebuilder:object:root=true
// +kubebuilder:storageversion
// +kubebuilder:resource:scope=Cluster,categories={external-secrets},shortName=ces
// +kubebuilder:subresource:status
// +kubebuilder:metadata:labels="external-secrets.io/component=controller"
// +kubebuilder:printcolumn:name="Store",type=string,JSONPath=`.spec.externalSecretSpec.secretStoreRef.name`
// +kubebuilder:printcolumn:name="Refresh Interval",type=string,JSONPath=`.spec.refreshTime`
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`
type ClusterExternalSecret struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   ClusterExternalSecretSpec   `json:"spec,omitempty"`
	Status ClusterExternalSecretStatus `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

// ClusterExternalSecretList contains a list of ClusterExternalSecret.
type ClusterExternalSecretList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []ClusterExternalSecret `json:"items"`
}
