{{- if .Values.statefulSet.enabled }}
{{- /*
========================================
VALIDATION BLOCK: Multi-replica requirements
========================================
Enforces constraints for scaling beyond 1 replica:
  1. Database: Must use PostgreSQL/MySQL (not SQLite)
  2. Persistence: Must be enabled
  3. Storage sharing: Must use either existingClaim or mode=shared with create.enabled
  4. Access mode: For mode=shared + create, must specify ReadWriteMany
*/}}
{{- $replicas := int .Values.replicaCount }}
{{- $dburi := "" }}
{{- if and .Values.config (hasKey .Values.config "dbUri") }}
  {{- $dburi = (index .Values.config "dbUri") }}
{{- else if and .Values.config (hasKey .Values.config "db-uri") }}
  {{- $dburi = (index .Values.config "db-uri") }}
{{- end }}
{{- $scheme := "" }}
{{- if ne $dburi "" }}
  {{- $parts := splitList "://" $dburi }}
  {{- if gt (len $parts) 0 }}
    {{- $scheme = lower (index $parts 0) }}
  {{- end }}
{{- end }}
{{- $multiAllowed := or (eq $scheme "postgres") (eq $scheme "postgresql") (eq $scheme "mysql") (eq $scheme "mariadb") }}
{{- $p := .Values.persistence }}
{{- $mode := default "perReplica" $p.mode }}
{{- $hasExisting := ne (default "" $p.existingClaim) "" }}
{{- $isShared := eq $mode "shared" }}

{{- /* Fail fast: Database validation */}}
{{- if and (gt $replicas 1) (not $multiAllowed) }}
  {{- fail (printf "replicaCount=%d requires PostgreSQL/MySQL config.db-uri; scheme '%s' unsupported" $replicas $scheme) }}
{{- end }}

{{- /* Fail fast: Persistence must be enabled */}}
{{- if and (gt $replicas 1) (not $p.enabled) }}
  {{- fail (printf "replicaCount=%d requires persistence.enabled=true" $replicas) }}
{{- end }}

{{- /* Fail fast: Prevent per-replica PVC divergence */}}
{{- if and (gt $replicas 1) (not (or $hasExisting $isShared)) }}
  {{- fail (printf "replicaCount=%d requires either persistence.existingClaim (shared RWX PVC) OR persistence.mode=shared to create one; perReplica PVCs would diverge" $replicas) }}
{{- end }}

{{- /* Fail fast: Shared mode requires PVC source */}}
{{- if and (gt $replicas 1) $isShared (not $hasExisting) (hasKey $p "create") (not (get $p.create "enabled")) }}
  {{- fail (printf "persistence.mode=shared but neither existingClaim nor create.enabled=true provided") }}
{{- end }}

{{- /* Fail fast: Auto-created shared PVC must be RWX */}}
{{- if and (gt $replicas 1) $isShared (not $hasExisting) $p.create.enabled }}
  {{- $am := list }}
  {{- if hasKey $p.create "accessModes" }}
    {{- $am = $p.create.accessModes }}
  {{- end }}
  {{- $rwxOk := false }}
  {{- range $am }}
    {{- if or (eq . "ReadWriteMany") (eq . "RWX") }}
      {{- $rwxOk = true }}
    {{- end }}
  {{- end }}
  {{- if not $rwxOk }}
    {{- fail "persistence.mode=shared create.accessModes must include ReadWriteMany for multi-replica" }}
  {{- end }}
{{- end }}
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ include "opengist.fullname" . }}
  namespace: {{ .Values.namespace | default .Release.Namespace }}
  labels:
    {{- include "opengist.labels" . | nindent 4 }}
    {{- if .Values.deployment.labels }}
    {{- toYaml .Values.deployment.labels | nindent 4 }}
    {{- end }}
  {{- with .Values.deployment.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  replicas: {{ .Values.replicaCount }}
  serviceName: {{ include "opengist.fullname" . }}-http
  podManagementPolicy: {{ .Values.statefulSet.podManagementPolicy }}
  updateStrategy:
    {{- toYaml .Values.statefulSet.updateStrategy | nindent 4 }}
  selector:
    matchLabels:
      {{- include "opengist.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
      {{- with .Values.podAnnotations }}
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "opengist.labels" . | nindent 8 }}
        {{- with .Values.podLabels }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
    spec:
      {{- if .Values.deployment.terminationGracePeriodSeconds }}
      terminationGracePeriodSeconds: {{ .Values.deployment.terminationGracePeriodSeconds }}
      {{- end }}
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "opengist.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      initContainers:
        - name: init-config
          image: busybox:1.37
          imagePullPolicy: IfNotPresent
          command: ['sh', '-c', 'cp /init/config/config.yml /config-volume/config.yml']
          volumeMounts:
            - name: config-secret
              mountPath: /init/config
            - name: config-volume
              mountPath: /config-volume
          {{- if .Values.deployment.env }}
          env:
            {{- toYaml .Values.deployment.env | nindent 12 }}
          {{- end }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.http.port }}
              protocol: TCP
          {{- if .Values.service.ssh.enabled }}
            - name: ssh
              containerPort: {{ .Values.service.ssh.port }}
              protocol: TCP
          {{- end }}
          {{- if index .Values.config "metrics.enabled" }}
            - name: metrics
              containerPort: {{ .Values.service.metrics.port }}
              protocol: TCP
          {{- end }}
          {{- if .Values.livenessProbe.enabled }}
          livenessProbe:
            {{- toYaml (omit .Values.livenessProbe "enabled") | nindent 12 }}
            httpGet:
              port: http
              path: /healthcheck
          {{- end }}
          {{- if .Values.readinessProbe.enabled }}
          readinessProbe:
            {{- toYaml (omit .Values.readinessProbe "enabled") | nindent 12 }}
            httpGet:
              port: http
              path: /healthcheck
          {{- end }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          volumeMounts:
            - name: config-volume
              mountPath: /config.yml
              subPath: config.yml
            - name: opengist-data
              mountPath: /opengist
          {{- if gt (len .Values.extraVolumeMounts) 0 }}
            {{- toYaml .Values.extraVolumeMounts | nindent 12 }}
          {{- end }}
      volumes:
        - name: config-secret
          secret:
            secretName: {{ include "opengist.secretName" . }}
            defaultMode: 511
        - name: config-volume
          emptyDir: {}
        {{- /*
        ========================================
        VOLUME MOUNTING DECISION TREE
        ========================================
        Priority order:
          1. existingClaim (user-provided PVC) → mount directly
          2. mode=shared (chart-created PVC)   → mount shared PVC
          3. mode=perReplica                   → use volumeClaimTemplates (defined below)
          4. persistence disabled              → use emptyDir (ephemeral)
        */}}
        {{- if .Values.persistence.enabled }}
          {{- if ne (default "" .Values.persistence.existingClaim) "" }}
            {{- /* User-provided existing claim: mount directly */}}
        - name: opengist-data
          persistentVolumeClaim:
            claimName: {{ .Values.persistence.existingClaim }}
          {{- else if eq (default "perReplica" .Values.persistence.mode) "shared" }}
            {{- /* Chart creates shared PVC (via pvc-shared.yaml), reference by name */}}
        - name: opengist-data
          persistentVolumeClaim:
            claimName: {{ include "opengist.fullname" . }}-{{ default "shared" .Values.persistence.create.nameSuffix }}
          {{- else if not .Values.persistence.enabled }}
        - name: opengist-data
          emptyDir: {}
          {{- end }}
        {{- else }}
        - name: opengist-data
          emptyDir: {}
        {{- end }}
        {{- if gt (len .Values.extraVolumes) 0 }}
          {{- toYaml .Values.extraVolumes | nindent 8 }}
        {{- end }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
  {{- /*
  ========================================
  VOLUMECLAIMTEMPLATES DECISION TREE
  ========================================
  volumeClaimTemplates are ONLY used for perReplica mode when:
    - persistence.enabled=true
    - persistence.existingClaim is empty
    - persistence.mode=perReplica (default)

  This creates one PVC per replica (RWO typically).

  NOT used when:
    - existingClaim is set (PVC already exists, referenced in volumes above)
    - mode=shared (standalone PVC created via pvc-shared.yaml)
    - persistence disabled (emptyDir used)

  WARNING: perReplica + replicaCount>1 causes data divergence. Use shared mode for multi-replica.
  */}}
  {{- if and .Values.persistence.enabled (ne (default "" .Values.persistence.existingClaim) "") }}
    {{- /* existingClaim path: no volumeClaimTemplates, already mounted above */}}
  {{- else if and .Values.persistence.enabled (eq (default "perReplica" .Values.persistence.mode) "shared") }}
    {{- /* shared mode: no volumeClaimTemplates, standalone PVC rendered via pvc-shared.yaml */}}
  {{- else if and .Values.persistence.enabled (eq (default "perReplica" .Values.persistence.mode) "perReplica") }}
  volumeClaimTemplates:
    - metadata:
        name: opengist-data
        labels:
          {{- include "opengist.labels" . | nindent 10 }}
        {{- with .Values.persistence.annotations }}
        annotations:
          {{- toYaml . | nindent 10 }}
        {{- end }}
      spec:
        accessModes:
          {{- .Values.persistence.accessModes | toYaml | nindent 10 }}
        volumeMode: Filesystem
        {{- if .Values.persistence.storageClass }}
        storageClassName: {{ .Values.persistence.storageClass | quote }}
        {{- end }}
        resources:
          requests:
            storage: {{ .Values.persistence.size | default "10Gi" }}
  {{- end }}
{{- end }}
