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

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "archestra-platform.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "archestra-platform.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "archestra-platform.labels" -}}
helm.sh/chart: {{ include "archestra-platform.chart" . }}
{{ include "archestra-platform.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: archestra
{{- end }}

{{/*
Selector labels
*/}}
{{- define "archestra-platform.selectorLabels" -}}
app.kubernetes.io/name: {{ include "archestra-platform.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Environment variables for the Archestra Platform container
*/}}
{{- define "archestra-platform.env" -}}
{{/*
List of sensitive environment variables that should be stored in the Secret
and referenced via secretKeyRef instead of being exposed as plaintext in Pod specs.
This must match the list in secret.yaml.
Additionally, any env var matching ARCHESTRA_CHAT_*_API_KEY is treated as sensitive.
*/}}
{{- $sensitiveEnvVars := list
  "ARCHESTRA_AUTH_SECRET"
  "ARCHESTRA_AUTH_ADMIN_PASSWORD"
  "ARCHESTRA_OTEL_EXPORTER_OTLP_AUTH_PASSWORD"
  "ARCHESTRA_OTEL_EXPORTER_OTLP_AUTH_BEARER"
  "ARCHESTRA_METRICS_SECRET"
  "ARCHESTRA_HASHICORP_VAULT_TOKEN"
}}
{{- if eq (toString .Values.postgresql.external_database_url) "from_vault" }}
{{/* Database URL provided by vault-secrets init container — no env var generated */}}
{{- else if .Values.postgresql.external_database_url }}
- name: ARCHESTRA_DATABASE_URL
  valueFrom:
    secretKeyRef:
      name: {{ include "archestra-platform.authSecretName" . }}
      key: database-url
{{- else if .Values.postgresql.enabled }}
{{/*
For the bundled PostgreSQL, we use Kubernetes env variable expansion to inject the password
from the Bitnami PostgreSQL secret into the DATABASE_URL. This keeps the password out of the manifest.
The Bitnami chart auto-generates a strong password and persists it across helm upgrades.
*/}}
- name: PGPASSWORD
  valueFrom:
    secretKeyRef:
      name: {{ include "archestra-platform.fullname" . }}-postgresql
      key: password
- name: ARCHESTRA_DATABASE_URL
  value: postgresql://{{ .Values.postgresql.auth.username }}:$(PGPASSWORD)@{{ include "archestra-platform.fullname" . }}-postgresql:5432/{{ .Values.postgresql.auth.database }}
{{- end }}
{{/*
When both external_database_url is null and postgresql.enabled is false,
ARCHESTRA_DATABASE_URL is not set here. Use archestra.envFromSecrets to inject it from a pre-existing K8s secret.
*/}}
{{/*
Assigns value from autogenerated auth-secret to ARCHESTRA_AUTH_SECRET by default.
If ARCHESTRA_AUTH_SECRET env variable is explicitly set, it will override the autogenerated default.
*/}}
{{- if not (hasKey .Values.archestra.env "ARCHESTRA_AUTH_SECRET") }}
- name: ARCHESTRA_AUTH_SECRET
  valueFrom:
    secretKeyRef:
      name: {{ include "archestra-platform.authSecretName" . }}
      key: {{ include "archestra-platform.authSecretKey" . }}
{{- end }}
{{- if not (hasKey .Values.archestra.env "ARCHESTRA_ORCHESTRATOR_K8S_NAMESPACE") }}
- name: ARCHESTRA_ORCHESTRATOR_K8S_NAMESPACE
  value: {{ default .Release.Namespace .Values.archestra.orchestrator.kubernetes.namespace | quote }}
{{- end }}
{{- if .Values.archestra.orchestrator.baseImage }}
- name: ARCHESTRA_ORCHESTRATOR_MCP_SERVER_BASE_IMAGE
  value: {{ .Values.archestra.orchestrator.baseImage | quote }}
{{- end }}
{{- if and .Values.archestra.orchestrator.kubernetes.kubeconfig.enabled .Values.archestra.orchestrator.kubernetes.kubeconfig.secretName }}
- name: ARCHESTRA_ORCHESTRATOR_KUBECONFIG
  value: {{ printf "%s/config" .Values.archestra.orchestrator.kubernetes.kubeconfig.mountPath | quote }}
{{- end }}
- name: ARCHESTRA_ORCHESTRATOR_LOAD_KUBECONFIG_FROM_CURRENT_CLUSTER
  value: {{ .Values.archestra.orchestrator.kubernetes.loadKubeconfigFromCurrentCluster | quote }}
{{- if .Values.archestra.orchestrator.kubernetes.clusterDomain }}
- name: ARCHESTRA_ORCHESTRATOR_K8S_CLUSTER_DOMAIN
  value: {{ .Values.archestra.orchestrator.kubernetes.clusterDomain | quote }}
{{- end }}
{{- if .Values.archestra.diagnostics.enabled }}
- name: ARCHESTRA_NODE_DIAGNOSTIC_DIR
  value: "/var/diagnostics"
{{- if gt (int .Values.archestra.diagnostics.heapSnapshotsNearHeapLimit) 0 }}
- name: ARCHESTRA_NODE_HEAPSNAPSHOT_NEAR_HEAP_LIMIT
  value: {{ .Values.archestra.diagnostics.heapSnapshotsNearHeapLimit | quote }}
{{- end }}
{{- end }}
{{- range $key, $value := .Values.archestra.env }}
{{/* Check if env var is in the explicit sensitive list OR matches ARCHESTRA_CHAT_*_API_KEY pattern */}}
{{- $isSensitive := or (has $key $sensitiveEnvVars) (and (hasPrefix "ARCHESTRA_CHAT_" $key) (hasSuffix "_API_KEY" $key)) }}
{{/* Only use secretKeyRef for sensitive vars with non-empty values; empty values are set as regular env vars */}}
{{- if and $isSensitive $value }}
{{/* Sensitive env vars with values are stored in the Secret and referenced via secretKeyRef */}}
- name: {{ $key }}
  valueFrom:
    secretKeyRef:
      name: {{ include "archestra-platform.authSecretName" $ }}
      key: {{ $key | lower | replace "_" "-" }}
{{- else }}
- name: {{ $key }}
  value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- range .Values.archestra.envFromSecrets }}
- name: {{ .name }}
  valueFrom:
    secretKeyRef:
      name: {{ .secretName }}
      key: {{ .secretKey }}
{{- end }}
{{- range .Values.archestra.envWithValueFrom }}
- name: {{ .name }}
  valueFrom:
    {{- toYaml .valueFrom | nindent 4 }}
{{- end }}
{{- end }}

{{/*
Auth secret name for the Archestra Platform
*/}}
{{- define "archestra-platform.authSecretName" -}}
{{- default (printf "%s-auth" (include "archestra-platform.fullname" .)) .Values.archestra.authSecret.existingSecretName -}}
{{- end }}

{{/*
Auth secret key for the Archestra Platform
*/}}
{{- define "archestra-platform.authSecretKey" -}}
{{- if and (not .Values.archestra.authSecret.existingSecretName) (ne .Values.archestra.authSecret.existingSecretKey "auth-secret") -}}
{{- fail "archestra.authSecret.existingSecretKey requires archestra.authSecret.existingSecretName to also be set." -}}
{{- end -}}
{{- default "auth-secret" .Values.archestra.authSecret.existingSecretKey -}}
{{- end }}

{{/*
Diagnostics PVC claim name
*/}}
{{- define "archestra-platform.diagnosticsClaimName" -}}
{{- default (printf "%s-diagnostics" (include "archestra-platform.fullname" .)) .Values.archestra.diagnostics.existingClaimName -}}
{{- end }}

{{/*
ServiceAccount name for the Archestra Platform
*/}}
{{- define "archestra-platform.serviceAccountName" -}}
{{- if .Values.archestra.orchestrator.kubernetes.serviceAccount.create }}
{{- default (include "archestra-platform.fullname" .) .Values.archestra.orchestrator.kubernetes.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.archestra.orchestrator.kubernetes.serviceAccount.name }}
{{- end }}
{{- end }}

{{/*
Worker selector labels
*/}}
{{- define "archestra-platform.workerSelectorLabels" -}}
app.kubernetes.io/name: {{ include "archestra-platform.name" . }}-worker
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: worker
{{- end }}

{{/*
Worker labels
*/}}
{{- define "archestra-platform.workerLabels" -}}
helm.sh/chart: {{ include "archestra-platform.chart" . }}
{{ include "archestra-platform.workerSelectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
app.kubernetes.io/part-of: archestra
{{- end }}

{{/*
Shared init containers for both platform and worker Deployments.
Handles Vault secret injection, pgvector extension setup, and PostgreSQL readiness.
*/}}
{{- define "archestra-platform.initContainers" -}}
{{- if .Values.archestra.initContainers.vaultSecrets.enabled }}
# Vault secret injection init container
- name: vault-secrets
  image: {{ include "archestra-platform.image" . }}
  workingDir: /app/backend
  env:
    {{- include "archestra-platform.env" . | nindent 4 }}
    - name: VAULT_INJECTOR_SECRETS
      value: {{ .Values.archestra.initContainers.vaultSecrets.secrets | toJson | quote }}
  command: ["node", "--enable-source-maps", "dist/standalone-scripts/vault-env-injector.ee.mjs"]
  volumeMounts:
    - name: vault-secrets
      mountPath: /vault/secrets
{{- end }}
{{- if .Values.postgresql.enabled }}
# Ensure the pgvector extension exists in the application database.
- name: setup-postgres-extensions
  image: {{ printf "%s:%s" (.Values.postgresql.image.repository | default "bitnami/postgresql") (.Values.postgresql.image.tag | default "latest") }}
  {{- with .Values.archestra.initContainers.resources }}
  resources:
    {{- toYaml . | nindent 4 }}
  {{- end }}
  env:
    - name: PGPASSWORD
      valueFrom:
        secretKeyRef:
          name: {{ include "archestra-platform.fullname" . }}-postgresql
          key: postgres-password
  command:
    - sh
    - -c
    - |
      max_attempts={{ .Values.archestra.initContainers.waitForPostgres.timeoutSeconds | default 300 }}
      attempt=0
      until pg_isready -h {{ include "archestra-platform.fullname" . }}-postgresql -U postgres; do
        attempt=$((attempt + 1))
        if [ "$attempt" -ge "$max_attempts" ]; then
          echo "PostgreSQL did not become ready after ${max_attempts}s - giving up" >&2
          exit 1
        fi
        echo "Waiting for PostgreSQL... (${attempt}/${max_attempts})"
        sleep 1
      done
      psql -h {{ include "archestra-platform.fullname" . }}-postgresql -U postgres -d {{ .Values.postgresql.auth.database }} -c "CREATE EXTENSION IF NOT EXISTS vector;"
{{- end }}
- name: wait-for-postgres
  image: {{ .Values.archestra.initContainers.busyboxImage | default "busybox:1.36" }}
  {{- with .Values.archestra.initContainers.resources }}
  resources:
    {{- toYaml . | nindent 4 }}
  {{- end }}
  env:
    {{- include "archestra-platform.env" . | nindent 4 }}
  {{- if .Values.archestra.initContainers.vaultSecrets.enabled }}
  volumeMounts:
    - name: vault-secrets
      mountPath: /vault/secrets
      readOnly: true
  {{- end }}
  command:
    - sh
    - -c
    - |
      {{- if .Values.archestra.initContainers.waitForPostgres.enabled }}
      # Source Vault secrets if available (may override ARCHESTRA_DATABASE_URL)
      if [ -f /vault/secrets/env ]; then
        set -a
        . /vault/secrets/env
        set +a
      fi

      # Parse host and port from ARCHESTRA_DATABASE_URL
      # Format: postgresql://user:pass@host[:port]/database
      DB_URL="${ARCHESTRA_DATABASE_URL##*@}"  # Remove prefix up to last @ (handles passwords with @)
      HOST_PORT="${DB_URL%%/*}"               # Remove /database suffix
      HOST="${HOST_PORT%%:*}"                 # Extract host
      # Extract port, defaulting to 5432 if not specified
      case "$HOST_PORT" in
        *:*) PORT="${HOST_PORT##*:}" ;;
        *)   PORT="5432" ;;
      esac

      echo "Waiting for PostgreSQL at ${HOST}:${PORT}..."
      max_attempts={{ .Values.archestra.initContainers.waitForPostgres.timeoutSeconds | default 300 }}
      attempt=0
      until nc -z "${HOST}" "${PORT}"; do
        attempt=$((attempt + 1))
        if [ "$attempt" -ge "$max_attempts" ]; then
          echo "PostgreSQL at ${HOST}:${PORT} did not become reachable after ${max_attempts}s - giving up" >&2
          exit 1
        fi
        echo "PostgreSQL is unavailable - sleeping (${attempt}/${max_attempts})"
        sleep 1
      done
      echo "PostgreSQL is up - continuing"
      {{- else }}
      echo "Skipping PostgreSQL readiness check"
      {{- end }}
{{- end }}

{{/*
Shared volumes for both platform and worker Deployments.
*/}}
{{- define "archestra-platform.volumes" -}}
{{- if or (and .Values.archestra.orchestrator.kubernetes.kubeconfig.enabled .Values.archestra.orchestrator.kubernetes.kubeconfig.secretName) .Values.archestra.initContainers.vaultSecrets.enabled .Values.archestra.diagnostics.enabled .Values.archestra.extraVolumes }}
volumes:
  {{- if and .Values.archestra.orchestrator.kubernetes.kubeconfig.enabled .Values.archestra.orchestrator.kubernetes.kubeconfig.secretName }}
  - name: kubeconfig
    secret:
      secretName: {{ .Values.archestra.orchestrator.kubernetes.kubeconfig.secretName }}
  {{- end }}
  {{- if .Values.archestra.initContainers.vaultSecrets.enabled }}
  - name: vault-secrets
    emptyDir:
      medium: Memory
  {{- end }}
  {{- if .Values.archestra.diagnostics.enabled }}
  - name: diagnostics
    persistentVolumeClaim:
      claimName: {{ include "archestra-platform.diagnosticsClaimName" . }}
  {{- end }}
  {{- with .Values.archestra.extraVolumes }}
  {{- toYaml . | nindent 2 }}
  {{- end }}
{{- end }}
{{- end }}

{{/*
Shared volume mounts for the main container.
*/}}
{{- define "archestra-platform.volumeMounts" -}}
{{- if or (and .Values.archestra.orchestrator.kubernetes.kubeconfig.enabled .Values.archestra.orchestrator.kubernetes.kubeconfig.secretName) .Values.archestra.initContainers.vaultSecrets.enabled .Values.archestra.diagnostics.enabled .Values.archestra.extraVolumeMounts }}
volumeMounts:
  {{- if and .Values.archestra.orchestrator.kubernetes.kubeconfig.enabled .Values.archestra.orchestrator.kubernetes.kubeconfig.secretName }}
  - name: kubeconfig
    mountPath: {{ .Values.archestra.orchestrator.kubernetes.kubeconfig.mountPath }}
    readOnly: true
  {{- end }}
  {{- if .Values.archestra.initContainers.vaultSecrets.enabled }}
  - name: vault-secrets
    mountPath: /vault/secrets
    readOnly: true
  {{- end }}
  {{- if .Values.archestra.diagnostics.enabled }}
  - name: diagnostics
    mountPath: /var/diagnostics
    readOnly: false
  {{- end }}
  {{- with .Values.archestra.extraVolumeMounts }}
  {{- toYaml . | nindent 2 }}
  {{- end }}
{{- end }}
{{- end }}

{{/*
Vault secrets command wrapper for the main container.
Sources /vault/secrets/env before exec'ing the given entrypoint command.
Usage: Pass the desired entrypoint as the argument.
*/}}
{{- define "archestra-platform.vaultSecretsCommand" -}}
command: ["/bin/sh", "-c"]
args:
  - |
    if [ -f /vault/secrets/env ]; then
      set -a
      . /vault/secrets/env
      set +a
    fi
    exec {{ . }}
{{- end }}

{{/*
Full container image reference for the Archestra Platform.
This helper constructs the image reference smartly:
- If archestra.image already contains a tag (colon after the last slash), use it as-is
- Otherwise, append the imageTag value

This maintains backward compatibility with existing deployments that set the full image:tag
in archestra.image, while also supporting the new imageTag field used by release-please.

Examples:
  image: "archestra/platform", imageTag: "1.0.0" -> "archestra/platform:1.0.0"
  image: "archestra/platform:ci-test", imageTag: "1.0.0" -> "archestra/platform:ci-test"
  image: "registry.io:5000/archestra/platform", imageTag: "1.0.0" -> "registry.io:5000/archestra/platform:1.0.0"
*/}}
{{- define "archestra-platform.image" -}}
{{- $image := .Values.archestra.image -}}
{{- $imageTag := .Values.archestra.imageTag -}}
{{- /* Extract the part after the last slash to check for a tag */ -}}
{{- $lastSlashIndex := (sub (len $image) (len (trimPrefix "/" (regexReplaceAll ".*/" $image "")))) -}}
{{- $afterLastSlash := regexReplaceAll ".*/" $image "" -}}
{{- /* Check if there's a colon in the image name part (after the last slash) */ -}}
{{- if contains ":" $afterLastSlash -}}
{{- /* Image already has a tag, use as-is */ -}}
{{- $image -}}
{{- else -}}
{{- /* No tag in image, append imageTag */ -}}
{{- printf "%s:%s" $image $imageTag -}}
{{- end -}}
{{- end }}
