/*
Copyright AppsCode Inc. and Contributors

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

    http://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.
*/

//go:generate go-enum --mustparse --names --values
package v1alpha1

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

const (
	ResourceCodeKafkaOpsRequest     = "kfops"
	ResourceKindKafkaOpsRequest     = "KafkaOpsRequest"
	ResourceSingularKafkaOpsRequest = "kafkaopsrequest"
	ResourcePluralKafkaOpsRequest   = "kafkaopsrequests"
)

// kafkaDBOpsRequest defines a Kafka DBA operation.

// +genclient
// +k8s:openapi-gen=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// +kubebuilder:object:root=true
// +kubebuilder:resource:path=kafkaopsrequests,singular=kafkaopsrequest,shortName=kfops,categories={ops,kubedb,appscode}
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".spec.type"
// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.phase"
// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
type KafkaOpsRequest struct {
	metav1.TypeMeta   `json:",inline,omitempty"`
	metav1.ObjectMeta `json:"metadata,omitempty"`
	Spec              KafkaOpsRequestSpec `json:"spec,omitempty"`
	Status            OpsRequestStatus    `json:"status,omitempty"`
}

// KafkaOpsRequestSpec is the spec for KafkaOpsRequest
type KafkaOpsRequestSpec struct {
	// Specifies the Kafka reference
	DatabaseRef core.LocalObjectReference `json:"databaseRef"`
	// Specifies the ops request type: UpdateVersion, HorizontalScaling, VerticalScaling etc.
	Type KafkaOpsRequestType `json:"type"`
	// Specifies information necessary for upgrading Kafka
	UpdateVersion *KafkaUpdateVersionSpec `json:"updateVersion,omitempty"`
	// Specifies information necessary for horizontal scaling
	HorizontalScaling *KafkaHorizontalScalingSpec `json:"horizontalScaling,omitempty"`
	// Specifies information necessary for vertical scaling
	VerticalScaling *KafkaVerticalScalingSpec `json:"verticalScaling,omitempty"`
	// Specifies information necessary for volume expansion
	VolumeExpansion *KafkaVolumeExpansionSpec `json:"volumeExpansion,omitempty"`
	// Specifies information necessary for custom configuration of Kafka
	Configuration *ReconfigurationSpec `json:"configuration,omitempty"`
	// Specifies information necessary for configuring TLS
	TLS *TLSSpec `json:"tls,omitempty"`
	// Specifies information necessary for configuring authSecret of the database
	Authentication *AuthSpec `json:"authentication,omitempty"`
	// Specifies information necessary for restarting database
	Restart *RestartSpec `json:"restart,omitempty"`
	// Specifies information necessary for migrating storageClass or data
	Migration *KafkaMigrationSpec `json:"migration,omitempty"`
	// Timeout for each step of the ops request in second. If a step doesn't finish within the specified timeout, the ops request will result in failure.
	Timeout *metav1.Duration `json:"timeout,omitempty"`
	// ApplyOption is to control the execution of OpsRequest depending on the database state.
	// +kubebuilder:default="IfReady"
	Apply ApplyOption `json:"apply,omitempty"`
	// +kubebuilder:default=1
	MaxRetries int32 `json:"maxRetries,omitempty"`
}

// +kubebuilder:validation:Enum=UpdateVersion;HorizontalScaling;VerticalScaling;VolumeExpansion;Restart;Reconfigure;ReconfigureTLS;RotateAuth;StorageMigration
// ENUM(UpdateVersion, HorizontalScaling, VerticalScaling, VolumeExpansion, Restart, Reconfigure, ReconfigureTLS, RotateAuth, StorageMigration)
type KafkaOpsRequestType string

// KafkaMigrationSpec is the spec for storage migration of a Kafka cluster.
// Set Node for combined mode, or Controller + Broker for topology mode.
type KafkaMigrationSpec struct {
	// Node is the migration spec for a combined-mode Kafka instance.
	// +optional
	Node *StorageMigrationSpec `json:"node,omitempty"`
	// Controller is the migration spec for controller nodes in topology mode.
	// +optional
	Controller *StorageMigrationSpec `json:"controller,omitempty"`
	// Broker is the migration spec for broker nodes in topology mode.
	// +optional
	Broker *StorageMigrationSpec `json:"broker,omitempty"`
}

// KafkaReplicaReadinessCriteria is the criteria for checking readiness of a Kafka pod
// after updating, horizontal scaling etc.
type KafkaReplicaReadinessCriteria struct{}

// KafkaUpdateVersionSpec contains the update version information of a kafka cluster
type KafkaUpdateVersionSpec struct {
	// Specifies the target version name from catalog
	TargetVersion string `json:"targetVersion,omitempty"`
}

// KafkaHorizontalScalingSpec contains the horizontal scaling information of a Kafka cluster
type KafkaHorizontalScalingSpec struct {
	// Number of combined (i.e. broker, controller) node
	Node *int32 `json:"node,omitempty"`
	// Node topology specification
	Topology *KafkaHorizontalScalingTopologySpec `json:"topology,omitempty"`
}

// KafkaHorizontalScalingTopologySpec contains the horizontal scaling information in cluster topology mode
type KafkaHorizontalScalingTopologySpec struct {
	// Number of broker nodes
	Broker *int32 `json:"broker,omitempty"`
	// Number of controller nodes
	Controller *int32 `json:"controller,omitempty"`
}

// KafkaVerticalScalingSpec contains the vertical scaling information of a Kafka cluster
type KafkaVerticalScalingSpec struct {
	// Resource spec for combined nodes
	Node *PodResources `json:"node,omitempty"`
	// Resource spec for broker
	Broker *PodResources `json:"broker,omitempty"`
	// Resource spec for controller
	Controller *PodResources `json:"controller,omitempty"`
	// Mode selects how the vertical scaling is actuated. Defaults to Restart.
	// +optional
	// +kubebuilder:default=Restart
	Mode VerticalScalingMode `json:"mode,omitempty"`
}

// KafkaVolumeExpansionSpec is the spec for Kafka volume expansion
type KafkaVolumeExpansionSpec struct {
	Mode VolumeExpansionMode `json:"mode"`
	// volume specification for combined nodes
	Node *resource.Quantity `json:"node,omitempty"`
	// volume specification for broker
	Broker *resource.Quantity `json:"broker,omitempty"`
	// volume specification for controller
	Controller *resource.Quantity `json:"controller,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// KafkaOpsRequestList is a list of KafkaOpsRequests
type KafkaOpsRequestList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	// Items is a list of KafkaOpsRequest CRD objects
	Items []KafkaOpsRequest `json:"items,omitempty"`
}
