#!/usr/bin/env bash
# onx-vhost-add-caddy — Create a Caddy vhost from template.
#
# Called by onx-vhost-add dispatcher when 'server' = 'caddy'.
# Caddy auto-HTTPS aktif — Let's Encrypt cert otomatik issue edilir.
#
# Input (stdin JSON) — same as onx-vhost-add.
# Output (stdout JSON):
#   {"vhost_path":..., "reloaded":true, "ssl_enabled":..., "server":"caddy"}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail 4=rolled-back

set -euo pipefail

SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
# shellcheck source=_lib/common.sh
source "${SCRIPT_DIR}/_lib/common.sh"

# ── Constants ────────────────────────────────────────────────────────────────
TEMPLATE_PATH="/usr/local/onoxsoft/templates/Caddyfile.stub"
VHOST_DIR="/etc/caddy/sites"
ROUNDCUBE_PATH="/usr/share/roundcubemail"
AUTODISCOVER_PATH="/usr/local/onoxsoft/autodiscover"
# Panel pool socket — system subdomain PHP handler (müşteri pool DEĞİL; open_basedir
# müşteri pool'da Roundcube/autodiscover path'ine izin vermez → 403/500).
PANEL_FPM_SOCK="/var/opt/remi/php82/run/php-fpm/onoxsoft-panel.sock"

# ── Read & parse stdin ───────────────────────────────────────────────────────
INPUT=$(cat)
onx_require_json "${INPUT}"

USERNAME=$(onx_json_get "${INPUT}" "username")
DOMAIN=$(onx_json_get "${INPUT}" "domain")
DOC_ROOT=$(onx_json_get "${INPUT}" "doc_root")
PHP_VERSION=$(onx_json_get "${INPUT}" "php_version" "8.2")

# v82.1: System subdomain mode (webmail/mail/panel/webdisk/autoconfig/autodiscover)
# — OLS v79.2 system subdomain pattern paralel implementasyon.
# SystemSubdomainProvisioner bu 4 type'tan birini gönderir (webmail_proxy,
# panel_redirect, webdisk, mail_autoconfig). Her type için ayrı Caddyfile
# site block üretilir (PHP handler = panel pool socket, cert = parent domain).
IS_SYSTEM_SUBDOMAIN=$(onx_json_get_bool "${INPUT}" "is_system_subdomain" "false")
SUBDOMAIN_TYPE=$(onx_json_get "${INPUT}" "subdomain_type" "")
PARENT_DOMAIN=$(onx_json_get "${INPUT}" "parent_domain" "")
REDIRECT_TO=$(onx_json_get "${INPUT}" "redirect_to" "")

# v3.40: Bulk regenerate callers (onx-caddy-vhosts-rewrite) bu flag'i true geçer
# → her vhost render'da reload yapmak yerine sonda tek seferde caller reload eder.
SKIP_RELOAD=$(onx_json_get_bool "${INPUT}" "skip_reload" "false")

# ── Input validation ─────────────────────────────────────────────────────────
onx_validate_username "${USERNAME}"

# Runtime detect home directory (handles /home/users/<user> vs /home/<user>)
USER_HOME=$(onx_resolve_home "${USERNAME}" 2>/dev/null || echo "/home/${USERNAME}")

onx_validate_domain "${DOMAIN}"

[[ -z "${DOC_ROOT}" ]] && onx_die 1 "doc_root is required"

PHP_VERSION_NODOT="${PHP_VERSION//./}"

# Parent domain auto-detect (system subdomain için) — input'tan gelmezse
# DOMAIN'in ilk segmentini soyup geri kalanını parent yap.
# webmail.example.com.tr → example.com.tr
if [[ "${IS_SYSTEM_SUBDOMAIN}" == "true" && -z "${PARENT_DOMAIN}" ]]; then
  PARENT_DOMAIN="${DOMAIN#*.}"
fi

# ── Preflight ────────────────────────────────────────────────────────────────
mkdir -p "${VHOST_DIR}"
command -v caddy >/dev/null 2>&1 || onx_die 2 "caddy not found"

# System subdomain için USER_HOME zorunlu değil — docroot Roundcube/autodiscover
# gibi sistem dizinleri (/usr/share/roundcubemail, /usr/local/onoxsoft/autodiscover).
# Normal vhost'ta home dir VAR olmalı (logs/ klasörü için).
if [[ "${IS_SYSTEM_SUBDOMAIN}" != "true" ]]; then
  [[ -d "${USER_HOME}" ]] || onx_die 2 "home directory not found: ${USER_HOME}"
  [[ -f "${TEMPLATE_PATH}" ]] || onx_die 2 "caddy template not found: ${TEMPLATE_PATH}"
  mkdir -p "${USER_HOME}/logs"
fi

VHOST_PATH="${VHOST_DIR}/${USERNAME}-${DOMAIN}.caddy"
BACKUP_PATH="${VHOST_PATH}.bak.$$"
[[ -f "${VHOST_PATH}" ]] && cp "${VHOST_PATH}" "${BACKUP_PATH}"

# ── Build space-separated aliases (Caddy syntax: domain.com www.domain.com {...}) ──
# v77.6: Caddy site bloğuna alias eklenirse her alias için ACME cert basma denenir
# (default auto-HTTPS). Alias DNS A record yoksa Let's Encrypt rate limit (HTTP 429)
# ve NXDOMAIN spam log. Bu yüzden ALIAS'LARI DNS check ile FILTER ediyoruz:
# - host komutu varsa: A/AAAA record check → DNS valid alias'ları al
# - host yoksa veya check fail: alias'ı atla (defensive — spam'i tetikleme)
SERVER_ALIASES_SPACE_SEPARATED=""
while IFS= read -r alias; do
  [[ -z "${alias}" ]] && continue

  # DNS check — A veya AAAA record var mı (1.5sn timeout, defensive)
  if command -v host >/dev/null 2>&1; then
    if timeout 2 host -t A "${alias}" >/dev/null 2>&1 || timeout 2 host -t AAAA "${alias}" >/dev/null 2>&1; then
      SERVER_ALIASES_SPACE_SEPARATED+=" ${alias}"
      onx_log "Alias DNS OK: ${alias}"
    else
      onx_log "Alias DNS YOK (skip): ${alias}"
    fi
  else
    # host komut yok — defensive skip (Caddy ACME spam'i önle)
    onx_log "Alias skip (host komutu yok): ${alias}"
  fi
done < <(onx_json_array_items "${INPUT}" "server_aliases")

# ── v77.2: TLS directive — cert path auto-detect ─────────────────────────────
# 5 candidate (vhost-add-nginx pattern'iyle paralel):
#   1. Input'tan gelen cert_path (panel SSL manager'in verdigi yol)
#   2. acme.sh ECC dizini (ECC daha hizli + modern, default acme.sh installer)
#   3. acme.sh RSA dizini
#   4. Let's Encrypt /etc/letsencrypt/live/<domain>/
#   5. Panel-managed /usr/local/onoxsoft/ssl/<domain>/
#
# v82.1: System subdomain için cert lookup'ı PARENT_DOMAIN ile yap. webmail.X
# için cert webmail.X'in altında YOK — parent X'in multi-SAN cert'i tüm 7
# hostname'i (parent + 6 system subdomain) kapsar. Cert subject:
# DNS:example.com, DNS:webmail.example.com, DNS:mail.example.com, ...
TLS_DIRECTIVE=""
INPUT_CERT=$(onx_json_get "${INPUT}" "cert_path" "")
INPUT_KEY=$(onx_json_get "${INPUT}" "key_path" "")

# System subdomain ise cert lookup PARENT_DOMAIN üzerinden (AutoSSL multi-SAN
# parent altında basılır). Normal vhost'ta DOMAIN kendi cert'iyle eşleşir.
if [[ "${IS_SYSTEM_SUBDOMAIN}" == "true" && -n "${PARENT_DOMAIN}" ]]; then
    CERT_LOOKUP_DOMAIN="${PARENT_DOMAIN}"
else
    CERT_LOOKUP_DOMAIN="${DOMAIN}"
fi

if [[ -n "${INPUT_CERT}" && -f "${INPUT_CERT}" && -n "${INPUT_KEY}" && -f "${INPUT_KEY}" ]]; then
    TLS_DIRECTIVE="tls ${INPUT_CERT} ${INPUT_KEY}"
    RESOLVED_CERT="${INPUT_CERT}"
    RESOLVED_KEY="${INPUT_KEY}"
elif [[ -f "/root/.acme.sh/${CERT_LOOKUP_DOMAIN}_ecc/fullchain.cer" && -f "/root/.acme.sh/${CERT_LOOKUP_DOMAIN}_ecc/${CERT_LOOKUP_DOMAIN}.key" ]]; then
    RESOLVED_CERT="/root/.acme.sh/${CERT_LOOKUP_DOMAIN}_ecc/fullchain.cer"
    RESOLVED_KEY="/root/.acme.sh/${CERT_LOOKUP_DOMAIN}_ecc/${CERT_LOOKUP_DOMAIN}.key"
    TLS_DIRECTIVE="tls ${RESOLVED_CERT} ${RESOLVED_KEY}"
elif [[ -f "/root/.acme.sh/${CERT_LOOKUP_DOMAIN}/fullchain.cer" && -f "/root/.acme.sh/${CERT_LOOKUP_DOMAIN}/${CERT_LOOKUP_DOMAIN}.key" ]]; then
    RESOLVED_CERT="/root/.acme.sh/${CERT_LOOKUP_DOMAIN}/fullchain.cer"
    RESOLVED_KEY="/root/.acme.sh/${CERT_LOOKUP_DOMAIN}/${CERT_LOOKUP_DOMAIN}.key"
    TLS_DIRECTIVE="tls ${RESOLVED_CERT} ${RESOLVED_KEY}"
elif [[ -f "/etc/letsencrypt/live/${CERT_LOOKUP_DOMAIN}/fullchain.pem" && -f "/etc/letsencrypt/live/${CERT_LOOKUP_DOMAIN}/privkey.pem" ]]; then
    RESOLVED_CERT="/etc/letsencrypt/live/${CERT_LOOKUP_DOMAIN}/fullchain.pem"
    RESOLVED_KEY="/etc/letsencrypt/live/${CERT_LOOKUP_DOMAIN}/privkey.pem"
    TLS_DIRECTIVE="tls ${RESOLVED_CERT} ${RESOLVED_KEY}"
elif [[ -f "/usr/local/onoxsoft/ssl/${CERT_LOOKUP_DOMAIN}/fullchain.pem" && -f "/usr/local/onoxsoft/ssl/${CERT_LOOKUP_DOMAIN}/privkey.pem" ]]; then
    RESOLVED_CERT="/usr/local/onoxsoft/ssl/${CERT_LOOKUP_DOMAIN}/fullchain.pem"
    RESOLVED_KEY="/usr/local/onoxsoft/ssl/${CERT_LOOKUP_DOMAIN}/privkey.pem"
    TLS_DIRECTIVE="tls ${RESOLVED_CERT} ${RESOLVED_KEY}"
else
    # v77.11: Cert YOK → site bloğunu `http://domain` scheme ile aç (HTTP-only).
    # `tls internal` Caddy local CA self-signed üretirken sistem trust store'a
    # root cert install için `sudo cp/certutil` çağırır — caddy user NOPASSWD yok
    # → validate fail. `http://` scheme Caddy auto-HTTPS davranışını HİÇ devreye
    # sokmaz, sadece port 80 serve. AutoSSL job sonradan cert basınca vhost
    # re-generate edilir + `tls /path /key` directive eklenir.
    TLS_DIRECTIVE=""
    DOMAIN_PREFIX="http://"
    RESOLVED_CERT=""
    RESOLVED_KEY=""
fi
DOMAIN_PREFIX="${DOMAIN_PREFIX:-}"

onx_log "TLS directive (lookup=${CERT_LOOKUP_DOMAIN}): ${TLS_DIRECTIVE:-(none — http:// scheme)}"

# ── v82.1: System subdomain branch ───────────────────────────────────────────
# OLS v79.2 pattern paralel — webmail/mail/panel/webdisk/autoconfig/autodiscover
# için template SKIP, doğrudan Caddyfile site block heredoc ile üretilir.
# PHP handler: panel pool socket (onoxsoft-panel.sock) — müşteri pool'un
# open_basedir restriction'i Roundcube'a izin vermez.
if [[ "${IS_SYSTEM_SUBDOMAIN}" == "true" ]]; then
  TMP_CONF=$(mktemp /tmp/onx-vhost-caddy-sys-XXXXXX.caddy)
  trap 'rm -f "${TMP_CONF}"' EXIT

  # Log/header common block — her system subdomain için aynı (Roundcube/autodiscover
  # access log /var/log/onoxsoft-system altında, user'ın logs/ klasöründe değil —
  # müşteri pool ile karışmasın diye).
  mkdir -p /var/log/onoxsoft-system 2>/dev/null
  chmod 755 /var/log/onoxsoft-system 2>/dev/null

  # Cert directive — parent'tan bulunduysa kullan, yoksa http:// scheme
  if [[ -n "${TLS_DIRECTIVE}" ]]; then
    SYS_DOMAIN_LINE="${DOMAIN}"
    SYS_TLS_LINE="    ${TLS_DIRECTIVE}"
  else
    SYS_DOMAIN_LINE="http://${DOMAIN}"
    SYS_TLS_LINE=""
  fi

  case "${SUBDOMAIN_TYPE}" in
    webmail_proxy)
      # mail.<domain>, webmail.<domain> → Roundcube (/usr/share/roundcubemail)
      # @blocked matcher: config/, logs/, SQL/, vendor/, .git/ ifşa engeli
      # (Roundcube var/log mount edilmeyen sensitive klasörler).
      cat > "${TMP_CONF}" <<CADDYEOF
# Auto-generated by onx-vhost-add-caddy (subdomain_type=webmail_proxy, parent=${PARENT_DOMAIN})
${SYS_DOMAIN_LINE} {
    root * ${ROUNDCUBE_PATH}
    encode gzip

    # Hassas dizin/dosya yasakla (Roundcube ifşa koruması)
    @blocked path /config/* /logs/* /SQL/* /vendor/* /.git/* /bin/* /CHANGELOG* /INSTALL* /LICENSE* /README*
    respond @blocked 403

    # PHP handler — panel pool socket (open_basedir Roundcube path'ine izinli)
    php_fastcgi unix/${PANEL_FPM_SOCK}

    file_server

${SYS_TLS_LINE}

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        Referrer-Policy strict-origin-when-cross-origin
    }

    log {
        output file /var/log/onoxsoft-system/${DOMAIN}-access.log
        format console
    }
}
CADDYEOF
      ;;

    panel_redirect)
      # panel.<domain> → ONOXSOFT panel admin URL'sine 302 redirect.
      # REDIRECT_TO yoksa default panel URL (config'den).
      _redirect_url="${REDIRECT_TO:-https://panel.onoxsoft.com.tr:666/customer/dashboard}"
      cat > "${TMP_CONF}" <<CADDYEOF
# Auto-generated by onx-vhost-add-caddy (subdomain_type=panel_redirect, parent=${PARENT_DOMAIN})
${SYS_DOMAIN_LINE} {
    redir ${_redirect_url} 302

${SYS_TLS_LINE}

    log {
        output file /var/log/onoxsoft-system/${DOMAIN}-access.log
        format console
    }
}
CADDYEOF
      ;;

    webdisk)
      # webdisk.<domain> → şimdilik panel files UI'sine 302 (gerçek WebDAV mount
      # Apache mod_dav'a bağımlı, Caddy native WebDAV yok — third-party module
      # caddy-webdav lazım). v82.x'te native module entegre edilirse direkt mount.
      _webdisk_url="${REDIRECT_TO:-https://panel.onoxsoft.com.tr:666/customer/files}"
      cat > "${TMP_CONF}" <<CADDYEOF
# Auto-generated by onx-vhost-add-caddy (subdomain_type=webdisk, parent=${PARENT_DOMAIN})
# NOT: Caddy'de native WebDAV yok — panel files UI'sine redirect (v82.x'te
# caddy-webdav modülü entegre edilirse direkt DAV mount eklenecek).
${SYS_DOMAIN_LINE} {
    redir ${_webdisk_url} 302

${SYS_TLS_LINE}

    log {
        output file /var/log/onoxsoft-system/${DOMAIN}-access.log
        format console
    }
}
CADDYEOF
      ;;

    mail_autoconfig)
      # autodiscover.<domain> (Outlook) + autoconfig.<domain> (Thunderbird)
      # Same docroot (/usr/local/onoxsoft/autodiscover), rewrite kuralları
      # subdomain'e göre seç (autodiscover.* = Outlook XML, autoconfig.* = Mozilla XML).
      cat > "${TMP_CONF}" <<CADDYEOF
# Auto-generated by onx-vhost-add-caddy (subdomain_type=mail_autoconfig, parent=${PARENT_DOMAIN})
${SYS_DOMAIN_LINE} {
    root * ${AUTODISCOVER_PATH}
    encode gzip

    # Outlook autodiscover (case-insensitive — XP/2003/2007/2010+ farklı case)
    @autodiscover path_regexp ad ^/[Aa]utodiscover/[Aa]utodiscover\.xml$
    rewrite @autodiscover /autodiscover.xml.php

    # Thunderbird / iOS Mail / Mozilla autoconfig
    @thunderbird path /mail/config-v1.1.xml /.well-known/autoconfig/mail/config-v1.1.xml
    rewrite @thunderbird /thunderbird.xml.php

    # PHP handler — panel pool (autodiscover script /usr/local/onoxsoft/autodiscover'da,
    # müşteri pool'un open_basedir'i bu path'e izin vermez)
    php_fastcgi unix/${PANEL_FPM_SOCK}

    file_server

${SYS_TLS_LINE}

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options nosniff
    }

    log {
        output file /var/log/onoxsoft-system/${DOMAIN}-access.log
        format console
    }
}
CADDYEOF
      ;;

    *)
      onx_die 1 "unknown subdomain_type: ${SUBDOMAIN_TYPE} (expected: webmail_proxy|panel_redirect|webdisk|mail_autoconfig)"
      ;;
  esac

  # Install rendered config
  install -m 0644 "${TMP_CONF}" "${VHOST_PATH}"

  # Ensure main Caddyfile imports /etc/caddy/sites/*.caddy (idempotent)
  MAIN_CADDYFILE="/etc/caddy/Caddyfile"
  if [[ -f "${MAIN_CADDYFILE}" ]] && ! grep -q "import sites/\*.caddy" "${MAIN_CADDYFILE}"; then
    echo "" >> "${MAIN_CADDYFILE}"
    echo "import sites/*.caddy" >> "${MAIN_CADDYFILE}"
  fi

  # caddy validate → rollback on failure (system subdomain'in syntax hatası
  # diğer 10+ vhost'u da down eder, validate ŞART)
  if ! caddy validate --config "${MAIN_CADDYFILE}" 2>/dev/null; then
    onx_log "caddy validate failed (system subdomain ${SUBDOMAIN_TYPE}) — rolling back"
    if [[ -f "${BACKUP_PATH}" ]]; then
      mv "${BACKUP_PATH}" "${VHOST_PATH}"
    else
      rm -f "${VHOST_PATH}"
    fi
    onx_die 4 "caddy validate failed; system subdomain rolled back"
  fi

  rm -f "${BACKUP_PATH}"

  # Reload Caddy (v77.12 graceful pattern — Caddy down ise deferred)
  # v3.40: SKIP_RELOAD flag bulk regenerate caller'lar için
  RELOADED="false"
  if [[ "${SKIP_RELOAD}" == "true" ]]; then
    RELOADED="skipped"
    onx_log "caddy reload atlandı (SKIP_RELOAD)"
  elif systemctl is-active --quiet caddy; then
    if systemctl reload caddy 2>/dev/null; then
      RELOADED="true"
    else
      RELOADED="reload_failed"
      onx_log "caddy aktif ama reload failed"
    fi
  else
    RELOADED="deferred"
    onx_log "caddy down — system subdomain vhost yazıldı, Caddy start'ta yüklenecek"
  fi

  onx_json_out \
    "vhost_path"           "${VHOST_PATH}" \
    "reloaded"             "${RELOADED}" \
    "ssl_enabled"          "$([[ -n "${TLS_DIRECTIVE}" ]] && echo true || echo false)" \
    "server"               "caddy" \
    "is_system_subdomain"  "true" \
    "subdomain_type"       "${SUBDOMAIN_TYPE}" \
    "parent_domain"        "${PARENT_DOMAIN}"
  exit 0
fi

# ── Render template ──────────────────────────────────────────────────────────
TMP_CONF=$(mktemp /tmp/onx-vhost-caddy-XXXXXX.caddy)
trap 'rm -f "${TMP_CONF}"' EXIT

cp "${TEMPLATE_PATH}" "${TMP_CONF}"

multiline_replace() {
  local var="$1"
  local val="$2"
  local tmpfile="${TMP_CONF}.replace"
  awk -v var="\${${var}}" -v val="${val}" '
    {
      while ((idx = index($0, var)) > 0) {
        $0 = substr($0, 1, idx-1) val substr($0, idx + length(var))
      }
      print
    }
  ' "${TMP_CONF}" > "${tmpfile}"
  mv "${tmpfile}" "${TMP_CONF}"
}

# v3.35: WAF_DIRECTIVE resolution — Coraza WAF snippet aktif ve Caddyfile'da
# `order coraza_waf first` tanımlı ise vhost'a "import coraza-include" ekle.
# Aksi halde boş bırakılır (gateless, template'de DOM içinde tek satır yer kaplar).
WAF_DIRECTIVE=""
if [[ -f /etc/caddy/coraza-include.caddy ]] && \
   grep -qE "order[[:space:]]+coraza_waf" /etc/caddy/Caddyfile 2>/dev/null; then
    WAF_DIRECTIVE="import coraza-include"
fi

multiline_replace "USERNAME"                       "${USERNAME}"
multiline_replace "DOMAIN_PREFIX"                  "${DOMAIN_PREFIX}"
multiline_replace "DOMAIN"                         "${DOMAIN}"
multiline_replace "DOC_ROOT"                       "${DOC_ROOT}"
multiline_replace "PHP_VERSION_NODOT"              "${PHP_VERSION_NODOT}"
multiline_replace "SERVER_ALIASES_SPACE_SEPARATED" "${SERVER_ALIASES_SPACE_SEPARATED}"
multiline_replace "TLS_DIRECTIVE"                  "${TLS_DIRECTIVE}"
multiline_replace "WAF_DIRECTIVE"                  "${WAF_DIRECTIVE}"

# Install the rendered config
install -m 0644 "${TMP_CONF}" "${VHOST_PATH}"

# Ensure main Caddyfile imports /etc/caddy/sites/*.caddy
MAIN_CADDYFILE="/etc/caddy/Caddyfile"
if [[ -f "${MAIN_CADDYFILE}" ]] && ! grep -q "import sites/\*.caddy" "${MAIN_CADDYFILE}"; then
  echo "" >> "${MAIN_CADDYFILE}"
  echo "import sites/*.caddy" >> "${MAIN_CADDYFILE}"
fi

# ── caddy validate → rollback on failure ─────────────────────────────────────
if ! caddy validate --config "${MAIN_CADDYFILE}" 2>/dev/null; then
  onx_log "caddy validate failed — rolling back"
  if [[ -f "${BACKUP_PATH}" ]]; then
    mv "${BACKUP_PATH}" "${VHOST_PATH}"
  else
    rm -f "${VHOST_PATH}"
  fi
  onx_die 4 "caddy validate failed; vhost rolled back"
fi

rm -f "${BACKUP_PATH}"

# ── Reload Caddy ─────────────────────────────────────────────────────────────
# v77.12: Caddy aktif değilse (Apache/Nginx mode'unda script çağrılması — switch
# sırasında veya prepare aşamasında) reload skip. Vhost dosyası diske yazıldı,
# Caddy aktive olduğunda zaten import sites/*.caddy ile load eder. Hard error
# vermek Provisioner'da partial fail'a sebep oluyordu (mail OK, diğer 5 fail
# zinciri) — sadece warning log + success JSON dön.
# v3.40: SKIP_RELOAD flag bulk regenerate caller'lar için
RELOADED="false"
if [[ "${SKIP_RELOAD}" == "true" ]]; then
    RELOADED="skipped"
elif systemctl is-active --quiet caddy; then
    if systemctl reload caddy 2>/dev/null; then
        RELOADED="true"
    else
        onx_log "caddy aktif ama reload başarısız (config issue?)"
        # NOT bunu da fail saymıyoruz — vhost yazıldı, validate geçti.
        RELOADED="reload_failed"
    fi
else
    onx_log "caddy down — vhost yazıldı, Caddy start'ta yüklenecek"
    RELOADED="deferred"
fi

# ── Success ──────────────────────────────────────────────────────────────────
onx_json_out \
  "vhost_path"  "${VHOST_PATH}" \
  "reloaded"    "${RELOADED}" \
  "ssl_enabled" "true" \
  "server"      "caddy"
