#!/usr/bin/env bash
# =============================================================================
# onx-user-unsuspend — Restore a suspended hosting account (v89 driver-agnostic)
#
# Purpose:
#   Unlocks Linux password (orijinal hash backup'tan restore edilir), restores
#   shell to /bin/bash, ve v89 cPanel-style rewrite marker'larını TÜM driver'lardan
#   temizler (.htaccess prepend, Nginx include, OLS marker, Caddy marker). Sonra
#   PHP-side restoreFor() çağrısı orijinal index.html'i .user-bak'tan geri yükler.
#
# v89 değişikliği — Apache vhost mv/restore PATERNİ KALDIRILDI:
#   - Eski: /etc/httpd/suspended/<user>-*.conf -> /etc/httpd/conf.d/sites/
#   - Yeni: vhost'lar zaten aktifti; sadece marker dosyalarını kaldırıp reload.
#
# Input (stdin JSON):
#   {
#     "username": "onx_xxxx"    -- required
#   }
#
# Output (stdout JSON):
#   {
#     "username":         "onx_xxxx",
#     "status":           "active",
#     "unsuspended_at":   "<ISO8601>",
#     "password_restored": 0|1,
#     "method":           "rewrite-cleanup"
#   }
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail
#             4=rolled-back 5=rollback-failed
#
# Sudoers entry needed:
#   apache ALL=(root) NOPASSWD: /usr/local/onoxsoft/bin/onx-user-unsuspend
#   Defaults!/usr/local/onoxsoft/bin/onx-user-unsuspend !requiretty
#   Defaults!/usr/local/onoxsoft/bin/onx-user-unsuspend log_output, log_input
#
# Deployed to: /usr/local/onoxsoft/bin/onx-user-unsuspend
# =============================================================================

set -euo pipefail

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

# ── Constants ─────────────────────────────────────────────────────────────────
META_DIR=".onox"
ACTIVE_SHELL="/bin/bash"
# v88 Agent 5 — Suspend sırasında shadow hash yedeği
SHADOW_BACKUP_DIR="/var/onox/suspended-passwords"

# v89 driver marker konumları (suspend ile aynı)
NGINX_INC_DIR="/etc/nginx/onoxsoft-suspend.d"
OLS_VHOST_BASE="/usr/local/lsws/conf/vhosts"
CADDY_SUSPEND_DIR="/etc/caddy/onoxsoft-suspend.d"

# ── Dependencies ──────────────────────────────────────────────────────────────
command -v jq      >/dev/null 2>&1 || { printf '{"error":"jq required"}\n' >&2; exit 2; }
command -v usermod >/dev/null 2>&1 || { printf '{"error":"usermod required"}\n' >&2; exit 2; }
require_root

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

USERNAME=$(onx_json_get "${INPUT}" "username")

# ── 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}")

# ── Preflight ─────────────────────────────────────────────────────────────────
# v89 IDEMPOTENT: user yoksa cleanup-only mode — marker'ları temizle, OK dön.
USER_EXISTS=0
if id "${USERNAME}" &>/dev/null; then
    USER_EXISTS=1
fi

trap 'onx_rollback_run' ERR

# ── v88 Agent 5 — Restore orijinal password hash (önce backup'a bak) ──────────
SHADOW_BACKUP_FILE="${SHADOW_BACKUP_DIR}/${USERNAME}.shadow"
PASSWORD_RESTORED=0
if [[ "${USER_EXISTS}" -eq 1 && -f "${SHADOW_BACKUP_FILE}" ]]; then
    OLD_HASH=$(awk -F: '{print $2}' "${SHADOW_BACKUP_FILE}")

    if [[ -z "${OLD_HASH}" || "${OLD_HASH}" == "!"* || "${OLD_HASH}" == "*" ]]; then
        onx_log "WARN: backup shadow hash boş veya locked, restore atlandı"
    else
        # /etc/shadow line'ı atomik olarak rebuild et
        DAYS_SINCE_EPOCH=$(( $(date +%s) / 86400 ))
        NEW_LINE="${USERNAME}:${OLD_HASH}:${DAYS_SINCE_EPOCH}:0:99999:7:::"

        SHADOW_TMP=$(mktemp /etc/shadow.onx.XXXXXX)
        chmod 000 "${SHADOW_TMP}" 2>/dev/null || true
        awk -F: -v user="${USERNAME}" -v line="${NEW_LINE}" '
            BEGIN { OFS=":" }
            $1 == user { print line; next }
            { print }
        ' /etc/shadow > "${SHADOW_TMP}"

        chown root:root "${SHADOW_TMP}"
        chmod 0 "${SHADOW_TMP}"
        mv -f "${SHADOW_TMP}" /etc/shadow

        rm -f "${SHADOW_BACKUP_FILE}"
        PASSWORD_RESTORED=1
        onx_log "unsuspend ${USERNAME}: orijinal password restore edildi (backup'tan)"
    fi
fi

# ── Unlock password + restore shell (user varsa) ─────────────────────────────
if [[ "${USER_EXISTS}" -eq 1 ]]; then
    usermod -U "${USERNAME}" 2>/dev/null || onx_log "WARN usermod -U failed: ${USERNAME}"
    onx_rollback_register "usermod -L '${USERNAME}' 2>/dev/null || true"
    onx_log "password unlocked: ${USERNAME}"

    usermod -s "${ACTIVE_SHELL}" "${USERNAME}" 2>/dev/null || onx_log "WARN shell restore failed"
    onx_rollback_register "usermod -s /sbin/nologin '${USERNAME}' 2>/dev/null || true"
    onx_log "shell restored to ${ACTIVE_SHELL}: ${USERNAME}"
fi

# ── v89: Discover docroots and clean Apache/LiteSpeed .htaccess markers ──────
DOCROOTS=()
[[ -d "${USER_HOME}/public_html" ]] && DOCROOTS+=("${USER_HOME}/public_html")
while IFS= read -r d; do
    [[ -n "$d" && -d "$d" ]] || continue
    skip=0
    for existing in "${DOCROOTS[@]+"${DOCROOTS[@]}"}"; do
        [[ "$existing" == "$d" ]] && skip=1 && break
    done
    [[ "$skip" -eq 0 ]] && DOCROOTS+=("$d")
done < <(find "${USER_HOME}" -mindepth 2 -maxdepth 4 -type d -name 'public_html' 2>/dev/null || true)

for DOCROOT in "${DOCROOTS[@]+"${DOCROOTS[@]}"}"; do
    [[ -d "${DOCROOT}" ]] || continue
    # Önce: kullanıcı yedeği varsa onu geri yükle (user'ın original .htaccess'i)
    if [[ -f "${DOCROOT}/.htaccess.onx-user-backup" ]]; then
        mv -f "${DOCROOT}/.htaccess.onx-user-backup" "${DOCROOT}/.htaccess"
        onx_log "restored user .htaccess from backup: ${DOCROOT}/.htaccess"
    elif [[ -f "${DOCROOT}/.htaccess" ]] && grep -q "ONOXSOFT suspended rewrite" "${DOCROOT}/.htaccess" 2>/dev/null; then
        # Kullanıcı yedeği yok ama bizim ürettiğimiz dosya var → tamamen sil
        rm -f "${DOCROOT}/.htaccess"
        onx_log "removed onoxsoft-only .htaccess (no user backup): ${DOCROOT}/.htaccess"
    fi
    # Snippet temizliği (her durumda)
    rm -f "${DOCROOT}/.htaccess.onx-suspended"
done

# ── v89: Nginx include cleanup ───────────────────────────────────────────────
NGINX_INC_FILE="${NGINX_INC_DIR}/${USERNAME}.conf"
if [[ -f "${NGINX_INC_FILE}" ]]; then
    rm -f "${NGINX_INC_FILE}"
    onx_log "nginx include removed: ${NGINX_INC_FILE}"
fi

if systemctl is-active --quiet nginx 2>/dev/null; then
    systemctl reload nginx 2>/dev/null || onx_log "WARN nginx reload failed (continuing)"
fi

# ── v3.39: OLS marker cleanup — multi-vhost glob (v3.38'de yazıldığı format) ─
# Suspend script her customer vhost dizinine ayrı marker yazıyor:
# /usr/local/lsws/conf/vhosts/<USER>-<DOMAIN>/.onx-suspended
OLS_REMOVED=0
shopt -s nullglob
for ols_vhost in "${OLS_VHOST_BASE}/${USERNAME}-"*/; do
    if [[ -f "${ols_vhost}/.onx-suspended" ]]; then
        rm -f "${ols_vhost}/.onx-suspended"
        OLS_REMOVED=$((OLS_REMOVED + 1))
    fi
done
shopt -u nullglob
onx_log "OLS markers removed: ${OLS_REMOVED} vhost(s) for ${USERNAME}"

# ── v3.39: Caddy marker cleanup — yeni format (.caddy snippet) ───────────────
# v3.38'de marker formatı .marker → .caddy snippet'e değişti, ikisini de sil.
CADDY_MARKER_FILE="${CADDY_SUSPEND_DIR}/${USERNAME}.marker"
CADDY_SNIPPET_FILE="${CADDY_SUSPEND_DIR}/${USERNAME}.caddy"
if [[ -f "${CADDY_MARKER_FILE}" ]]; then
    rm -f "${CADDY_MARKER_FILE}"
    onx_log "Caddy legacy .marker removed: ${CADDY_MARKER_FILE}"
fi
if [[ -f "${CADDY_SNIPPET_FILE}" ]]; then
    rm -f "${CADDY_SNIPPET_FILE}"
    onx_log "Caddy snippet removed: ${CADDY_SNIPPET_FILE}"
fi

if systemctl is-active --quiet caddy 2>/dev/null; then
    systemctl reload caddy 2>/dev/null || onx_log "WARN caddy reload failed (continuing)"
fi

# ── Apache/LSWS reload (best effort) ─────────────────────────────────────────
if systemctl is-active --quiet httpd 2>/dev/null; then
    systemctl reload httpd 2>/dev/null || onx_log "WARN httpd reload failed (continuing)"
fi
if systemctl is-active --quiet lsws 2>/dev/null; then
    /usr/local/lsws/bin/lswsctrl reload 2>/dev/null || \
        systemctl reload lsws 2>/dev/null || \
        onx_log "WARN lsws reload failed (continuing)"
fi

# ── Remove suspension marker ──────────────────────────────────────────────────
SUSPENSION_FILE="${USER_HOME}/${META_DIR}/suspension.json"
[[ -f "${SUSPENSION_FILE}" ]] && rm -f "${SUSPENSION_FILE}"
onx_log "suspension.json removed"

# ── v87: Restore customer .user-bak index.html (primary docroot) ──────────────
# PHP-side AccountUnsuspended listener tüm domain docroot'larını restore eder;
# bu blok sadece primary için emniyet ağı.
if [[ -x "${SCRIPT_DIR}/onx-default-page-restore" && -d "${USER_HOME}/public_html" ]]; then
    RESTORE_PAYLOAD=$(jq -nc \
        --arg u "${USERNAME}" \
        --arg r "${USER_HOME}/public_html" \
        '{
            username: $u,
            docroot: $r,
            remove_if_no_backup: true
        }')
    echo "${RESTORE_PAYLOAD}" | "${SCRIPT_DIR}/onx-default-page-restore" >/dev/null 2>&1 || \
        onx_log "WARN: default-page-restore skipped"
fi

# ── Output ────────────────────────────────────────────────────────────────────
UNSUSPENDED_AT=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
onx_json_out \
    "username"          "${USERNAME}" \
    "status"            "active" \
    "unsuspended_at"    "${UNSUSPENDED_AT}" \
    "password_restored" "${PASSWORD_RESTORED}" \
    "method"            "rewrite-cleanup"
