#!/usr/bin/env bash
# =============================================================================
# onx-ssl-issue (v89) — Issue SSL cert via acme.sh (primary) or certbot (fallback)
#
# Listener-driven SSL provisioning (DomainAdded event → queued listener).
# Mevcut onx-cert-issue (AutoSSL multi-SAN, account_email + advanced flags)
# ile rekabet etmez — bu daha basit "domain + www." 2-SAN minimal cert.
#
# Input (stdin JSON):
#   domain   string  Primary domain (örn "example.com")
#   webroot  string  DocumentRoot for http-01 challenge
#   aliases  array   Ek SAN'lar (örn ["www.example.com"]) — opsiyonel
#
# Output (stdout JSON):
#   {"domain":..., "cert_path":..., "key_path":..., "chain_path":..., "backend":"acme.sh"|"certbot"}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail
#
# Backend tercih sırası:
#   1. acme.sh (/usr/local/onoxsoft/acme.sh/acme.sh, /etc/onoxsoft/acme.sh/acme.sh, /root/.acme.sh/acme.sh)
#   2. certbot (system PATH) — sadece acme.sh fail ederse veya kurulu değilse
#
# SELinux: cert/key file'lar `cert_t` label'lı yapılır (sysapi servisleri okuyabilsin).
#
# Deployed to: /usr/local/onoxsoft/bin/onx-ssl-issue
# =============================================================================

set -euo pipefail

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

# ── Constants ────────────────────────────────────────────────────────────────
# acme.sh multi-path lookup (install.sh path öncelikli)
ACME_BIN=""
for candidate in \
    /usr/local/onoxsoft/acme.sh/acme.sh \
    /etc/onoxsoft/acme.sh/acme.sh \
    /root/.acme.sh/acme.sh \
    /opt/onoxsoft/acme.sh/acme.sh; do
    if [[ -x "${candidate}" ]]; then
        ACME_BIN="${candidate}"
        break
    fi
done

CERT_BASE="/etc/letsencrypt/live"
ACME_LOG="/tmp/onx-ssl-issue-acme.log"
CB_LOG="/tmp/onx-ssl-issue-cb.log"

# ── Read & parse stdin ───────────────────────────────────────────────────────
onx_json_input

DOMAIN=$(onx_json_field "domain")
WEBROOT=$(onx_json_field "webroot")

# ── Validation ───────────────────────────────────────────────────────────────
[[ -z "${DOMAIN}" ]]  && onx_die 1 "domain required"
[[ -z "${WEBROOT}" ]] && onx_die 1 "webroot required"
onx_validate_domain "${DOMAIN}"
[[ -d "${WEBROOT}" ]] || onx_die 1 "webroot directory does not exist: ${WEBROOT}"

# ── Build alt_names array ────────────────────────────────────────────────────
declare -a ALIASES=()
while IFS= read -r alt; do
    [[ -n "${alt}" ]] || continue
    # Inline alias validation (regex permissif çünkü www.x.co.uk vs)
    if [[ "${alt}" =~ ^([a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$ ]]; then
        ALIASES+=("${alt}")
    else
        onx_log "skipping invalid alias: ${alt}"
    fi
done < <(onx_json_array_items "${INPUT}" "aliases")

# ── Build -d flag list ───────────────────────────────────────────────────────
D_FLAGS=(-d "${DOMAIN}")
for a in "${ALIASES[@]}"; do
    D_FLAGS+=(-d "${a}")
done

mkdir -p "${CERT_BASE}" /var/log/onoxsoft 2>/dev/null || true

CERT_PATH=""
KEY_PATH=""
CHAIN_PATH=""
BACKEND=""

# ─── Try acme.sh first ───────────────────────────────────────────────────────
if [[ -n "${ACME_BIN}" && -x "${ACME_BIN}" ]]; then
    onx_log "trying acme.sh for ${DOMAIN} (aliases: ${#ALIASES[@]})"
    ACME_HOME_DIR="$(dirname "${ACME_BIN}")"

    # Apache vhost Alias eşleşmesi (vhost template'inde
    # "Alias /.well-known/acme-challenge /var/lib/letsencrypt/..." var)
    ACME_WEBROOT_BASE="/var/lib/letsencrypt/.well-known/acme-challenge"
    mkdir -p "${ACME_WEBROOT_BASE}" 2>/dev/null
    chmod 0755 /var/lib/letsencrypt /var/lib/letsencrypt/.well-known "${ACME_WEBROOT_BASE}" 2>/dev/null || true

    # --server letsencrypt explicit (ZeroSSL rate-limit agresif)
    if "${ACME_BIN}" --issue --server letsencrypt --home "${ACME_HOME_DIR}" \
        "${D_FLAGS[@]}" -w /var/lib/letsencrypt --force \
        > "${ACME_LOG}" 2>&1; then
        ACME_EC=0
    else
        ACME_EC=$?
    fi

    # acme.sh exit 2 = already up-to-date (treat as success, run install-cert)
    if [[ "${ACME_EC}" -eq 0 || "${ACME_EC}" -eq 2 ]]; then
        CERT_INSTALL_DIR="${CERT_BASE}/${DOMAIN}"
        mkdir -p "${CERT_INSTALL_DIR}"
        CERT_FILE="${CERT_INSTALL_DIR}/fullchain.pem"
        KEY_FILE="${CERT_INSTALL_DIR}/privkey.pem"
        CHAIN_FILE="${CERT_INSTALL_DIR}/chain.pem"

        if "${ACME_BIN}" --install-cert -d "${DOMAIN}" \
            --cert-file       "${CERT_INSTALL_DIR}/cert.pem" \
            --key-file        "${KEY_FILE}" \
            --fullchain-file  "${CERT_FILE}" \
            --ca-file         "${CHAIN_FILE}" \
            >> "${ACME_LOG}" 2>&1; then
            CERT_PATH="${CERT_FILE}"
            KEY_PATH="${KEY_FILE}"
            CHAIN_PATH="${CHAIN_FILE}"
            BACKEND="acme.sh"
        fi
    fi
fi

# ─── Fallback to certbot ─────────────────────────────────────────────────────
if [[ -z "${CERT_PATH}" ]] && command -v certbot >/dev/null 2>&1; then
    onx_log "falling back to certbot for ${DOMAIN}"
    CB_ARGS=(certonly --webroot -w "${WEBROOT}" --non-interactive --agree-tos --register-unsafely-without-email --keep-until-expiring)
    for a in "${ALIASES[@]}"; do
        CB_ARGS+=(-d "${a}")
    done
    CB_ARGS+=(-d "${DOMAIN}")

    if certbot "${CB_ARGS[@]}" > "${CB_LOG}" 2>&1; then
        CERT_PATH="/etc/letsencrypt/live/${DOMAIN}/fullchain.pem"
        KEY_PATH="/etc/letsencrypt/live/${DOMAIN}/privkey.pem"
        CHAIN_PATH="/etc/letsencrypt/live/${DOMAIN}/chain.pem"
        BACKEND="certbot"
    fi
fi

# ─── Validate result ─────────────────────────────────────────────────────────
if [[ -z "${CERT_PATH}" || ! -f "${CERT_PATH}" ]]; then
    ACME_ERR=$(tail -c 1024 "${ACME_LOG}" 2>/dev/null | tr -d '\000' || echo "")
    CB_ERR=$(tail -c 1024 "${CB_LOG}" 2>/dev/null | tr -d '\000' || echo "")
    [[ -z "${ACME_ERR}" ]] && ACME_ERR="(no acme.sh log)"
    [[ -z "${CB_ERR}"   ]] && CB_ERR="(no certbot log)"
    onx_die 3 "ssl issue failed for ${DOMAIN}; acme: ${ACME_ERR}; certbot: ${CB_ERR}"
fi

# ─── SELinux label ───────────────────────────────────────────────────────────
chcon -t cert_t "${CERT_PATH}" 2>/dev/null || true
chcon -t cert_t "${KEY_PATH}" 2>/dev/null || true
[[ -n "${CHAIN_PATH}" && -f "${CHAIN_PATH}" ]] && \
    chcon -t cert_t "${CHAIN_PATH}" 2>/dev/null || true

# ─── Success ─────────────────────────────────────────────────────────────────
onx_log "ssl-issue success: ${DOMAIN} backend=${BACKEND} cert=${CERT_PATH}"

onx_json_out \
    "domain"     "${DOMAIN}" \
    "cert_path"  "${CERT_PATH}" \
    "key_path"   "${KEY_PATH}" \
    "chain_path" "${CHAIN_PATH}" \
    "backend"    "${BACKEND}"
