/*
SPDX-FileCopyrightText: Red Hat

SPDX-License-Identifier: Apache-2.0
*/

package utils

import (
	"fmt"
	"time"

	"github.com/openshift-kni/oran-o2ims/internal/constants"
)

// Default namespace
const (
	InventoryNamespace = constants.DefaultNamespace
)

// Base resource names
const (
	InventoryDatabase     = "postgres"
	InventoryResource     = "resource"
	InventoryAlarms       = "alarms"
	InventoryCluster      = "cluster"
	InventoryArtifacts    = "artifacts"
	InventoryProvisioning = "provisioning"
)

// Suffix for server names
const serverSuffix = "-server"

// Deployment names
const (
	InventoryDatabaseServerName     = InventoryDatabase + serverSuffix
	InventoryResourceServerName     = InventoryResource + serverSuffix
	InventoryAlarmServerName        = InventoryAlarms + serverSuffix
	InventoryClusterServerName      = InventoryCluster + serverSuffix
	InventoryArtifactsServerName    = InventoryArtifacts + serverSuffix
	InventoryProvisioningServerName = InventoryProvisioning + serverSuffix
)

// Hardware manager
const (
	HardwareManager           = "hardwaremanager"
	HardwareManagerServerName = HardwareManager + serverSuffix
)

// InventoryCRDName is the fully qualified name of the Inventory CRD, used as the
// owner reference for runtime-created cluster-scoped resources (ClusterRoles,
// ClusterRoleBindings) so they are garbage collected on operator uninstall.
const InventoryCRDName = "inventories.ocloud.openshift.io"

// IngressName defines the name of our ingress controller
const IngressName = "oran-o2ims-ingress"

// IngressClassName defines the ingress controller class to be used
const IngressClassName = "openshift-default"

// IngressPortName defines the name of service port to which our ingress controller directs traffic to
const IngressPortName = "api"

// Resource operations
const (
	UPDATE = "Update"
	PATCH  = "Patch"
)

// Field Manager Names for Server-Side Apply
const (
	// ProvisioningRequestFieldManager is the unique identifier for the ProvisioningRequest controller
	// when performing Server-Side Apply operations. This name is used by the Kubernetes API server
	// to track field ownership for SSA.
	ProvisioningRequestFieldManager = "provisioning-request-reconciler"
)

// Container arguments
var (
	AlarmServerArgs = []string{
		constants.AlarmsServerCmd,
		constants.ServeSubcommand,
		fmt.Sprintf("--api-listener-address=0.0.0.0:%d", constants.DefaultContainerPort),
		fmt.Sprintf("--tls-server-cert=%s/%s", constants.TLSServerMountPath, constants.TLSCertField),
		fmt.Sprintf("--tls-server-key=%s/%s", constants.TLSServerMountPath, constants.TLSKeyField),
		fmt.Sprintf("--audience=%s", InventoryAlarmServerName),
	}

	ArtifactsServerArgs = []string{
		constants.ArtifactsServerCmd,
		constants.ServeSubcommand,
		fmt.Sprintf("--api-listener-address=0.0.0.0:%d", constants.DefaultContainerPort),
		fmt.Sprintf("--tls-server-cert=%s/%s", constants.TLSServerMountPath, constants.TLSCertField),
		fmt.Sprintf("--tls-server-key=%s/%s", constants.TLSServerMountPath, constants.TLSKeyField),
		fmt.Sprintf("--audience=%s", InventoryArtifactsServerName),
	}

	ResourceServerArgs = []string{
		constants.ResourceServerCmd,
		constants.ServeSubcommand,
		fmt.Sprintf("--api-listener-address=0.0.0.0:%d", constants.DefaultContainerPort),
		fmt.Sprintf("--tls-server-cert=%s/%s", constants.TLSServerMountPath, constants.TLSCertField),
		fmt.Sprintf("--tls-server-key=%s/%s", constants.TLSServerMountPath, constants.TLSKeyField),
		fmt.Sprintf("--audience=%s", InventoryResourceServerName),
	}

	ClusterServerArgs = []string{
		constants.ClusterServerCmd,
		constants.ServeSubcommand,
		fmt.Sprintf("--api-listener-address=0.0.0.0:%d", constants.DefaultContainerPort),
		fmt.Sprintf("--tls-server-cert=%s/%s", constants.TLSServerMountPath, constants.TLSCertField),
		fmt.Sprintf("--tls-server-key=%s/%s", constants.TLSServerMountPath, constants.TLSKeyField),
		fmt.Sprintf("--audience=%s", InventoryClusterServerName),
	}

	ProvisioningServerArgs = []string{
		constants.ProvisioningServerCmd,
		constants.ServeSubcommand,
		fmt.Sprintf("--api-listener-address=0.0.0.0:%d", constants.DefaultContainerPort),
		fmt.Sprintf("--tls-server-cert=%s/%s", constants.TLSServerMountPath, constants.TLSCertField),
		fmt.Sprintf("--tls-server-key=%s/%s", constants.TLSServerMountPath, constants.TLSKeyField),
		fmt.Sprintf("--audience=%s", InventoryProvisioningServerName),
	}

	HardwareManagerServerArgs = []string{
		constants.HardwareManagerCmd,
		constants.StartSubcommand,
		constants.HealthProbeFlag + "=" + constants.HealthProbePort,
		fmt.Sprintf("%s=:%d", constants.MetricsFlag, constants.DefaultContainerPort),
		fmt.Sprintf("--metrics-tls-cert-dir=%s", constants.TLSServerMountPath),
		constants.LeaderElectFlag,
	}
)

// Search API attributes
const (
	SearchApiLabelKey   = "search-monitor"
	SearchApiLabelValue = "search-api"
)

// Default values for backend URL and token:
const (
	defaultApiServerURL    = "https://" + constants.KubernetesAPIService
	defaultBackendCABundle = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" // nolint: gosec // hardcoded path only
)

// Default timeout values
const (
	DefaultHardwareProvisioningTimeout = 90 * time.Minute
	DefaultClusterInstallationTimeout  = 90 * time.Minute
	DefaultClusterConfigurationTimeout = 30 * time.Minute
	DefaultClusterUpgradeTimeout       = 4 * time.Hour
	DefaultClusterEUSUpgradeTimeout    = 8 * time.Hour
)

// These are optional keys in the respective ConfigMaps defined in ClusterTemplate
// spec.templates, used to configure the timeout values for each operation.
// If not specified, the default timeout values will be applied.
const (
	HardwareProvisioningTimeoutConfigKey = "hardwareProvisioningTimeout"
	ClusterInstallationTimeoutConfigKey  = "clusterInstallationTimeout"
	ClusterConfigurationTimeoutConfigKey = "clusterConfigurationTimeout"
	ClusterUpgradeTimeoutConfigKey       = "clusterUpgradeTimeout"
)

// ClusterInstance template constants
const (
	ClusterInstanceTemplateName                 = "ClusterInstance"
	ClusterInstanceTemplateDefaultsConfigmapKey = "clusterinstance-defaults"
	ClusterInstanceCrdName                      = "clusterinstances"
)

var (
	// AllowedClusterInstanceFields contains path patterns for fields that are allowed to be updated.
	// The wildcard "*" is used to match any index in a list.
	AllowedClusterInstanceFields = [][]string{
		// Cluster-level non-immutable fields
		{"extraAnnotations"},
		{"extraLabels"},
		// Node-level non-immutable fields
		{"nodes", "*", "extraAnnotations"},
		{"nodes", "*", "extraLabels"},
	}

	// IgnoredClusterInstanceFields contains path patterns for fields that should be ignored.
	// The wildcard "*" is used to match any index in a list.
	IgnoredClusterInstanceFields = [][]string{
		// Node-level ignored fields
		{"nodes", "*", "bmcAddress"},
		{"nodes", "*", "bmcCredentialsName"},
		{"nodes", "*", "bootMACAddress"},
		{"nodes", "*", "hostRef"},
		{"nodes", "*", "nodeNetwork", "interfaces", "*", "macAddress"},
		// The interface labels are not part of the ClusterInstance.
		{"nodes", "*", "nodeNetwork", "interfaces", "*", "label"},
		// modified for upgrade
		{"suppressedManifests"},
	}
)

// PolicyTemplate constants
const (
	PolicyTemplateDefaultsConfigmapKey = "policytemplate-defaults"
	ClusterVersionLabelKey             = "cluster-version"
)

// Cluster status
const (
	ClusterZtpDone    = "ZTP Done"
	ClusterZtpNotDone = "ZTP Not Done"
)

const (
	OperationTypeCreated = "created"
	OperationTypeUpdated = "updated"
	OperationTypeDryRun  = "validated with dry-run"
)

// Environment variable names
const (
	TLSProfileMinVersionEnvName = "TLS_PROFILE_MIN_VERSION"
	TLSProfileCiphersEnvName    = "TLS_PROFILE_CIPHERS"
)

// Label specific to ACM child policies.
const (
	ChildPolicyRootPolicyLabel       = "policy.open-cluster-management.io/root-policy"
	ChildPolicyClusterNameLabel      = "policy.open-cluster-management.io/cluster-name"
	ChildPolicyClusterNamespaceLabel = "policy.open-cluster-management.io/cluster-namespace"
)

// Policy annotation keys
const (
	// CTPolicyTemplatesAnnotation is an optional annotation on root Policy objects.
	// It contains a comma-separated list of ClusterTemplate refs (metadata.name = spec.name + "." + spec.version)
	// that this root policy is associated with. When present, the controller will use it to
	// determine the expected set of child policies for a ProvisioningRequest using that template.
	CTPolicyTemplatesAnnotation = "clustertemplates.clcm.openshift.io/templates"
)

// POD Port Values
const (
	DefaultServiceTargetPort = "https"
	DatabaseTargetPort       = "database"
)

// ClusterVersionName is the name given to the default ClusterVersion object
const ClusterVersionName = "version"

// Upgrade constants
const (
	UpgradeDefaultsIBGUKey              = "imageBasedGroupUpgrade"
	UpgradeDefaultsClusterVersionKey    = "clusterVersion"
	UpgradeIntermediateVersionConfigKey = "intermediateVersion"
)

// CRDs needed to be suppressed in ClusterInstance for upgrade
var (
	CRDsToBeSuppressedForUpgrade = []string{
		"AgentClusterInstall",
	}
)

// Postgres values
const (
	AdminPasswordEnvName     = "POSTGRESQL_ADMIN_PASSWORD"     // nolint: gosec
	AlarmsPasswordEnvName    = "ORAN_O2IMS_ALARMS_PASSWORD"    // nolint: gosec
	ResourcesPasswordEnvName = "ORAN_O2IMS_RESOURCES_PASSWORD" // nolint: gosec
	ClustersPasswordEnvName  = "ORAN_O2IMS_CLUSTERS_PASSWORD"  // nolint: gosec

	DatabaseHostnameEnvVar = "POSTGRES_HOSTNAME"
)

// NodeCluster/ClusterResource extensions
const (
	ClusterModelExtension             = "model"
	ClusterVersionExtension           = "version"
	ClusterVendorExtension            = "vendor"
	ClusterAlarmDictionaryIDExtension = "alarmDictionaryID"

	ClusterModelHubCluster     = "hub-cluster"
	ClusterModelManagedCluster = "managed-cluster"

	OpenshiftVersionLabelName = "openshiftVersion"
	ClusterIDLabelName        = "clusterID"
	LocalClusterLabelName     = "local-cluster"

	ClusterTemplateArtifactsLabel = "clustertemplates.clcm.openshift.io/templateId"
	HardwareManagerNodeIdLabel    = "clcm.openshift.io/hwMgrNodeId"
)

// AlarmDefinitionSeverityField severity field within additional fields of alarm definition
const AlarmDefinitionSeverityField = "severity"

// Alertmanager values
const (
	AlertmanagerObjectName                      = "alertmanager"
	OpenClusterManagementObservabilityNamespace = "open-cluster-management-observability"
	AlertmanagerSA                              = "alertmanager"
)

// SMO OAuth specific environment variables.  These values are stored in environment variables to
// avoid them being visible in the command line arguments.
const (
	OAuthClientIDEnvName     = "SMO_OAUTH_CLIENT_ID"
	OAuthClientSecretEnvName = "SMO_OAUTH_CLIENT_SECRET" // nolint: gosec
)

// OAuth Secret fields
const (
	OAuthClientIDField     = "client-id"
	OAuthClientSecretField = "client-secret"
)

const AllocatedNodeLabel = "clcm.openshift.io/allocated-node"

// Status message constants
const ValidationMessage = "Validating and preparing resources"

// ClusterTemplate annotation keys
const (
	// SkipClusterImageSetValidationAnnotation when set to "true" (case-insensitive),
	// skips the validation that ensures the ClusterImageSet referenced in the
	// ClusterInstanceDefaults matches the release version specified in the ClusterTemplate.
	// This is useful in scenarios where the ClusterImageSet validation needs to be bypassed,
	// such as during testing or when using custom image sets that don't follow standard naming.
	SkipClusterImageSetValidationAnnotation = "clcm.openshift.io/skip-clusterimageset-validation"

	// SkipCleanupAnnotation is set on a ProvisioningRequest to indicate that cleanup
	// operations (disk wipe, power off) should be skipped when the PR is deleted.
	// This is propagated to the NAR and BMH during deletion processing.
	SkipCleanupAnnotation = "clcm.openshift.io/skip-cleanup"
)
