{{/*
Expand the name of the chart.
*/}}
{{- define "shenron.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a fully qualified app name.
*/}}
{{- define "shenron.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := include "shenron.name" . -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Chart metadata label.
*/}}
{{- define "shenron.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Common labels.
*/}}
{{- define "shenron.labels" -}}
helm.sh/chart: {{ include "shenron.chart" . }}
app.kubernetes.io/name: {{ include "shenron.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end -}}

{{/*
Labels used to select pods.
*/}}
{{- define "shenron.selectorLabels" -}}
app.kubernetes.io/name: {{ include "shenron.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}

{{/*
Sanitize an arbitrary model key into a DNS-safe slug.
*/}}
{{- define "shenron.modelSlug" -}}
{{- $name := printf "%v" . -}}
{{- $slug := trimAll "-" (regexReplaceAll "[^a-z0-9]+" (lower $name) "-") -}}
{{- if eq $slug "" -}}
model
{{- else -}}
{{- $slug -}}
{{- end -}}
{{- end -}}

{{/*
Stable short hash for model keys.
*/}}
{{- define "shenron.modelHash" -}}
{{- sha256sum (printf "%v" .) | trunc 8 -}}
{{- end -}}

{{/*
Stable model id for labels.
*/}}
{{- define "shenron.modelID" -}}
{{- $slug := include "shenron.modelSlug" . -}}
{{- $hash := include "shenron.modelHash" . -}}
{{- $maxSlugLen := int (sub 63 (add 1 (len $hash))) -}}
{{- $trimmedSlug := trunc $maxSlugLen $slug | trimSuffix "-" -}}
{{- printf "%s-%s" $trimmedSlug $hash | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Resource name per model, unique and stable.
*/}}
{{- define "shenron.modelResourceName" -}}
{{- $root := index . "root" -}}
{{- $modelName := index . "modelName" -}}
{{- $fullname := include "shenron.fullname" $root -}}
{{- $modelID := include "shenron.modelID" $modelName -}}
{{- $maxPrefixLen := int (sub 63 (add 1 (len $modelID))) -}}
{{- $trimmedPrefix := trunc $maxPrefixLen $fullname | trimSuffix "-" -}}
{{- printf "%s-%s" $trimmedPrefix $modelID | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Resource name for onwards Deployment/Service.
*/}}
{{- define "shenron.onwardsName" -}}
{{- printf "%s-onwards" (include "shenron.fullname" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Resource name for onwards config ConfigMap.
*/}}
{{- define "shenron.onwardsConfigName" -}}
{{- printf "%s-config" (include "shenron.onwardsName" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Validate top-level models map.
*/}}
{{- define "shenron.validateModelsMap" -}}
{{- if not (kindIs "map" .Values.models) -}}
{{- fail "values.models must be a map keyed by model name" -}}
{{- end -}}
{{- end -}}

{{/*
Resolve and validate the shared model port.
*/}}
{{- define "shenron.sharedPort" -}}
{{- if not (hasKey .Values "port") -}}
{{- fail "values.port is required and is shared by all models" -}}
{{- end -}}
{{- $port := int .Values.port -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate onwards enabled flag.
*/}}
{{- define "shenron.onwardsEnabled" -}}
{{- $onwards := .Values.onwards | default dict -}}
{{- $enabled := true -}}
{{- if hasKey $onwards "enabled" -}}
{{- $enabled = (get $onwards "enabled") -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.onwards.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resolve and validate onwards listen port.
*/}}
{{- define "shenron.onwardsPort" -}}
{{- $onwards := .Values.onwards | default dict -}}
{{- $port := 3000 -}}
{{- if hasKey $onwards "port" -}}
{{- $port = int (get $onwards "port") -}}
{{- end -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.onwards.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate onwards service port.
*/}}
{{- define "shenron.onwardsServicePort" -}}
{{- $onwards := .Values.onwards | default dict -}}
{{- $service := get $onwards "service" | default dict -}}
{{- $port := int (include "shenron.onwardsPort" .) -}}
{{- if hasKey $service "port" -}}
{{- $port = int (get $service "port") -}}
{{- end -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.onwards.service.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate onwards service nodePort.
*/}}
{{- define "shenron.onwardsServiceNodePort" -}}
{{- $onwards := .Values.onwards | default dict -}}
{{- $service := get $onwards "service" | default dict -}}
{{- $nodePort := 0 -}}
{{- if hasKey $service "nodePort" -}}
{{- $nodePort = int (get $service "nodePort") -}}
{{- end -}}
{{- if ne $nodePort 0 -}}
{{- if or (lt $nodePort 30000) (gt $nodePort 32767) -}}
{{- fail "values.onwards.service.nodePort must be between 30000 and 32767" -}}
{{- end -}}
{{- end -}}
{{- $nodePort -}}
{{- end -}}

{{/*
Resolve and validate onwards API key secret name.
*/}}
{{- define "shenron.onwardsApiSecretName" -}}
{{- $onwards := .Values.onwards | default dict -}}
{{- $secret := get $onwards "systemApiKeySecret" | default dict -}}
{{- $name := "system-api-key" -}}
{{- if hasKey $secret "name" -}}
{{- $name = printf "%v" (get $secret "name") -}}
{{- end -}}
{{- if eq (trim $name) "" -}}
{{- fail "values.onwards.systemApiKeySecret.name must not be empty" -}}
{{- end -}}
{{- if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" $name) -}}
{{- fail "values.onwards.systemApiKeySecret.name must be a lowercase RFC1123 subdomain (e.g. system-api-key)" -}}
{{- end -}}
{{- $name -}}
{{- end -}}

{{/*
Resolve and validate onwards API key secret key.
*/}}
{{- define "shenron.onwardsApiSecretKey" -}}
{{- $onwards := .Values.onwards | default dict -}}
{{- $secret := get $onwards "systemApiKeySecret" | default dict -}}
{{- $key := "SYSTEM_API_KEY" -}}
{{- if hasKey $secret "key" -}}
{{- $key = printf "%v" (get $secret "key") -}}
{{- end -}}
{{- if eq (trim $key) "" -}}
{{- fail "values.onwards.systemApiKeySecret.key must not be empty" -}}
{{- end -}}
{{- $key -}}
{{- end -}}

{{/*
Validate onwards settings.
*/}}
{{- define "shenron.validateOnwards" -}}
{{- $_ := include "shenron.onwardsEnabled" . -}}
{{- $_ := include "shenron.onwardsPort" . -}}
{{- $_ := include "shenron.onwardsServicePort" . -}}
{{- $_ := include "shenron.onwardsServiceNodePort" . -}}
{{- $_ := include "shenron.onwardsApiSecretName" . -}}
{{- $_ := include "shenron.onwardsApiSecretKey" . -}}
{{- end -}}

{{/*
Resource name for Caddy Deployment/Service/ConfigMap.
*/}}
{{- define "shenron.caddyName" -}}
{{- printf "%s-caddy" (include "shenron.fullname" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Resolve and validate Caddy enabled flag.
*/}}
{{- define "shenron.caddyEnabled" -}}
{{- $caddy := .Values.caddy | default dict -}}
{{- $enabled := true -}}
{{- if hasKey $caddy "enabled" -}}
{{- $enabled = (get $caddy "enabled") -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.caddy.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resolve Caddy FQDN. Returns empty string when not set.
When non-empty Caddy serves HTTPS with auto Let's Encrypt.
When empty Caddy serves HTTP-only on :80.
*/}}
{{- define "shenron.caddyFqdn" -}}
{{- $caddy := .Values.caddy | default dict -}}
{{- $fqdn := "" -}}
{{- if hasKey $caddy "fqdn" -}}
{{- $fqdn = printf "%v" (get $caddy "fqdn") -}}
{{- end -}}
{{- trim $fqdn -}}
{{- end -}}

{{/*
Generate the Caddyfile content for the ConfigMap.

Routing (all traffic enters via Caddy on 80/443):
  /llm/*     → onwards         (handle_path strips /llm, matches /llm and /llm/*)
  /replica/* → replica-manager (handle_path strips /replica, matches /replica and /replica/*)
  /metrics/* → prometheus      (handle_path strips /metrics, matches /metrics and /metrics/*)

Additional routes can be added via values.caddy.extraRoutes:
  [{path: "/scale/*", service: "my-scaler", port: 8080}]
*/}}
{{- define "shenron.caddyfile" -}}
{{- $onwardsName := include "shenron.onwardsName" . -}}
{{- $onwardsPort := include "shenron.onwardsServicePort" . -}}
{{- $fqdn := include "shenron.caddyFqdn" . -}}
{{- $host := ternary $fqdn ":80" (ne $fqdn "") }}
{{ $host }} {
    handle_path /llm/* {
        reverse_proxy {{ $onwardsName }}:{{ $onwardsPort }}
    }
{{- if eq (include "shenron.replicaManagerEnabled" .) "true" }}
    handle_path /replica/* {
        reverse_proxy {{ include "shenron.replicaManagerName" . }}:{{ include "shenron.replicaManagerServicePort" . }}
    }
{{- end }}
{{- $prom := .Values.prometheus | default dict }}
{{- $promEnabled := false }}
{{- if hasKey $prom "enabled" }}
{{- $promEnabled = get $prom "enabled" }}
{{- end }}
{{- if $promEnabled }}
{{- $promPort := 9090 }}
{{- if hasKey $prom "port" }}
{{- $promPort = int (get $prom "port") }}
{{- end }}
    handle_path /metrics/* {
        reverse_proxy {{ include "shenron.fullname" . }}-prometheus:{{ $promPort }}
    }
{{- end }}
{{- range .Values.caddy.extraRoutes }}
    handle {{ .path }} {
        reverse_proxy {{ .service }}:{{ .port }}
    }
{{- end }}
}
{{- end -}}

{{/*
Resolve and validate Hugging Face cache enabled flag.
*/}}
{{- define "shenron.hfCacheEnabled" -}}
{{- $cache := .Values.huggingfaceCache | default dict -}}
{{- $enabled := true -}}
{{- if hasKey $cache "enabled" -}}
{{- $enabled = (get $cache "enabled") -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.huggingfaceCache.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resolve and validate Hugging Face cache host path.
*/}}
{{- define "shenron.hfCacheHostPath" -}}
{{- $cache := .Values.huggingfaceCache | default dict -}}
{{- $path := "/root/.cache/huggingface" -}}
{{- if hasKey $cache "hostPath" -}}
{{- $path = trim (printf "%v" (get $cache "hostPath")) -}}
{{- end -}}
{{- if eq $path "" -}}
{{- fail "values.huggingfaceCache.hostPath must not be empty" -}}
{{- end -}}
{{- if not (hasPrefix "/" $path) -}}
{{- fail "values.huggingfaceCache.hostPath must be an absolute path (do not use ~)" -}}
{{- end -}}
{{- $path -}}
{{- end -}}

{{/*
Resolve and validate Hugging Face cache mount path.
*/}}
{{- define "shenron.hfCacheMountPath" -}}
{{- $cache := .Values.huggingfaceCache | default dict -}}
{{- $path := "/root/.cache/huggingface" -}}
{{- if hasKey $cache "mountPath" -}}
{{- $path = trim (printf "%v" (get $cache "mountPath")) -}}
{{- end -}}
{{- if eq $path "" -}}
{{- fail "values.huggingfaceCache.mountPath must not be empty" -}}
{{- end -}}
{{- if not (hasPrefix "/" $path) -}}
{{- fail "values.huggingfaceCache.mountPath must be an absolute path" -}}
{{- end -}}
{{- $path -}}
{{- end -}}

{{/*
Resolve and validate Hugging Face cache hostPath type.
*/}}
{{- define "shenron.hfCacheHostPathType" -}}
{{- $cache := .Values.huggingfaceCache | default dict -}}
{{- $t := "DirectoryOrCreate" -}}
{{- if hasKey $cache "hostPathType" -}}
{{- $t = trim (printf "%v" (get $cache "hostPathType")) -}}
{{- end -}}
{{- if not (or (eq $t "DirectoryOrCreate") (eq $t "Directory") (eq $t "FileOrCreate") (eq $t "File") (eq $t "Socket") (eq $t "CharDevice") (eq $t "BlockDevice")) -}}
{{- fail "values.huggingfaceCache.hostPathType must be a valid Kubernetes hostPath type" -}}
{{- end -}}
{{- $t -}}
{{- end -}}

{{/*
Validate Hugging Face cache settings.
*/}}
{{- define "shenron.validateHuggingfaceCache" -}}
{{- $_ := include "shenron.hfCacheEnabled" . -}}
{{- $_ := include "shenron.hfCacheHostPath" . -}}
{{- $_ := include "shenron.hfCacheMountPath" . -}}
{{- $_ := include "shenron.hfCacheHostPathType" . -}}
{{- end -}}

{{/*
Validate per-model required fields and types.
*/}}
{{- define "shenron.validateModel" -}}
{{- $modelName := index . "modelName" -}}
{{- $model := index . "model" -}}
{{- if not (kindIs "map" $model) -}}
{{- fail (printf "models.%s must be an object" $modelName) -}}
{{- end -}}
{{- if not (hasKey $model "replicas") -}}
{{- fail (printf "models.%s.replicas is required" $modelName) -}}
{{- end -}}
{{- if not (hasKey $model "command") -}}
{{- fail (printf "models.%s.command is required" $modelName) -}}
{{- end -}}
{{- $replicas := int (get $model "replicas") -}}
{{- if lt $replicas 0 -}}
{{- fail (printf "models.%s.replicas must be >= 0" $modelName) -}}
{{- end -}}
{{- $command := get $model "command" -}}
{{- if not (kindIs "slice" $command) -}}
{{- fail (printf "models.%s.command must be a list of command arguments" $modelName) -}}
{{- end -}}
{{- if eq (len $command) 0 -}}
{{- fail (printf "models.%s.command must not be empty" $modelName) -}}
{{- end -}}
{{- if has "--port" $command -}}
{{- fail (printf "models.%s.command must not include --port; use top-level values.port" $modelName) -}}
{{- end -}}
{{- if hasKey $model "num_gpus" -}}
{{- $numGpusRaw := printf "%v" (get $model "num_gpus") -}}
{{- if not (regexMatch "^[0-9]+$" $numGpusRaw) -}}
{{- fail (printf "models.%s.num_gpus must be a non-negative integer" $modelName) -}}
{{- end -}}
{{- end -}}
{{- if hasKey $model "env" -}}
{{- $env := get $model "env" -}}
{{- if not (kindIs "slice" $env) -}}
{{- fail (printf "models.%s.env must be a list of {name, value} objects" $modelName) -}}
{{- end -}}
{{- range $idx, $item := $env -}}
{{- if not (kindIs "map" $item) -}}
{{- fail (printf "models.%s.env[%d] must be an object with name and value" $modelName $idx) -}}
{{- end -}}
{{- if not (hasKey $item "name") -}}
{{- fail (printf "models.%s.env[%d].name is required" $modelName $idx) -}}
{{- end -}}
{{- if not (hasKey $item "value") -}}
{{- fail (printf "models.%s.env[%d].value is required" $modelName $idx) -}}
{{- end -}}
{{- if eq (printf "%v" (get $item "name")) "" -}}
{{- fail (printf "models.%s.env[%d].name must not be empty" $modelName $idx) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- if hasKey $model "image" -}}
{{- $image := get $model "image" -}}
{{- if not (kindIs "map" $image) -}}
{{- fail (printf "models.%s.image must be an object" $modelName) -}}
{{- end -}}
{{- end -}}
{{- if hasKey $model "shm" -}}
{{- $shm := get $model "shm" -}}
{{- if not (kindIs "map" $shm) -}}
{{- fail (printf "models.%s.shm must be an object" $modelName) -}}
{{- end -}}
{{- if hasKey $shm "enabled" -}}
{{- if not (kindIs "bool" (get $shm "enabled")) -}}
{{- fail (printf "models.%s.shm.enabled must be a boolean" $modelName) -}}
{{- end -}}
{{- end -}}
{{- if hasKey $shm "sizeLimit" -}}
{{- $sizeLimit := trim (printf "%v" (get $shm "sizeLimit")) -}}
{{- if eq $sizeLimit "" -}}
{{- fail (printf "models.%s.shm.sizeLimit must not be empty when set" $modelName) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- if hasKey $model "resources" -}}
{{- $resources := get $model "resources" -}}
{{- if not (kindIs "map" $resources) -}}
{{- fail (printf "models.%s.resources must be an object" $modelName) -}}
{{- end -}}
{{- if hasKey $resources "limits" -}}
{{- $limits := get $resources "limits" -}}
{{- if not (kindIs "map" $limits) -}}
{{- fail (printf "models.%s.resources.limits must be an object" $modelName) -}}
{{- end -}}
{{- end -}}
{{- if hasKey $resources "requests" -}}
{{- $requests := get $resources "requests" -}}
{{- if not (kindIs "map" $requests) -}}
{{- fail (printf "models.%s.resources.requests must be an object" $modelName) -}}
{{- end -}}
{{- end -}}
{{- if hasKey $model "num_gpus" -}}
{{- $limits := get $resources "limits" | default dict -}}
{{- if and (kindIs "map" $limits) (hasKey $limits "nvidia.com/gpu") -}}
{{- fail (printf "models.%s.resources.limits.nvidia.com/gpu must not be set when models.%s.num_gpus is set" $modelName $modelName) -}}
{{- end -}}
{{- $requests := get $resources "requests" | default dict -}}
{{- if and (kindIs "map" $requests) (hasKey $requests "nvidia.com/gpu") -}}
{{- fail (printf "models.%s.resources.requests.nvidia.com/gpu must not be set when models.%s.num_gpus is set" $modelName $modelName) -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{- end -}}

{{/*
Resolve and validate cluster.total_gpus.
*/}}
{{- define "shenron.clusterTotalGpus" -}}
{{- $cluster := .Values.cluster | default dict -}}
{{- if not (kindIs "map" $cluster) -}}
{{- fail "values.cluster must be an object" -}}
{{- end -}}
{{- if not (hasKey $cluster "total_gpus") -}}
{{- fail "values.cluster.total_gpus is required" -}}
{{- end -}}
{{- $totalRaw := printf "%v" (get $cluster "total_gpus") -}}
{{- if not (regexMatch "^[0-9]+$" $totalRaw) -}}
{{- fail "values.cluster.total_gpus must be a non-negative integer" -}}
{{- end -}}
{{- int $totalRaw -}}
{{- end -}}

{{/*
Validate cluster values.
*/}}
{{- define "shenron.validateCluster" -}}
{{- $_ := include "shenron.clusterTotalGpus" . -}}
{{- end -}}

{{/*
Resolve and validate router.enabled flag.
*/}}
{{- define "shenron.routerEnabled" -}}
{{- $router := .Values.router | default dict -}}
{{- if not (kindIs "map" $router) -}}
{{- fail "values.router must be an object" -}}
{{- end -}}
{{- $enabled := true -}}
{{- if hasKey $router "enabled" -}}
{{- $enabled = get $router "enabled" -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.router.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resolve and validate router listen port.
*/}}
{{- define "shenron.routerPort" -}}
{{- $router := .Values.router | default dict -}}
{{- $port := 3001 -}}
{{- if hasKey $router "port" -}}
{{- $port = int (get $router "port") -}}
{{- end -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.router.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate router policy.
*/}}
{{- define "shenron.routerPolicy" -}}
{{- $router := .Values.router | default dict -}}
{{- $policy := "cache_aware" -}}
{{- if hasKey $router "policy" -}}
{{- $policy = trim (printf "%v" (get $router "policy")) -}}
{{- end -}}
{{- if eq $policy "" -}}
{{- fail "values.router.policy must not be empty" -}}
{{- end -}}
{{- $policy -}}
{{- end -}}

{{/*
Resolve and validate router service discovery enabled flag.
*/}}
{{- define "shenron.routerServiceDiscoveryEnabled" -}}
{{- $router := .Values.router | default dict -}}
{{- $svcDiscovery := get $router "serviceDiscovery" | default dict -}}
{{- if and (hasKey $router "serviceDiscovery") (not (kindIs "map" $svcDiscovery)) -}}
{{- fail "values.router.serviceDiscovery must be an object" -}}
{{- end -}}
{{- $enabled := true -}}
{{- if hasKey $svcDiscovery "enabled" -}}
{{- $enabled = get $svcDiscovery "enabled" -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.router.serviceDiscovery.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resource name for per-model router Deployment/Service.
*/}}
{{- define "shenron.routerResourceName" -}}
{{- $root := index . "root" -}}
{{- $modelName := index . "modelName" -}}
{{- $fullname := include "shenron.fullname" $root -}}
{{- $hash := include "shenron.modelHash" $modelName -}}
{{- $prefix := printf "%s-router" $fullname -}}
{{- $maxPrefixLen := int (sub 63 (add 1 (len $hash))) -}}
{{- $trimmedPrefix := trunc $maxPrefixLen $prefix | trimSuffix "-" -}}
{{- printf "%s-%s" $trimmedPrefix $hash | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Service account name for all router pods.
*/}}
{{- define "shenron.routerServiceAccountName" -}}
{{- printf "%s-router" (include "shenron.fullname" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Validate router settings.
*/}}
{{- define "shenron.validateRouter" -}}
{{- $_ := include "shenron.routerEnabled" . -}}
{{- $_ := include "shenron.routerPort" . -}}
{{- $_ := include "shenron.routerPolicy" . -}}
{{- $_ := include "shenron.routerServiceDiscoveryEnabled" . -}}
{{- end -}}

{{/*
Resource name for replica manager Deployment/Service.
*/}}
{{- define "shenron.replicaManagerName" -}}
{{- printf "%s-replica-manager" (include "shenron.fullname" .) | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Service account name for replica manager.
*/}}
{{- define "shenron.replicaManagerServiceAccountName" -}}
{{- include "shenron.replicaManagerName" . -}}
{{- end -}}

{{/*
Resolve and validate replica manager enabled flag.
*/}}
{{- define "shenron.replicaManagerEnabled" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- if not (kindIs "map" $manager) -}}
{{- fail "values.replicaManager must be an object" -}}
{{- end -}}
{{- $enabled := true -}}
{{- if hasKey $manager "enabled" -}}
{{- $enabled = get $manager "enabled" -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.replicaManager.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resolve and validate replica manager Deployment replicas.
*/}}
{{- define "shenron.replicaManagerReplicas" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $replicas := 1 -}}
{{- if hasKey $manager "replicas" -}}
{{- $replicas = int (get $manager "replicas") -}}
{{- end -}}
{{- if lt $replicas 0 -}}
{{- fail "values.replicaManager.replicas must be >= 0" -}}
{{- end -}}
{{- $replicas -}}
{{- end -}}

{{/*
Resolve and validate replica manager container listen port.
*/}}
{{- define "shenron.replicaManagerPort" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $port := 8081 -}}
{{- if hasKey $manager "port" -}}
{{- $port = int (get $manager "port") -}}
{{- end -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.replicaManager.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate replica manager service port.
*/}}
{{- define "shenron.replicaManagerServicePort" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $service := get $manager "service" | default dict -}}
{{- $port := int (include "shenron.replicaManagerPort" .) -}}
{{- if hasKey $service "port" -}}
{{- $port = int (get $service "port") -}}
{{- end -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.replicaManager.service.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate replica manager auth secret name.
*/}}
{{- define "shenron.replicaManagerTokenSecretName" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $auth := get $manager "auth" | default dict -}}
{{- if and (hasKey $manager "auth") (not (kindIs "map" $auth)) -}}
{{- fail "values.replicaManager.auth must be an object" -}}
{{- end -}}
{{- $tokenSecret := get $auth "tokenSecret" | default dict -}}
{{- if and (hasKey $auth "tokenSecret") (not (kindIs "map" $tokenSecret)) -}}
{{- fail "values.replicaManager.auth.tokenSecret must be an object" -}}
{{- end -}}
{{- $name := "replica-manager-auth" -}}
{{- if hasKey $tokenSecret "name" -}}
{{- $name = trim (printf "%v" (get $tokenSecret "name")) -}}
{{- end -}}
{{- if eq $name "" -}}
{{- fail "values.replicaManager.auth.tokenSecret.name must not be empty" -}}
{{- end -}}
{{- if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" $name) -}}
{{- fail "values.replicaManager.auth.tokenSecret.name must be a lowercase RFC1123 subdomain" -}}
{{- end -}}
{{- $name -}}
{{- end -}}

{{/*
Resolve and validate replica manager auth secret key.
*/}}
{{- define "shenron.replicaManagerTokenSecretKey" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $auth := get $manager "auth" | default dict -}}
{{- $tokenSecret := get $auth "tokenSecret" | default dict -}}
{{- $key := "token" -}}
{{- if hasKey $tokenSecret "key" -}}
{{- $key = trim (printf "%v" (get $tokenSecret "key")) -}}
{{- end -}}
{{- if eq $key "" -}}
{{- fail "values.replicaManager.auth.tokenSecret.key must not be empty" -}}
{{- end -}}
{{- $key -}}
{{- end -}}

{{/*
Resolve and validate replica manager Helm release name.
*/}}
{{- define "shenron.replicaManagerHelmReleaseName" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $helm := get $manager "helm" | default dict -}}
{{- if and (hasKey $manager "helm") (not (kindIs "map" $helm)) -}}
{{- fail "values.replicaManager.helm must be an object" -}}
{{- end -}}
{{- $releaseName := .Release.Name -}}
{{- if hasKey $helm "releaseName" -}}
{{- $candidate := trim (printf "%v" (get $helm "releaseName")) -}}
{{- if ne $candidate "" -}}
{{- $releaseName = $candidate -}}
{{- end -}}
{{- end -}}
{{- if eq $releaseName "" -}}
{{- fail "values.replicaManager.helm.releaseName must not be empty" -}}
{{- end -}}
{{- $releaseName -}}
{{- end -}}

{{/*
Resolve and validate replica manager Helm namespace.
*/}}
{{- define "shenron.replicaManagerHelmNamespace" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $helm := get $manager "helm" | default dict -}}
{{- $namespace := .Release.Namespace -}}
{{- if hasKey $helm "namespace" -}}
{{- $candidate := trim (printf "%v" (get $helm "namespace")) -}}
{{- if ne $candidate "" -}}
{{- $namespace = $candidate -}}
{{- end -}}
{{- end -}}
{{- if eq $namespace "" -}}
{{- fail "values.replicaManager.helm.namespace must not be empty" -}}
{{- end -}}
{{- $namespace -}}
{{- end -}}

{{/*
Resolve and validate replica manager chart path.
*/}}
{{- define "shenron.replicaManagerHelmChartPath" -}}
{{- $manager := .Values.replicaManager | default dict -}}
{{- $helm := get $manager "helm" | default dict -}}
{{- $chartPath := "/opt/shenron/helm" -}}
{{- if hasKey $helm "chartPath" -}}
{{- $chartPath = trim (printf "%v" (get $helm "chartPath")) -}}
{{- end -}}
{{- if eq $chartPath "" -}}
{{- fail "values.replicaManager.helm.chartPath must not be empty" -}}
{{- end -}}
{{- $chartPath -}}
{{- end -}}

{{/*
Validate replica manager settings.
*/}}
{{- define "shenron.validateReplicaManager" -}}
{{- $_ := include "shenron.replicaManagerEnabled" . -}}
{{- $_ := include "shenron.replicaManagerReplicas" . -}}
{{- $_ := include "shenron.replicaManagerPort" . -}}
{{- $_ := include "shenron.replicaManagerServicePort" . -}}
{{- $_ := include "shenron.replicaManagerTokenSecretName" . -}}
{{- $_ := include "shenron.replicaManagerTokenSecretKey" . -}}
{{- $_ := include "shenron.replicaManagerHelmReleaseName" . -}}
{{- $_ := include "shenron.replicaManagerHelmNamespace" . -}}
{{- $_ := include "shenron.replicaManagerHelmChartPath" . -}}
{{- end -}}

{{/*
Resolve and validate scouter reporter enabled flag.
*/}}
{{- define "shenron.scouterReporterEnabled" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- if not (kindIs "map" $reporter) -}}
{{- fail "values.scouterReporter must be an object" -}}
{{- end -}}
{{- $enabled := false -}}
{{- if hasKey $reporter "enabled" -}}
{{- $enabled = get $reporter "enabled" -}}
{{- end -}}
{{- if not (kindIs "bool" $enabled) -}}
{{- fail "values.scouterReporter.enabled must be a boolean" -}}
{{- end -}}
{{- $enabled -}}
{{- end -}}

{{/*
Resolve and validate scouter reporter interval.
*/}}
{{- define "shenron.scouterReporterInterval" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $interval := 10 -}}
{{- if hasKey $reporter "reporterInterval" -}}
{{- $interval = int (get $reporter "reporterInterval") -}}
{{- end -}}
{{- if lt $interval 1 -}}
{{- fail "values.scouterReporter.reporterInterval must be >= 1" -}}
{{- end -}}
{{- $interval -}}
{{- end -}}

{{/*
Resolve and validate scouter collector URL scheme.
*/}}
{{- define "shenron.scouterCollectorScheme" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $collector := get $reporter "collector" | default dict -}}
{{- if and (hasKey $reporter "collector") (not (kindIs "map" $collector)) -}}
{{- fail "values.scouterReporter.collector must be an object" -}}
{{- end -}}
{{- $scheme := "http" -}}
{{- if hasKey $collector "scheme" -}}
{{- $scheme = lower (trim (printf "%v" (get $collector "scheme"))) -}}
{{- end -}}
{{- if not (or (eq $scheme "http") (eq $scheme "https")) -}}
{{- fail "values.scouterReporter.collector.scheme must be http or https" -}}
{{- end -}}
{{- $scheme -}}
{{- end -}}

{{/*
Resolve and validate scouter collector port.
*/}}
{{- define "shenron.scouterCollectorPort" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $collector := get $reporter "collector" | default dict -}}
{{- $port := 4321 -}}
{{- if hasKey $collector "port" -}}
{{- $port = int (get $collector "port") -}}
{{- end -}}
{{- if or (lt $port 1) (gt $port 65535) -}}
{{- fail "values.scouterReporter.collector.port must be between 1 and 65535" -}}
{{- end -}}
{{- $port -}}
{{- end -}}

{{/*
Resolve and validate scouter collector instance secret name.
*/}}
{{- define "shenron.scouterCollectorInstanceSecretName" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $collector := get $reporter "collector" | default dict -}}
{{- $instanceSecret := get $collector "instanceSecret" | default dict -}}
{{- if and (hasKey $collector "instanceSecret") (not (kindIs "map" $instanceSecret)) -}}
{{- fail "values.scouterReporter.collector.instanceSecret must be an object" -}}
{{- end -}}
{{- $name := "scouter-reporter" -}}
{{- if hasKey $instanceSecret "name" -}}
{{- $name = trim (printf "%v" (get $instanceSecret "name")) -}}
{{- end -}}
{{- if eq $name "" -}}
{{- fail "values.scouterReporter.collector.instanceSecret.name must not be empty" -}}
{{- end -}}
{{- if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" $name) -}}
{{- fail "values.scouterReporter.collector.instanceSecret.name must be a lowercase RFC1123 subdomain" -}}
{{- end -}}
{{- $name -}}
{{- end -}}

{{/*
Resolve and validate scouter collector instance secret key.
*/}}
{{- define "shenron.scouterCollectorInstanceSecretKey" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $collector := get $reporter "collector" | default dict -}}
{{- $instanceSecret := get $collector "instanceSecret" | default dict -}}
{{- $key := "collector-instance" -}}
{{- if hasKey $instanceSecret "key" -}}
{{- $key = trim (printf "%v" (get $instanceSecret "key")) -}}
{{- end -}}
{{- if eq $key "" -}}
{{- fail "values.scouterReporter.collector.instanceSecret.key must not be empty" -}}
{{- end -}}
{{- $key -}}
{{- end -}}

{{/*
Resolve and validate scouter ingest API key secret name.
*/}}
{{- define "shenron.scouterIngestApiKeySecretName" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $collector := get $reporter "collector" | default dict -}}
{{- $apiKeySecret := get $collector "apiKeySecret" | default dict -}}
{{- if and (hasKey $collector "apiKeySecret") (not (kindIs "map" $apiKeySecret)) -}}
{{- fail "values.scouterReporter.collector.apiKeySecret must be an object" -}}
{{- end -}}
{{- $name := "scouter-reporter" -}}
{{- if hasKey $apiKeySecret "name" -}}
{{- $name = trim (printf "%v" (get $apiKeySecret "name")) -}}
{{- end -}}
{{- if eq $name "" -}}
{{- fail "values.scouterReporter.collector.apiKeySecret.name must not be empty" -}}
{{- end -}}
{{- if not (regexMatch "^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" $name) -}}
{{- fail "values.scouterReporter.collector.apiKeySecret.name must be a lowercase RFC1123 subdomain" -}}
{{- end -}}
{{- $name -}}
{{- end -}}

{{/*
Resolve and validate scouter ingest API key secret key.
*/}}
{{- define "shenron.scouterIngestApiKeySecretKey" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $collector := get $reporter "collector" | default dict -}}
{{- $apiKeySecret := get $collector "apiKeySecret" | default dict -}}
{{- $key := "ingest-api-key" -}}
{{- if hasKey $apiKeySecret "key" -}}
{{- $key = trim (printf "%v" (get $apiKeySecret "key")) -}}
{{- end -}}
{{- if eq $key "" -}}
{{- fail "values.scouterReporter.collector.apiKeySecret.key must not be empty" -}}
{{- end -}}
{{- $key -}}
{{- end -}}

{{/*
Resolve and validate scouter reporter prometheus URL.
*/}}
{{- define "shenron.scouterReporterPrometheusURL" -}}
{{- $reporter := .Values.scouterReporter | default dict -}}
{{- $promCfg := get $reporter "prometheus" | default dict -}}
{{- if and (hasKey $reporter "prometheus") (not (kindIs "map" $promCfg)) -}}
{{- fail "values.scouterReporter.prometheus must be an object" -}}
{{- end -}}
{{- $url := "" -}}
{{- if hasKey $promCfg "url" -}}
{{- $url = trim (printf "%v" (get $promCfg "url")) -}}
{{- end -}}
{{- if eq $url "" -}}
{{- $prom := .Values.prometheus | default dict -}}
{{- $promEnabled := false -}}
{{- if hasKey $prom "enabled" -}}
{{- $promEnabled = get $prom "enabled" -}}
{{- end -}}
{{- if and $promEnabled (not (kindIs "bool" $promEnabled)) -}}
{{- fail "values.prometheus.enabled must be a boolean" -}}
{{- end -}}
{{- if not $promEnabled -}}
{{- fail "values.scouterReporter.prometheus.url must be set when values.prometheus.enabled is false" -}}
{{- end -}}
{{- $promPort := 9090 -}}
{{- if hasKey $prom "port" -}}
{{- $promPort = int (get $prom "port") -}}
{{- end -}}
{{- if or (lt $promPort 1) (gt $promPort 65535) -}}
{{- fail "values.prometheus.port must be between 1 and 65535" -}}
{{- end -}}
{{- $url = printf "http://%s-prometheus:%d" (include "shenron.fullname" .) $promPort -}}
{{- end -}}
{{- $url -}}
{{- end -}}

{{/*
Resource name for per-model scouter reporter deployment.
*/}}
{{- define "shenron.scouterReporterResourceName" -}}
{{- $root := index . "root" -}}
{{- $modelName := index . "modelName" -}}
{{- $fullname := include "shenron.fullname" $root -}}
{{- $hash := include "shenron.modelHash" $modelName -}}
{{- $prefix := printf "%s-scouter" $fullname -}}
{{- $maxPrefixLen := int (sub 63 (add 1 (len $hash))) -}}
{{- $trimmedPrefix := trunc $maxPrefixLen $prefix | trimSuffix "-" -}}
{{- printf "%s-%s" $trimmedPrefix $hash | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Validate scouter reporter settings.
*/}}
{{- define "shenron.validateScouterReporter" -}}
{{- $_ := include "shenron.scouterReporterEnabled" . -}}
{{- $_ := include "shenron.scouterReporterInterval" . -}}
{{- $_ := include "shenron.scouterCollectorScheme" . -}}
{{- $_ := include "shenron.scouterCollectorPort" . -}}
{{- $_ := include "shenron.scouterCollectorInstanceSecretName" . -}}
{{- $_ := include "shenron.scouterCollectorInstanceSecretKey" . -}}
{{- $_ := include "shenron.scouterIngestApiKeySecretName" . -}}
{{- $_ := include "shenron.scouterIngestApiKeySecretKey" . -}}
{{- if eq (include "shenron.scouterReporterEnabled" .) "true" -}}
{{- $_ := include "shenron.scouterReporterPrometheusURL" . -}}
{{- end -}}
{{- end -}}
