// +kubebuilder:object:generate=true
package config

import (
	"fmt"
	"os"
	"strconv"
	"time"

	"gopkg.in/yaml.v3"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// ManagerConfig holds the configuration for the manager.
type ManagerConfig struct {
	// HTTP Server
	// +optional
	// +kubebuilder:default=8080
	HTTPPort int `yaml:"http_port" json:"httpPort"`

	// ManagerImage is the manager service image.
	ManagerImage string `yaml:"manager_image" json:"-"`
	// ProcdBinImageRef is an OCI image mounted read-only at /procd-image inside sandbox pods.
	ProcdBinImageRef string `yaml:"procd_bin_image_ref" json:"-"`

	DefaultClusterId string `yaml:"default_cluster_id" json:"-"`
	RegionID         string `yaml:"region_id" json:"-"`
	// +optional
	// +kubebuilder:default=true
	TemplateStoreEnabled bool `yaml:"template_store_enabled" json:"-"`

	// Kubernetes
	// +optional
	KubeConfig string `yaml:"kube_config" json:"kubeConfig"`
	// K8sClientQPS configures the manager-wide Kubernetes client token bucket rate.
	// When unset, manager uses the Sandbox0 Kubernetes client default.
	// +optional
	K8sClientQPS int `yaml:"k8s_client_qps" json:"k8sClientQps"`
	// K8sClientBurst configures the manager-wide Kubernetes client burst.
	// When unset, manager uses the Sandbox0 Kubernetes client default.
	// +optional
	K8sClientBurst int `yaml:"k8s_client_burst" json:"k8sClientBurst"`
	// +optional
	// +kubebuilder:default=true
	LeaderElection bool `yaml:"leader_election" json:"leaderElection"`
	// +optional
	// +kubebuilder:default="30s"
	ResyncPeriod metav1.Duration `yaml:"resync_period" json:"resyncPeriod"`

	// Database
	DatabaseURL string `yaml:"database_url" json:"-"`
	// +optional
	// +kubebuilder:default=10
	DatabaseMaxConns int32 `yaml:"database_max_conns" json:"databaseMaxConns"`
	// +optional
	// +kubebuilder:default=2
	DatabaseMinConns int32 `yaml:"database_min_conns" json:"databaseMinConns"`

	// RedisURL configures the Redis backend used for manager-wide admission locks.
	// When empty, manager falls back to PostgreSQL advisory locks.
	// +optional
	RedisURL string `yaml:"redis_url" json:"-"`
	// +optional
	RedisKeyPrefix string `yaml:"redis_key_prefix" json:"-"`
	// +optional
	RedisTimeout metav1.Duration `yaml:"redis_timeout" json:"-"`

	// Cleanup Controller
	// +optional
	// +kubebuilder:default="60s"
	CleanupInterval metav1.Duration `yaml:"cleanup_interval" json:"cleanupInterval"`

	// Logging
	// +optional
	// +kubebuilder:default="info"
	LogLevel string `yaml:"log_level" json:"logLevel"`

	// Metrics
	// +optional
	// +kubebuilder:default=9090
	MetricsPort int `yaml:"metrics_port" json:"metricsPort"`

	// Webhook
	// +optional
	// +kubebuilder:default=9443
	WebhookPort int `yaml:"webhook_port" json:"webhookPort"`
	// +optional
	// +kubebuilder:default="/tmp/k8s-webhook-server/serving-certs/tls.crt"
	WebhookCertPath string `yaml:"webhook_cert_path" json:"webhookCertPath"`
	// +optional
	// +kubebuilder:default="/tmp/k8s-webhook-server/serving-certs/tls.key"
	WebhookKeyPath string `yaml:"webhook_key_path" json:"webhookKeyPath"`

	// Sandbox
	// +optional
	// +kubebuilder:default="0s"
	DefaultSandboxTTL metav1.Duration `yaml:"default_sandbox_ttl" json:"defaultSandboxTTL"`
	// +optional
	// +kubebuilder:default="4Gi"
	TeamTemplateMemoryPerCPU string `yaml:"team_template_memory_per_cpu" json:"teamTemplateMemoryPerCpu"`
	// SandboxMaxMemory is the maximum memory limit accepted for a single sandbox.
	// +optional
	// +kubebuilder:default="32Gi"
	SandboxMaxMemory string `yaml:"sandbox_max_memory" json:"sandboxMaxMemory"`
	// +optional
	SandboxRuntimeClassName string `yaml:"sandbox_runtime_class_name" json:"sandboxRuntimeClassName"`
	// DefaultTeamQuotas configures region-wide fallback team quota limits.
	// Team-specific quota rows in the database override these defaults.
	// +optional
	DefaultTeamQuotas []TeamQuotaLimitConfig `yaml:"default_team_quotas" json:"defaultTeamQuotas"`
	// AllowColdStartWithoutReadyDataPlane lets cold claims create Pending pods
	// when no sandbox data-plane-ready nodes exist yet. This is required for
	// node autoscaler scale-from-zero deployments.
	// +optional
	AllowColdStartWithoutReadyDataPlane bool `yaml:"allow_cold_start_without_ready_data_plane" json:"allowColdStartWithoutReadyDataPlane"`

	// NetworkPolicyProvider selects the dataplane integration used to enforce sandbox network policy.
	// +optional
	// +kubebuilder:default="noop"
	NetworkPolicyProvider string `yaml:"network_policy_provider" json:"-"`

	// Netd apply wait
	// +optional
	// +kubebuilder:default="30s"
	NetdPolicyApplyTimeout metav1.Duration `yaml:"netd_policy_apply_timeout" json:"netdPolicyApplyTimeout"`
	// +optional
	// +kubebuilder:default="500ms"
	NetdPolicyApplyPollInterval metav1.Duration `yaml:"netd_policy_apply_poll_interval" json:"netdPolicyApplyPollInterval"`
	// +optional
	NetdMITMCASecretName string `yaml:"netd_mitm_ca_secret_name" json:"-"`
	// +optional
	NetdMITMCASecretNamespace string `yaml:"netd_mitm_ca_secret_namespace" json:"-"`

	// Pause/Resume
	// +optional
	// +kubebuilder:default="10Mi"
	PauseMinMemoryRequest string `yaml:"pause_min_memory_request" json:"pauseMinMemoryRequest"`
	// +optional
	// +kubebuilder:default="32Mi"
	PauseMinMemoryLimit string `yaml:"pause_min_memory_limit" json:"pauseMinMemoryLimit"`
	// +optional
	// +kubebuilder:default="1.1"
	PauseMemoryBufferRatio string `yaml:"pause_memory_buffer_ratio" json:"pauseMemoryBufferRatio"`
	// +optional
	// +kubebuilder:default="10m"
	PauseMinCPU string `yaml:"pause_min_cpu" json:"pauseMinCPU"`
	// CtldEnabled gates ctld-owned sandbox power transitions. When false, pause/resume is unsupported.
	// +optional
	// +kubebuilder:default=false
	CtldEnabled bool `yaml:"ctld_enabled" json:"-"`
	// +optional
	// +kubebuilder:default=8095
	CtldPort int `yaml:"ctld_port" json:"-"`

	// Timeouts
	// +optional
	// +kubebuilder:default="30s"
	ProcdClientTimeout metav1.Duration `yaml:"procd_client_timeout" json:"procdClientTimeout"`
	// +optional
	// +kubebuilder:default="15s"
	CtldClientTimeout metav1.Duration `yaml:"ctld_client_timeout" json:"-"`
	// +optional
	// +kubebuilder:default="6s"
	ProcdInitTimeout metav1.Duration `yaml:"procd_init_timeout" json:"procdInitTimeout"`
	// +optional
	// +kubebuilder:default="30s"
	ShutdownTimeout metav1.Duration `yaml:"shutdown_timeout" json:"shutdownTimeout"`

	// Procd config injected into sandbox pods
	// +optional
	// +kubebuilder:default={}
	ProcdConfig          ProcdConfig               `yaml:"procd_config" json:"procdConfig"`
	StorageProxyBaseURL  string                    `yaml:"storage_proxy_base_url" json:"-"`
	StorageProxyHTTPPort int                       `yaml:"storage_proxy_http_port" json:"-"`
	RootFSMaintenance    RootFSMaintenanceConfig   `yaml:"rootfs_maintenance" json:"-"`
	RootFSObjectStorage  RootFSObjectStorageConfig `yaml:"rootfs_object_storage" json:"-"`

	// SandboxObservabilityLogsIngestURL is the cluster-gateway internal logs ingest endpoint.
	// It is injected by infra-operator from spec.sandboxObservability.
	// +optional
	SandboxObservabilityLogsIngestURL string `yaml:"sandbox_observability_logs_ingest_url" json:"-"`
	// +optional
	SandboxObservabilityIngestQueueSize int `yaml:"sandbox_observability_ingest_queue_size" json:"-"`
	// +optional
	SandboxObservabilityIngestBatchSize int `yaml:"sandbox_observability_ingest_batch_size" json:"-"`
	// +optional
	SandboxObservabilityIngestFlushInterval metav1.Duration `yaml:"sandbox_observability_ingest_flush_interval" json:"-"`
	// +optional
	SandboxObservabilityIngestRequestTimeout metav1.Duration `yaml:"sandbox_observability_ingest_request_timeout" json:"-"`
	// +optional
	SandboxObservabilityIngestMaxRetries int `yaml:"sandbox_observability_ingest_max_retries" json:"-"`
	// +optional
	SandboxObservabilityIngestRetryBackoff metav1.Duration `yaml:"sandbox_observability_ingest_retry_backoff" json:"-"`
	// +optional
	SandboxObservabilityLogPollInterval metav1.Duration `yaml:"sandbox_observability_log_poll_interval" json:"-"`

	// Metering configures the optional region usage ledger.
	// +optional
	Metering MeteringConfig `yaml:"metering" json:"metering"`

	// Registry config for image pull secret provisioning
	// +optional
	// +kubebuilder:default={}
	Registry RegistryConfig `yaml:"registry" json:"-"`

	// Public Exposure config for generating public URLs (injected by infra-operator)
	// +optional
	PublicRootDomain string `yaml:"public_root_domain" json:"-"`
	// +optional
	PublicRegionID string `yaml:"public_region_id" json:"-"`

	// Runtime egress auth resolver settings injected by infra-operator.
	// Resolution now runs inside manager rather than a standalone service.
	// +optional
	EgressAuthDefaultResolveTTL metav1.Duration `yaml:"egress_auth_default_resolve_ttl" json:"-"`
	// +optional
	EgressAuthStaticAuth []StaticEgressAuthConfig `yaml:"egress_auth_static_auth" json:"-"`
	// +optional
	CredentialStore CredentialStoreConfig `yaml:"credential_store" json:"-"`

	// Autoscaler config for pool scaling behavior
	// +optional
	// +kubebuilder:default={}
	Autoscaler AutoscalerConfig `yaml:"autoscaler" json:"autoscaler"`

	// SandboxPodPlacement configures default scheduling constraints injected into
	// sandbox/template pool pods by the manager. This is operator-populated and
	// hidden from the public CRD surface so placement can follow data-plane
	// topology without requiring users to duplicate netd settings per template.
	// +optional
	SandboxPodPlacement SandboxPodPlacementConfig `yaml:"sandbox_pod_placement" json:"-"`
	// ClaimStartLimiter configures cluster-wide admission for claim and pool
	// starts. Defaults to min(30 * ready sandbox nodes, 80).
	// +optional
	ClaimStartLimiter ClaimStartLimiterConfig `yaml:"claim_start_limiter" json:"-"`
}

// TeamQuotaLimitConfig configures a fallback quota limit for teams without a
// database override for the same dimension.
type TeamQuotaLimitConfig struct {
	Dimension  string `yaml:"dimension" json:"dimension"`
	LimitValue int64  `yaml:"limit_value" json:"limitValue"`
}

// StaticEgressAuthConfig defines a static auth directive for runtime egress auth injection.
type StaticEgressAuthConfig struct {
	AuthRef string            `yaml:"auth_ref" json:"authRef"`
	Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
	TTL     metav1.Duration   `yaml:"ttl" json:"ttl"`
}

// CredentialStoreConfig configures credential source secret storage.
type CredentialStoreConfig struct {
	DefaultStorageKind string                       `yaml:"default_storage_kind" json:"-"`
	EncryptedPG        CredentialEncryptedPGConfig  `yaml:"encrypted_pg" json:"-"`
	Vault              CredentialVaultRuntimeConfig `yaml:"vault" json:"-"`
}

type RootFSMaintenanceConfig struct {
	Disabled                bool            `yaml:"disabled" json:"-"`
	Interval                metav1.Duration `yaml:"interval" json:"-"`
	BatchSize               int             `yaml:"batch_size" json:"-"`
	MaxBatchesPerRun        int             `yaml:"max_batches_per_run" json:"-"`
	Workers                 int             `yaml:"workers" json:"-"`
	ObjectDeleteClaimTTL    metav1.Duration `yaml:"object_delete_claim_ttl" json:"-"`
	ObjectDeleteBackoffBase metav1.Duration `yaml:"object_delete_backoff_base" json:"-"`
	ObjectDeleteBackoffMax  metav1.Duration `yaml:"object_delete_backoff_max" json:"-"`
	ObjectDeleteMaxAttempts int             `yaml:"object_delete_max_attempts" json:"-"`
	SquashDisabled          bool            `yaml:"squash_disabled" json:"-"`
	SquashMaxChainDepth     int             `yaml:"squash_max_chain_depth" json:"-"`
	SquashMaxChainBytes     int64           `yaml:"squash_max_chain_bytes" json:"-"`
}

type RootFSObjectStorageConfig struct {
	Type         string `yaml:"type" json:"-"`
	Bucket       string `yaml:"bucket" json:"-"`
	Region       string `yaml:"region" json:"-"`
	Endpoint     string `yaml:"endpoint" json:"-"`
	AccessKey    string `yaml:"access_key" json:"-"`
	SecretKey    string `yaml:"secret_key" json:"-"`
	SessionToken string `yaml:"session_token" json:"-"`
}

type CredentialEncryptedPGConfig struct {
	KeyID   string `yaml:"key_id" json:"-"`
	KeyFile string `yaml:"key_file" json:"-"`
	Key     string `yaml:"key" json:"-"`
}

type CredentialVaultRuntimeConfig struct {
	Connections []CredentialVaultConnectionConfig `yaml:"connections" json:"-"`
}

type CredentialVaultConnectionConfig struct {
	Name                string   `yaml:"name" json:"-"`
	Provider            string   `yaml:"provider" json:"-"`
	Address             string   `yaml:"address" json:"-"`
	TokenFile           string   `yaml:"token_file" json:"-"`
	CACertFile          string   `yaml:"ca_cert_file" json:"-"`
	Namespace           string   `yaml:"namespace" json:"-"`
	DefaultMount        string   `yaml:"default_mount" json:"-"`
	KVVersion           int      `yaml:"kv_version" json:"-"`
	SkipTLSVerify       bool     `yaml:"skip_tls_verify" json:"-"`
	AllowedPathPrefixes []string `yaml:"allowed_path_prefixes" json:"-"`
}

// SandboxPodPlacementConfig defines default scheduling constraints for sandbox
// workloads generated by the manager.
type SandboxPodPlacementConfig struct {
	NodeSelector map[string]string   `yaml:"node_selector" json:"-"`
	Tolerations  []corev1.Toleration `yaml:"tolerations" json:"-"`
}

// ClaimStartLimiterConfig defines cluster-wide start admission limits.
type ClaimStartLimiterConfig struct {
	PerSandboxNode int32           `yaml:"per_sandbox_node" json:"-"`
	MaxLimit       int32           `yaml:"max_limit" json:"-"`
	LockTTL        metav1.Duration `yaml:"lock_ttl" json:"-"`
	AcquireTimeout metav1.Duration `yaml:"acquire_timeout" json:"-"`
}

// AutoscalerConfig holds autoscaler settings for pool scaling behavior.
type AutoscalerConfig struct {
	// MinScaleInterval is the minimum time between scale operations for a template.
	// This prevents thundering herd when multiple cold claims arrive simultaneously.
	// +optional
	// +kubebuilder:default="100ms"
	MinScaleInterval metav1.Duration `yaml:"min_scale_interval" json:"minScaleInterval"`

	// ScaleUpFactor determines how aggressively to scale up.
	// When cold claim occurs, newReplicas = current * ScaleUpFactor.
	// +optional
	// +kubebuilder:default="1.5"
	ScaleUpFactor string `yaml:"scale_up_factor" json:"scaleUpFactor"`

	// MaxScaleStep caps the maximum pods to add in a single scale operation.
	// +optional
	// +kubebuilder:default=10
	MaxScaleStep int32 `yaml:"max_scale_step" json:"maxScaleStep"`

	// MinIdleBuffer is the minimum number of idle pods to maintain above minIdle.
	// When idle count drops to minIdle + MinIdleBuffer, proactive scaling kicks in.
	// +optional
	// +kubebuilder:default=2
	MinIdleBuffer int32 `yaml:"min_idle_buffer" json:"minIdleBuffer"`

	// TargetIdleRatio is the target ratio of idle pods to active pods.
	// Formula: desiredIdle = active * TargetIdleRatio
	// +optional
	// +kubebuilder:default="0.2"
	TargetIdleRatio string `yaml:"target_idle_ratio" json:"targetIdleRatio"`

	// NoTrafficScaleDownAfter is the duration without any claims before scaling down.
	// Scale down is still async and happens in the background reconcile loop.
	// +optional
	// +kubebuilder:default="10m"
	NoTrafficScaleDownAfter metav1.Duration `yaml:"no_traffic_scale_down_after" json:"noTrafficScaleDownAfter"`

	// ScaleDownPercent is the percentage to reduce replicas during scale down.
	// +optional
	// +kubebuilder:default="0.1"
	ScaleDownPercent string `yaml:"scale_down_percent" json:"scaleDownPercent"`
}

func (c AutoscalerConfig) ParsedScaleUpFactor(defaultValue float64) float64 {
	return parseFloatOrDefault(c.ScaleUpFactor, defaultValue)
}

func (c AutoscalerConfig) ParsedTargetIdleRatio(defaultValue float64) float64 {
	return parseFloatOrDefault(c.TargetIdleRatio, defaultValue)
}

func (c AutoscalerConfig) ParsedScaleDownPercent(defaultValue float64) float64 {
	return parseFloatOrDefault(c.ScaleDownPercent, defaultValue)
}

func parseFloatOrDefault(value string, defaultValue float64) float64 {
	if value == "" {
		return defaultValue
	}
	v, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return defaultValue
	}
	return v
}

// RegistryConfig holds registry settings for manager.
type RegistryConfig struct {
	// Provider is the registry provider identifier.
	// +optional
	Provider string `yaml:"provider" json:"-"`

	// PushRegistry is the registry hostname (host:port) for external image push.
	// +optional
	PushRegistry string `yaml:"push_registry" json:"-"`

	// PullRegistry is the registry hostname (host:port) for in-cluster image pull.
	// +optional
	PullRegistry string `yaml:"pull_registry" json:"-"`

	// PullSecretName is the secret name to create in template namespaces.
	// +optional
	PullSecretName string `yaml:"pull_secret_name" json:"-"`

	// PullCredentialsFile is the path to dockerconfigjson file for pull secrets.
	// +optional
	PullCredentialsFile string `yaml:"pull_credentials_file" json:"-"`

	// Namespace is the namespace for registry secrets.
	// +optional
	Namespace string `yaml:"namespace" json:"-"`

	// AWS configures AWS registry integration.
	// +optional
	AWS *RegistryAWSConfig `yaml:"aws" json:"-"`

	// GCP configures GCP registry integration.
	// +optional
	GCP *RegistryGCPConfig `yaml:"gcp" json:"-"`

	// Azure configures Azure registry integration.
	// +optional
	Azure *RegistryAzureConfig `yaml:"azure" json:"-"`

	// Aliyun configures Aliyun registry integration.
	// +optional
	Aliyun *RegistryAliyunConfig `yaml:"aliyun" json:"-"`

	// Harbor configures Harbor registry integration.
	// +optional
	Harbor *RegistryHarborConfig `yaml:"harbor" json:"-"`

	// Builtin configures builtin registry integration.
	// +optional
	Builtin *RegistryBuiltinConfig `yaml:"builtin" json:"-"`
}

// RegistryAWSConfig defines AWS registry config.
type RegistryAWSConfig struct {
	Region           string `yaml:"region" json:"-"`
	RegistryID       string `yaml:"registry_id" json:"-"`
	AssumeRoleARN    string `yaml:"assume_role_arn" json:"-"`
	ExternalID       string `yaml:"external_id" json:"-"`
	AccessKeySecret  string `yaml:"access_key_secret" json:"-"`
	AccessKeyKey     string `yaml:"access_key_key" json:"-"`
	SecretKeyKey     string `yaml:"secret_key_key" json:"-"`
	SessionTokenKey  string `yaml:"session_token_key" json:"-"`
	RegistryOverride string `yaml:"registry_override" json:"-"`
	AccessKeyID      string `yaml:"access_key_id" json:"-"`
	SecretAccessKey  string `yaml:"secret_access_key" json:"-"`
	SessionToken     string `yaml:"session_token" json:"-"`
}

// RegistryGCPConfig defines GCP registry config.
type RegistryGCPConfig struct {
	Registry             string `yaml:"registry" json:"-"`
	ServiceAccountSecret string `yaml:"service_account_secret" json:"-"`
	ServiceAccountKey    string `yaml:"service_account_key" json:"-"`
	ServiceAccountJSON   string `yaml:"service_account_json" json:"-"`
}

// RegistryAzureConfig defines Azure registry config.
type RegistryAzureConfig struct {
	Registry          string `yaml:"registry" json:"-"`
	CredentialsSecret string `yaml:"credentials_secret" json:"-"`
	TenantIDKey       string `yaml:"tenant_id_key" json:"-"`
	ClientIDKey       string `yaml:"client_id_key" json:"-"`
	ClientSecretKey   string `yaml:"client_secret_key" json:"-"`
	TenantID          string `yaml:"tenant_id" json:"-"`
	ClientID          string `yaml:"client_id" json:"-"`
	ClientSecret      string `yaml:"client_secret" json:"-"`
}

// RegistryAliyunConfig defines Aliyun registry config.
type RegistryAliyunConfig struct {
	Registry          string `yaml:"registry" json:"-"`
	Region            string `yaml:"region" json:"-"`
	InstanceID        string `yaml:"instance_id" json:"-"`
	CredentialsSecret string `yaml:"credentials_secret" json:"-"`
	AccessKeyKey      string `yaml:"access_key_key" json:"-"`
	SecretKeyKey      string `yaml:"secret_key_key" json:"-"`
	AccessKeyID       string `yaml:"access_key_id" json:"-"`
	AccessKeySecret   string `yaml:"access_key_secret" json:"-"`
}

// RegistryHarborConfig defines Harbor registry config.
type RegistryHarborConfig struct {
	Registry          string `yaml:"registry" json:"-"`
	CredentialsSecret string `yaml:"credentials_secret" json:"-"`
	UsernameKey       string `yaml:"username_key" json:"-"`
	PasswordKey       string `yaml:"password_key" json:"-"`
	Username          string `yaml:"username" json:"-"`
	Password          string `yaml:"password" json:"-"`
}

// RegistryBuiltinConfig defines builtin registry config.
type RegistryBuiltinConfig struct {
	// AuthSecretName is the name of the secret containing registry auth credentials.
	AuthSecretName string `yaml:"auth_secret_name" json:"-"`
	// UsernameKey is the key for username in the auth secret.
	UsernameKey string `yaml:"username_key" json:"-"`
	// PasswordKey is the key for password in the auth secret.
	PasswordKey string `yaml:"password_key" json:"-"`
	// Username is the direct registry username. If set, AuthSecretName is not required.
	Username string `yaml:"username" json:"-"`
	// Password is the direct registry password. If set, AuthSecretName is not required.
	Password string `yaml:"password" json:"-"`
}

// LoadManagerConfig returns the manager configuration.
func LoadManagerConfig() *ManagerConfig {
	path := os.Getenv("CONFIG_PATH")
	if path == "" {
		path = "/config/config.yaml"
	}

	cfg, err := loadManagerConfig(path)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to load config from %s: %v, using empty config\n", path, err)
		cfg = &ManagerConfig{}
	}
	if cfg.EgressAuthDefaultResolveTTL.Duration == 0 {
		cfg.EgressAuthDefaultResolveTTL = metav1.Duration{Duration: 5 * time.Minute}
	}
	for idx := range cfg.EgressAuthStaticAuth {
		if cfg.EgressAuthStaticAuth[idx].TTL.Duration == 0 {
			cfg.EgressAuthStaticAuth[idx].TTL = cfg.EgressAuthDefaultResolveTTL
		}
	}
	if cfg.CredentialStore.DefaultStorageKind == "" {
		cfg.CredentialStore.DefaultStorageKind = "encrypted_pg"
	}
	applyRootFSMaintenanceDefaults(cfg)
	applySandboxObservabilityProducerDefaults(cfg)
	applyClaimStartLimiterDefaults(cfg)
	return cfg
}

func applyClaimStartLimiterDefaults(cfg *ManagerConfig) {
	if cfg == nil {
		return
	}
	if cfg.RedisURL != "" && cfg.RedisTimeout.Duration == 0 {
		cfg.RedisTimeout = metav1.Duration{Duration: 100 * time.Millisecond}
	}
	if cfg.ClaimStartLimiter.PerSandboxNode <= 0 {
		cfg.ClaimStartLimiter.PerSandboxNode = 30
	}
	if cfg.ClaimStartLimiter.MaxLimit <= 0 {
		cfg.ClaimStartLimiter.MaxLimit = 80
	}
	if cfg.ClaimStartLimiter.LockTTL.Duration == 0 {
		cfg.ClaimStartLimiter.LockTTL = metav1.Duration{Duration: 5 * time.Second}
	}
	if cfg.ClaimStartLimiter.AcquireTimeout.Duration == 0 {
		cfg.ClaimStartLimiter.AcquireTimeout = metav1.Duration{Duration: 250 * time.Millisecond}
	}
}

func applySandboxObservabilityProducerDefaults(cfg *ManagerConfig) {
	if cfg == nil {
		return
	}
	if cfg.SandboxObservabilityIngestQueueSize == 0 {
		cfg.SandboxObservabilityIngestQueueSize = 1024
	}
	if cfg.SandboxObservabilityIngestBatchSize == 0 {
		cfg.SandboxObservabilityIngestBatchSize = 100
	}
	if cfg.SandboxObservabilityIngestFlushInterval.Duration == 0 {
		cfg.SandboxObservabilityIngestFlushInterval = metav1.Duration{Duration: time.Second}
	}
	if cfg.SandboxObservabilityIngestRequestTimeout.Duration == 0 {
		cfg.SandboxObservabilityIngestRequestTimeout = metav1.Duration{Duration: 2 * time.Second}
	}
	if cfg.SandboxObservabilityIngestMaxRetries == 0 {
		cfg.SandboxObservabilityIngestMaxRetries = 3
	}
	if cfg.SandboxObservabilityIngestRetryBackoff.Duration == 0 {
		cfg.SandboxObservabilityIngestRetryBackoff = metav1.Duration{Duration: 100 * time.Millisecond}
	}
	if cfg.SandboxObservabilityLogPollInterval.Duration == 0 {
		cfg.SandboxObservabilityLogPollInterval = metav1.Duration{Duration: 10 * time.Second}
	}
}

func applyRootFSMaintenanceDefaults(cfg *ManagerConfig) {
	if cfg == nil {
		return
	}
	if cfg.RootFSMaintenance.Interval.Duration == 0 {
		cfg.RootFSMaintenance.Interval = metav1.Duration{Duration: time.Minute}
	}
	if cfg.RootFSMaintenance.BatchSize <= 0 {
		cfg.RootFSMaintenance.BatchSize = 100
	}
	if cfg.RootFSMaintenance.MaxBatchesPerRun <= 0 {
		cfg.RootFSMaintenance.MaxBatchesPerRun = 10
	}
	if cfg.RootFSMaintenance.Workers <= 0 {
		cfg.RootFSMaintenance.Workers = 1
	}
	if cfg.RootFSMaintenance.ObjectDeleteClaimTTL.Duration == 0 {
		cfg.RootFSMaintenance.ObjectDeleteClaimTTL = metav1.Duration{Duration: 2 * time.Minute}
	}
	if cfg.RootFSMaintenance.ObjectDeleteBackoffBase.Duration == 0 {
		cfg.RootFSMaintenance.ObjectDeleteBackoffBase = metav1.Duration{Duration: 5 * time.Second}
	}
	if cfg.RootFSMaintenance.ObjectDeleteBackoffMax.Duration == 0 {
		cfg.RootFSMaintenance.ObjectDeleteBackoffMax = metav1.Duration{Duration: 10 * time.Minute}
	}
	if cfg.RootFSMaintenance.SquashMaxChainDepth <= 0 {
		cfg.RootFSMaintenance.SquashMaxChainDepth = 8
	}
	if cfg.RootFSMaintenance.SquashMaxChainBytes <= 0 {
		cfg.RootFSMaintenance.SquashMaxChainBytes = 512 * 1024 * 1024
	}
}

func loadManagerConfig(path string) (*ManagerConfig, error) {
	cfg := &ManagerConfig{}
	if path == "" {
		return cfg, nil
	}

	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("failed to read config file: %w", err)
	}

	// Expand environment variables
	data = []byte(os.ExpandEnv(string(data)))

	if err := yaml.Unmarshal(data, cfg); err != nil {
		return nil, fmt.Errorf("failed to unmarshal config: %w", err)
	}

	return cfg, nil
}
