/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
*/

package v1

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

// NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
// Important: Run "make generate" to regenerate code after modifying this file

// +genclient
// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/autoscaling/v1.Scale
// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale
// +kubebuilder:object:root=true
// +kubebuilder:resource:path=integrations,scope=Namespaced,shortName=it,categories=kamel;camel
// +kubebuilder:subresource:status
// +kubebuilder:storageversion
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.selector
// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase`,description="The integration phase"
// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].status`,description="The integration readiness"
// +kubebuilder:printcolumn:name="Runtime Provider",type=string,JSONPath=`.status.runtimeProvider`,description="The runtime version"
// +kubebuilder:printcolumn:name="Runtime Version",type=string,JSONPath=`.status.runtimeVersion`,description="The runtime provider"
// +kubebuilder:printcolumn:name="Catalog Version",type=string,JSONPath=`.status.catalog.version`,description="The catalog version"
// +kubebuilder:printcolumn:name="Kit",type=string,JSONPath=`.status.integrationKit.name`,description="The integration kit"
// +kubebuilder:printcolumn:name="Replicas",type=integer,JSONPath=`.status.replicas`,description="The number of pods"

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

	// the desired Integration specification
	Spec IntegrationSpec `json:"spec,omitempty"`
	// the status of the Integration
	Status IntegrationStatus `json:"status,omitempty"`
}

// IntegrationSpec specifies the configuration of an Integration.
// The Integration will be watched by the operator which will be in charge to run the related application, according to the configuration specified.
type IntegrationSpec struct {
	// the number of `Pods` needed for the running Integration
	// +kubebuilder:default=1
	Replicas *int32 `json:"replicas,omitempty"`
	// the sources which contain the Camel routes to run
	Sources []SourceSpec `json:"sources,omitempty"`
	// the configuration of the project to build on Git
	Git *GitConfigSpec `json:"git,omitempty"`
	// a source in YAML DSL language which contain the routes to run
	Flows []Flow `json:"flows,omitempty"`
	// the reference of the `IntegrationKit` which is used for this Integration
	IntegrationKit *corev1.ObjectReference `json:"integrationKit,omitempty"`
	// the list of Camel or Maven dependencies required by the Integration
	Dependencies []string `json:"dependencies,omitempty"`
	// the profile needed to run this Integration
	Profile TraitProfile `json:"profile,omitempty"`
	// the traits needed to run this Integration
	Traits Traits `json:"traits,omitempty"`
	// Pod template customization
	// Deprecated:
	// Use container, init-containers or owner traits instead
	PodTemplate *PodSpecTemplate `json:"template,omitempty"`
	// Deprecated:
	// Use camel trait (camel.properties) to manage properties
	// Use mount trait (mount.configs) to manage configs
	// Use mount trait (mount.resources) to manage resources
	// Use mount trait (mount.volumes) to manage volumes
	Configuration []ConfigurationSpec `json:"configuration,omitempty"`
	// additional Maven repositories to be used
	Repositories []string `json:"repositories,omitempty"`
	// custom SA to use for the Integration
	ServiceAccountName string `json:"serviceAccountName,omitempty"`
}

// IntegrationStatus defines the observed state of Integration.
type IntegrationStatus struct {
	// ObservedGeneration is the most recent generation observed for this Integration.
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`
	// the actual phase
	Phase IntegrationPhase `json:"phase,omitempty"`
	// the digest calculated for this Integration
	Digest string `json:"digest,omitempty"`
	// the container image used
	Image string `json:"image,omitempty"`
	// the Java jar dependency to execute (if available)
	Jar string `json:"jar,omitempty"`
	// a list of dependencies needed by the application
	Dependencies []string `json:"dependencies,omitempty"`
	// the profile needed to run this Integration
	Profile TraitProfile `json:"profile,omitempty"`
	// the traits executed for the Integration
	Traits *Traits `json:"traits,omitempty"`
	// the reference of the `IntegrationKit` which is used for this Integration
	IntegrationKit *corev1.ObjectReference `json:"integrationKit,omitempty"`
	// The IntegrationPlatform watching this Integration
	Platform string `json:"platform,omitempty"`
	// a list of sources generated for this Integration
	GeneratedSources []SourceSpec `json:"generatedSources,omitempty"`
	// the runtime version targeted for this Integration
	RuntimeVersion string `json:"runtimeVersion,omitempty"`
	// the runtime provider targeted for this Integration
	RuntimeProvider RuntimeProvider `json:"runtimeProvider,omitempty"`
	// the catalog used to build/operate the Integration.
	Catalog *Catalog `json:"catalog,omitempty"`
	// Deprecated:
	// a list of configuration specification
	Configuration []ConfigurationSpec `json:"configuration,omitempty"`
	// a list of events happened for the Integration
	Conditions []IntegrationCondition `json:"conditions,omitempty"`
	// the operator version
	Version string `json:"version,omitempty"`
	// the number of replicas
	Replicas *int32 `json:"replicas,omitempty"`
	// label selector
	Selector string `json:"selector,omitempty"`
	// features offered by the Integration
	Capabilities []string `json:"capabilities,omitempty"`
	// the timestamp representing the last time when this integration was initialized.
	InitializationTimestamp *metav1.Time `json:"lastInitTimestamp,omitempty"`
}

// +kubebuilder:object:root=true

// IntegrationList contains a list of Integration.
type IntegrationList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`

	Items []Integration `json:"items"`
}

// IntegrationPhase --.
type IntegrationPhase string

// IntegrationConditionType --.
type IntegrationConditionType string

const (
	// IntegrationKind --.
	IntegrationKind string = "Integration"

	// IntegrationPhaseNone --.
	IntegrationPhaseNone IntegrationPhase = ""
	// IntegrationPhaseWaitingForPlatform --.
	IntegrationPhaseWaitingForPlatform IntegrationPhase = "Waiting For Platform"
	// IntegrationPhaseInitialization --.
	IntegrationPhaseInitialization IntegrationPhase = "Initialization"
	// IntegrationPhaseBuildingKit if building from a Camel route.
	IntegrationPhaseBuildingKit IntegrationPhase = "Building Kit"
	// IntegrationPhaseBuildSubmitted if building from a Git repository.
	IntegrationPhaseBuildSubmitted IntegrationPhase = "BuildSubmitted"
	// IntegrationPhaseBuildRunning if building from a Git repository.
	IntegrationPhaseBuildRunning IntegrationPhase = "BuildRunning"
	// IntegrationPhaseDeploying --.
	IntegrationPhaseDeploying IntegrationPhase = "Deploying"
	// IntegrationPhaseRunning --.
	IntegrationPhaseRunning IntegrationPhase = "Running"
	// IntegrationPhaseError --.
	IntegrationPhaseError IntegrationPhase = "Error"
	// IntegrationPhaseUnknown --.
	IntegrationPhaseUnknown IntegrationPhase = "Unknown"

	// IntegrationConditionReady --.
	IntegrationConditionReady IntegrationConditionType = "Ready"
	// IntegrationConditionKitAvailable --.
	IntegrationConditionKitAvailable IntegrationConditionType = "IntegrationKitAvailable"
	// IntegrationConditionPlatformAvailable --.
	IntegrationConditionPlatformAvailable IntegrationConditionType = "IntegrationPlatformAvailable"
	// IntegrationConditionDeploymentAvailable --.
	IntegrationConditionDeploymentAvailable IntegrationConditionType = "DeploymentAvailable"
	// IntegrationConditionServiceAvailable --.
	IntegrationConditionServiceAvailable IntegrationConditionType = "ServiceAvailable"
	// IntegrationConditionKnativeServiceAvailable --.
	IntegrationConditionKnativeServiceAvailable IntegrationConditionType = "KnativeServiceAvailable"
	// IntegrationConditionKnativeAvailable --.
	IntegrationConditionKnativeAvailable IntegrationConditionType = "KnativeAvailable"
	// IntegrationConditionCronJobAvailable --.
	IntegrationConditionCronJobAvailable IntegrationConditionType = "CronJobAvailable"
	// IntegrationConditionExposureAvailable --.
	IntegrationConditionExposureAvailable IntegrationConditionType = "ExposureAvailable"
	// IntegrationConditionPrometheusAvailable --.
	IntegrationConditionPrometheusAvailable IntegrationConditionType = "PrometheusAvailable"
	// IntegrationConditionJolokiaAvailable --.
	IntegrationConditionJolokiaAvailable IntegrationConditionType = "JolokiaAvailable"
	// IntegrationConditionProbesAvailable --.
	IntegrationConditionProbesAvailable IntegrationConditionType = "ProbesAvailable"
	// IntegrationConditionTraitInfo --.
	IntegrationConditionTraitInfo IntegrationConditionType = "TraitInfo"

	// IntegrationConditionKitAvailableReason --.
	IntegrationConditionKitAvailableReason string = "IntegrationKitAvailable"
	// IntegrationConditionPlatformAvailableReason --.
	IntegrationConditionPlatformAvailableReason string = "IntegrationPlatformAvailable"
	// IntegrationConditionDeploymentAvailableReason --.
	IntegrationConditionDeploymentAvailableReason string = "DeploymentAvailable"
	// IntegrationConditionDeploymentNotAvailableReason --.
	IntegrationConditionDeploymentNotAvailableReason string = "DeploymentNotAvailable"
	// IntegrationConditionServiceAvailableReason --.
	IntegrationConditionServiceAvailableReason string = "ServiceAvailable"
	// IntegrationConditionServiceNotAvailableReason --.
	IntegrationConditionServiceNotAvailableReason string = "ServiceNotAvailable"
	// IntegrationConditionContainerNotAvailableReason --.
	IntegrationConditionContainerNotAvailableReason string = "ContainerNotAvailable"
	// IntegrationConditionRouteAvailableReason --.
	IntegrationConditionRouteAvailableReason string = "RouteAvailable"
	// IntegrationConditionRouteNotAvailableReason --.
	IntegrationConditionRouteNotAvailableReason string = "RouteNotAvailable"
	// IntegrationConditionIngressAvailableReason --.
	IntegrationConditionIngressAvailableReason string = "IngressAvailable"
	// IntegrationConditionIngressNotAvailableReason --.
	IntegrationConditionIngressNotAvailableReason string = "IngressNotAvailable"
	// IntegrationConditionKnativeServiceAvailableReason --.
	IntegrationConditionKnativeServiceAvailableReason string = "KnativeServiceAvailable"
	// IntegrationConditionKnativeServiceNotAvailableReason --.
	IntegrationConditionKnativeServiceNotAvailableReason string = "KnativeServiceNotAvailable"
	// IntegrationConditionKnativeNotInstalledReason --.
	IntegrationConditionKnativeNotInstalledReason string = "KnativeNotInstalled"
	// IntegrationConditionCronJobAvailableReason --.
	IntegrationConditionCronJobAvailableReason string = "CronJobAvailableReason"
	// IntegrationConditionCronJobNotAvailableReason --.
	IntegrationConditionCronJobNotAvailableReason string = "CronJobNotAvailableReason"
	// IntegrationConditionPrometheusAvailableReason --.
	IntegrationConditionPrometheusAvailableReason string = "PrometheusAvailable"
	// IntegrationConditionJolokiaAvailableReason --.
	IntegrationConditionJolokiaAvailableReason string = "JolokiaAvailable"
	// IntegrationConditionProbesAvailableReason --.
	IntegrationConditionProbesAvailableReason string = "ProbesAvailable"
	// IntegrationConditionMonitoringPodsAvailableReason used to specify that the Pods generated are available for monitoring.
	IntegrationConditionMonitoringPodsAvailableReason string = "MonitoringPodsAvailable"
	// IntegrationConditionKnativeServiceReadyReason --.
	IntegrationConditionKnativeServiceReadyReason string = "KnativeServiceReady"
	// IntegrationConditionDeploymentReadyReason --.
	IntegrationConditionDeploymentReadyReason string = "DeploymentReady"
	// IntegrationConditionDeploymentProgressingReason --.
	IntegrationConditionDeploymentProgressingReason string = "DeploymentProgressing"
	// IntegrationConditionCronJobCreatedReason --.
	IntegrationConditionCronJobCreatedReason string = "CronJobCreated"
	// IntegrationConditionCronJobActiveReason --.
	IntegrationConditionCronJobActiveReason string = "CronJobActive"
	// IntegrationConditionLastJobSucceededReason --.
	IntegrationConditionLastJobSucceededReason string = "LastJobSucceeded"
	// IntegrationConditionLastJobFailedReason --.
	IntegrationConditionLastJobFailedReason string = "LastJobFailed"
	// IntegrationConditionRuntimeNotReadyReason --.
	IntegrationConditionRuntimeNotReadyReason string = "RuntimeNotReady"
	// IntegrationConditionErrorReason --.
	IntegrationConditionErrorReason string = "Error"
	// IntegrationConditionInitializationFailedReason --.
	IntegrationConditionInitializationFailedReason string = "InitializationFailed"
	// IntegrationConditionUnsupportedLanguageReason --.
	IntegrationConditionUnsupportedLanguageReason string = "UnsupportedLanguage"
	// IntegrationConditionKameletsAvailable --.
	IntegrationConditionKameletsAvailable IntegrationConditionType = "KameletsAvailable"
	// IntegrationConditionKameletsAvailableReason --.
	IntegrationConditionKameletsAvailableReason string = "KameletsAvailable"
	// IntegrationConditionKameletsNotAvailableReason --.
	IntegrationConditionKameletsNotAvailableReason string = "KameletsNotAvailable"
	// IntegrationConditionImportingKindAvailableReason used (as false) if we're trying to import an unsupported kind.
	IntegrationConditionImportingKindAvailableReason string = "ImportingKindAvailable"
)

// IntegrationCondition describes the state of a resource at a certain point.
type IntegrationCondition struct {
	// Type of integration condition.
	Type IntegrationConditionType `json:"type"`
	// Status of the condition, one of True, False, Unknown.
	Status corev1.ConditionStatus `json:"status"`
	// The last time this condition was updated.
	LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
	// Last time the condition transitioned from one status to another.
	LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
	// First time the condition status transitioned to True.
	FirstTruthyTime *metav1.Time `json:"firstTruthyTime,omitempty"`
	// The reason for the condition's last transition.
	Reason string `json:"reason,omitempty"`
	// A human-readable message indicating details about the transition.
	Message string `json:"message,omitempty"`
	// Pods collect health and conditions information from the owned PODs
	Pods []PodCondition `json:"pods,omitempty"`
}

// PodSpecTemplate represent a template used to deploy an Integration `Pod`.
type PodSpecTemplate struct {
	// the specification
	Spec PodSpec `json:"spec,omitempty"`
}

// PodSpec defines a group of Kubernetes resources.
type PodSpec struct {
	// AutomountServiceAccountToken
	AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty" protobuf:"varint,21,opt,name=automountServiceAccountToken"`
	// Volumes
	Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"`
	// InitContainers
	InitContainers []corev1.Container `json:"initContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,20,rep,name=initContainers"`
	// Containers
	Containers []corev1.Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"`
	// EphemeralContainers
	EphemeralContainers []corev1.EphemeralContainer `json:"ephemeralContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,34,rep,name=ephemeralContainers"`
	// RestartPolicy
	RestartPolicy corev1.RestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,3,opt,name=restartPolicy,casttype=RestartPolicy"`
	// TerminationGracePeriodSeconds
	TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty" protobuf:"varint,4,opt,name=terminationGracePeriodSeconds"`
	// ActiveDeadlineSeconds
	ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"`
	// DNSPolicy
	DNSPolicy corev1.DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"`
	// NodeSelector
	NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,7,rep,name=nodeSelector"`
	// TopologySpreadConstraints
	TopologySpreadConstraints []corev1.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey" protobuf:"bytes,33,opt,name=topologySpreadConstraints"`
	// PodSecurityContext
	SecurityContext corev1.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,34,opt,name=securityContext"`
}

type PodCondition struct {
	Name      string                `json:"name,omitempty" yaml:"name,omitempty"`
	Condition corev1.PodCondition   `json:"condition" yaml:"condition"`
	Health    []HealthCheckResponse `json:"health,omitempty" yaml:"health,omitempty"`
}
