#!/usr/bin/env bash
# onx-nginx-bulk-restart — v77.14: Bulk vhost finaliser for Nginx (SNI cache clear).
#
# Bulk operasyon sonrası caller bu script'i çağırır. Heuristic:
#   - change_count == 1  → systemctl reload nginx (zero-downtime hot reload)
#   - change_count  > 1  → systemctl restart nginx (TLS context FULL RESET)
#
# Neden restart?
#   Nginx `reload` worker'ları graceful restart eder, AMA SSL context cache'i
#   her zaman tam temizlemez. Özellikle SNI-based per-vhost cert değişimlerinde
#   eski cert worker memory'sinde tutulabilir (HOT reload semantics). Bulk vhost
#   değişikliği = potansiyel cert path drift = restart şart.
#
# Tek vhost değişikliğinde reload yeterli (downtime minimize) — tipik durumda
# script vhost-add'in zaten yaptığı reload'u tekrarlamaz, sadece bulk migration
# sonunda toplu reload/restart için kullanılır.
#
# Input (stdin JSON):
#   change_count  int     Toplam vhost ekle/sil/güncelle sayısı (default 0)
#   force         bool    "true" ise zorla restart (change_count'a bakılmaz)
#   skip_test     bool    "true" ise nginx -t bypass (caller zaten test etti)
#
# Output (stdout JSON):
#   {"ok":true, "action":"reload|restart|skipped|deferred", "change_count":N,
#    "config_test":"ok|failed", "duration_ms":N}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=config-test-fail 4=action-fail
#
# Idempotent: nginx down/uninstalled ise deferred (rc=0).

set -euo pipefail

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

START_MS=$(date +%s%3N 2>/dev/null || echo "0")

# ── Read & parse stdin (optional; defaults safe) ─────────────────────────────
INPUT=$(cat 2>/dev/null || echo '{}')
if ! printf '%s' "${INPUT}" | jq -e 'type == "object"' >/dev/null 2>&1; then
    INPUT='{}'
fi

CHANGE_COUNT=$(printf '%s' "${INPUT}" | jq -r '.change_count // 0')
FORCE=$(onx_json_get_bool "${INPUT}" "force" "false")
SKIP_TEST=$(onx_json_get_bool "${INPUT}" "skip_test" "false")

# ── Preflight ────────────────────────────────────────────────────────────────
# Nginx kurulu değil veya systemctl yok → graceful skip (deferred).
if ! command -v nginx >/dev/null 2>&1; then
    onx_log "nginx binary not found — deferred"
    onx_json_out "ok" "true" "action" "skipped" "change_count" "${CHANGE_COUNT}" \
                 "config_test" "n/a" "reason" "nginx-not-installed"
    exit 0
fi

if ! command -v systemctl >/dev/null 2>&1; then
    onx_json_out "ok" "true" "action" "skipped" "change_count" "${CHANGE_COUNT}" \
                 "config_test" "n/a" "reason" "systemctl-missing"
    exit 0
fi

# Service hiç enable değilse veya unit yoksa skip.
if ! systemctl list-unit-files nginx.service >/dev/null 2>&1; then
    onx_json_out "ok" "true" "action" "skipped" "change_count" "${CHANGE_COUNT}" \
                 "config_test" "n/a" "reason" "nginx-unit-missing"
    exit 0
fi

# ── nginx -t (config validation) ─────────────────────────────────────────────
CONFIG_TEST="skipped"
if [[ "${SKIP_TEST}" != "true" ]]; then
    if timeout 15 nginx -t >/dev/null 2>&1; then
        CONFIG_TEST="ok"
    else
        # Config bozuk → action ALMA (restart cert/syntax error nedeniyle servisi düşürür).
        CONFIG_TEST="failed"
        END_MS=$(date +%s%3N 2>/dev/null || echo "${START_MS}")
        DURATION=$((END_MS - START_MS))
        onx_log "nginx -t FAILED — skipping reload/restart (action=skipped)"
        onx_json_out "ok" "false" "action" "skipped" "change_count" "${CHANGE_COUNT}" \
                     "config_test" "failed" "duration_ms" "${DURATION}" \
                     "error" "nginx -t failed"
        exit 3
    fi
fi

# ── Determine action (reload vs restart heuristic) ───────────────────────────
ACTION="reload"
REASON=""
if [[ "${FORCE}" == "true" ]]; then
    ACTION="restart"
    REASON="forced"
elif [[ "${CHANGE_COUNT}" -gt 1 ]]; then
    ACTION="restart"
    REASON="bulk-changes-sni-cache-clear"
fi

# ── Nginx running mu? Değilse vhost dosyaları diskte, sonraki start'ta yüklenir.
if ! systemctl is-active --quiet nginx; then
    END_MS=$(date +%s%3N 2>/dev/null || echo "${START_MS}")
    DURATION=$((END_MS - START_MS))
    onx_log "nginx down — deferred (changes=${CHANGE_COUNT})"
    onx_json_out "ok" "true" "action" "deferred" "change_count" "${CHANGE_COUNT}" \
                 "config_test" "${CONFIG_TEST}" "duration_ms" "${DURATION}" \
                 "reason" "nginx-not-running"
    exit 0
fi

# ── Action: reload or restart ────────────────────────────────────────────────
if [[ "${ACTION}" == "restart" ]]; then
    # Restart — TLS context FULL RESET (SNI cache clear).
    if ! timeout 30 systemctl restart nginx 2>/dev/null; then
        END_MS=$(date +%s%3N 2>/dev/null || echo "${START_MS}")
        DURATION=$((END_MS - START_MS))
        onx_json_out "ok" "false" "action" "restart" "change_count" "${CHANGE_COUNT}" \
                     "config_test" "${CONFIG_TEST}" "duration_ms" "${DURATION}" \
                     "error" "systemctl restart nginx failed"
        exit 4
    fi
    # Restart sonrası kısa wait — worker'lar gerçekten up olsun (master fork)
    sleep 1
    # Restart sonra running doğrula
    if ! systemctl is-active --quiet nginx; then
        END_MS=$(date +%s%3N 2>/dev/null || echo "${START_MS}")
        DURATION=$((END_MS - START_MS))
        onx_json_out "ok" "false" "action" "restart" "change_count" "${CHANGE_COUNT}" \
                     "config_test" "${CONFIG_TEST}" "duration_ms" "${DURATION}" \
                     "error" "nginx not running after restart"
        exit 4
    fi
else
    # Reload — graceful hot reload (single change).
    if ! timeout 15 systemctl reload nginx 2>/dev/null; then
        # Reload fail → restart fallback (worker stuck olabilir)
        onx_log "reload failed — fallback restart"
        ACTION="restart-fallback"
        REASON="reload-failed-fallback"
        if ! timeout 30 systemctl restart nginx 2>/dev/null; then
            END_MS=$(date +%s%3N 2>/dev/null || echo "${START_MS}")
            DURATION=$((END_MS - START_MS))
            onx_json_out "ok" "false" "action" "${ACTION}" \
                         "change_count" "${CHANGE_COUNT}" \
                         "config_test" "${CONFIG_TEST}" \
                         "duration_ms" "${DURATION}" \
                         "error" "reload + restart fallback both failed"
            exit 4
        fi
        sleep 1
    fi
fi

END_MS=$(date +%s%3N 2>/dev/null || echo "${START_MS}")
DURATION=$((END_MS - START_MS))

onx_log "nginx ${ACTION} OK (changes=${CHANGE_COUNT}, reason=${REASON:-single-change}, ${DURATION}ms)"

onx_json_out \
    "ok"            "true" \
    "action"        "${ACTION}" \
    "change_count"  "${CHANGE_COUNT}" \
    "config_test"   "${CONFIG_TEST}" \
    "duration_ms"   "${DURATION}" \
    "reason"        "${REASON:-single-change}"
