/*
Copyright (C) 2022-2025 ApeCloud Co., Ltd

This file is part of KubeBlocks project

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package v1

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

	kbappsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
)

// +genclient
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:resource:categories={kubeblocks},shortName=inst
// +kubebuilder:printcolumn:name="UP-TO-DATE",type="string",JSONPath=".status.upToDate",description="update-to-date."
// +kubebuilder:printcolumn:name="READY",type="string",JSONPath=".status.ready",description="ready."
// +kubebuilder:printcolumn:name="AVAILABLE",type="string",JSONPath=".status.available",description="available."
// +kubebuilder:printcolumn:name="ROLE",type="string",JSONPath=".status.role",description="role."
// +kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp"

// Instance is the Schema for the instances API
type Instance struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   InstanceSpec    `json:"spec,omitempty"`
	Status InstanceStatus2 `json:"status,omitempty"`
}

//+kubebuilder:object:root=true

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

func init() {
	SchemeBuilder.Register(&Instance{}, &InstanceList{})
}

// InstanceSpec defines the desired state of Instance
type InstanceSpec struct {
	Template corev1.PodTemplateSpec `json:"template"`

	// Represents a label query over pods that should match the desired replica count indicated by the `replica` field.
	// It must match the labels defined in the pod template.
	// More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors
	Selector *metav1.LabelSelector `json:"selector"`

	// Defines the minimum number of seconds a newly created pod should be ready
	// without any of its container crashing to be considered available.
	// Defaults to 0, meaning the pod will be considered available as soon as it is ready.
	//
	// +kubebuilder:default=0
	// +kubebuilder:validation:Minimum=0
	// +optional
	MinReadySeconds int32 `json:"minReadySeconds,omitempty"`

	// Specifies a list of PersistentVolumeClaim templates that define the storage requirements for the instance.
	// Each template specifies the desired characteristics of a persistent volume, such as storage class,
	// size, and access modes.
	// These templates are used to dynamically provision persistent volumes for instance upon their creation.
	// The final name of each PVC is generated by appending the pod's identifier to the name specified in volumeClaimTemplates[*].name.
	//
	// +optional
	// VolumeClaimTemplates []corev1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
	VolumeClaimTemplates []corev1.PersistentVolumeClaimTemplate `json:"volumeClaimTemplates,omitempty"`

	// persistentVolumeClaimRetentionPolicy describes the lifecycle of persistent
	// volume claims created from volumeClaimTemplates. By default, all persistent
	// volume claims are created as needed and retained until manually deleted. This
	// policy allows the lifecycle to be altered, for example by deleting persistent
	// volume claims when their workload is deleted, or when their pod is scaled
	// down.
	//
	// +optional
	PersistentVolumeClaimRetentionPolicy *PersistentVolumeClaimRetentionPolicy `json:"persistentVolumeClaimRetentionPolicy,omitempty"`

	// +optional
	InstanceSetName string `json:"instanceSetName,omitempty"`

	// +optional
	InstanceTemplateName string `json:"instanceTemplateName,omitempty"`

	// Provides fine-grained control over the spec update process of the instance.
	//
	// +optional
	InstanceUpdateStrategyType *kbappsv1.InstanceUpdateStrategyType `json:"instanceUpdateStrategyType,omitempty"`

	// PodUpdatePolicy indicates how pods should be updated.
	//
	// +optional
	PodUpdatePolicy PodUpdatePolicyType `json:"podUpdatePolicy,omitempty"`

	// PodUpdatePolicy indicates how pods should be upgraded.
	//
	// +optional
	PodUpgradePolicy PodUpdatePolicyType `json:"podUpgradePolicy,omitempty"`

	// A list of roles defined in the system. Instanceset obtains role through pods' role label `kubeblocks.io/role`.
	//
	// +optional
	Roles []ReplicaRole `json:"roles,omitempty"`

	// Defines a set of hooks that customize the behavior of an Instance throughout its lifecycle.
	//
	// +optional
	LifecycleActions *LifecycleActions `json:"lifecycleActions,omitempty"`

	// Assistant objects that are necessary to run the instance.
	//
	// +optional
	InstanceAssistantObjects []InstanceAssistantObject `json:"instanceAssistantObjects,omitempty"`

	// Indicate whether the instance is scaled down.
	//
	// +optional
	ScaledDown *bool `json:"scaledDown,omitempty"`
}

// InstanceStatus2 defines the observed state of Instance
type InstanceStatus2 struct {
	// observedGeneration is the most recent generation observed for this InstanceSet. It corresponds to the
	// InstanceSet's generation, which is updated on mutation by the API Server.
	//
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Represents the latest available observations of an instance's current state.
	// Known .status.conditions.type are: "InstanceFailure", "InstanceReady", "InstanceAvailable"
	//
	// +optional
	Conditions []metav1.Condition `json:"conditions,omitempty"`

	// currentRevision, if not empty, indicates the version of the Instance used to generate pod.
	//
	// +optional
	CurrentRevision string `json:"currentRevision,omitempty"`

	// updateRevision, if not empty, indicates the version of the Instance used to generate pod.
	//
	// +optional
	UpdateRevision string `json:"updateRevision,omitempty"`

	// Represents whether the instance is up-to-date.
	//
	// +optional
	UpToDate bool `json:"upToDate,omitempty"`

	// Represents whether the instance is in ready condition.
	//
	// +optional
	Ready bool `json:"ready,omitempty"`

	// Represents whether the instance is in available condition.
	//
	// +optional
	Available bool `json:"available,omitempty"`

	// Represents the role of the instance observed.
	//
	// +optional
	Role string `json:"role,omitempty"`

	// Represents whether the instance is in volume expansion.
	//
	// +optional
	VolumeExpansion bool `json:"volumeExpansion,omitempty"`
}

type InstanceAssistantObject struct {
	Service        *corev1.Service        `json:"service,omitempty"`
	ConfigMap      *corev1.ConfigMap      `json:"configMap,omitempty"`
	Secret         *corev1.Secret         `json:"secret,omitempty"`
	ServiceAccount *corev1.ServiceAccount `json:"serviceAccount,omitempty"`
	Role           *rbacv1.Role           `json:"role,omitempty"`
	RoleBinding    *rbacv1.RoleBinding    `json:"roleBinding,omitempty"`
}
