#!/usr/bin/env bash
# onx-cert-issue — Issue a Let's Encrypt certificate via acme.sh.
#
# Input (stdin JSON):
#   domain         string   Primary domain (e.g. "example.com")
#   alt_names      array    Subject Alternative Names (e.g. ["www.example.com",
#                           "mail.example.com", "webmail.example.com", ...])
#                           cPanel AutoSSL muadili: tek multi-SAN cert tüm
#                           sistem subdomain'lerini kapsayabilir (LE 100 SAN).
#   method         string   "http-01" (default) or "dns-01"
#   webroot        string   DocumentRoot for http-01 challenge (required for http-01)
#   force          bool     Force re-issue even if cert is not expiring (default: false)
#   account_email  string   ACME account email (autossl_settings.letsencrypt_email)
#   autossl        bool     Marker — log için (default: false)
#
# Output (stdout JSON):
#   {"cert_path":..., "key_path":..., "chain_path":..., "expires_at":..., "issuer":"Let's Encrypt"}
#
# Exit codes: 0=ok 1=invalid-input 2=preflight-fail 3=exec-fail
#
# Deployed to: /usr/local/onoxsoft/bin/onx-cert-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 /usr/local/onoxsoft/acme.sh kullanır,
# bazı eski kurulumlarda /etc/onoxsoft/acme.sh veya /root/.acme.sh.
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
export LE_WORKING_DIR="$(dirname "${ACME_BIN:-/usr/local/onoxsoft/acme.sh/acme.sh}")"

ACME_CERT_BASE="/etc/letsencrypt/live"
ACME_WEBROOT_BASE="/var/lib/letsencrypt/.well-known/acme-challenge"

# ── Read & parse stdin ───────────────────────────────────────────────────────
INPUT=$(cat)

onx_require_json "${INPUT}"

DOMAIN=$(onx_json_get "${INPUT}" "domain")
METHOD=$(onx_json_get "${INPUT}" "method" "http-01")
WEBROOT=$(onx_json_get "${INPUT}" "webroot" "")
FORCE=$(onx_json_get_bool "${INPUT}" "force" "false")
ACCOUNT_EMAIL=$(onx_json_get "${INPUT}" "account_email" "")
AUTOSSL=$(onx_json_get_bool "${INPUT}" "autossl" "false")

# ── Input validation ─────────────────────────────────────────────────────────
onx_validate_domain "${DOMAIN}"
[[ "${METHOD}" == "http-01" || "${METHOD}" == "dns-01" ]] || \
  onx_die 1 "method must be http-01 or dns-01, got: ${METHOD}"

if [[ "${METHOD}" == "http-01" && -z "${WEBROOT}" ]]; then
  onx_die 1 "webroot is required for http-01 challenge"
fi

# ── Preflight ────────────────────────────────────────────────────────────────
[[ -n "${ACME_BIN}" && -x "${ACME_BIN}" ]] || \
  onx_die 2 "acme.sh not found. Aranan: /usr/local/onoxsoft/acme.sh/, /etc/onoxsoft/acme.sh/, /root/.acme.sh/"

if [[ "${METHOD}" == "http-01" ]]; then
  [[ -d "${WEBROOT}" ]] || onx_die 2 "webroot directory not found: ${WEBROOT}"
  # Ensure acme-challenge directory is accessible
  mkdir -p "${ACME_WEBROOT_BASE}"
fi

# Install dir for the cert
CERT_INSTALL_DIR="${ACME_CERT_BASE}/${DOMAIN}"
mkdir -p "${CERT_INSTALL_DIR}"

# ── Build alt_names -d flags ─────────────────────────────────────────────────
DOMAIN_FLAGS=(-d "${DOMAIN}")
while IFS= read -r alt; do
  [[ -n "${alt}" ]] && DOMAIN_FLAGS+=(-d "${alt}")
done < <(onx_json_array_items "${INPUT}" "alt_names")

# ── Build acme.sh command ────────────────────────────────────────────────────
# --server letsencrypt explicit — ZeroSSL'in rate-limit'i agresif (24sa).
# Let's Encrypt: 50/hafta/account, IP başına 100/3saat. Production için stable.
# --home explicit — acme.sh /root/.acme.sh default'una düşmesin (install.sh
# /usr/local/onoxsoft/acme.sh kullanır, --home olmadan acme.sh kendi default
# home dizinine yazar ve cert'ler farklı yere düşer).
ACME_HOME_DIR="$(dirname "${ACME_BIN}")"
ACME_CMD=("${ACME_BIN}" --issue --server letsencrypt --home "${ACME_HOME_DIR}" "${DOMAIN_FLAGS[@]}")

if [[ "${METHOD}" == "http-01" ]]; then
  # Apache vhost'unda "Alias /.well-known/acme-challenge /var/lib/letsencrypt/..."
  # var; acme.sh webroot bu yolla aynı olmalı. Caller'ın geçtiği WEBROOT
  # (genelde DocumentRoot) override ediliyor — webroot != DocRoot kalsa
  # Apache Alias'ı dosyayı yanlış yerde arar → 404 challenge fail.
  ACME_CMD+=(--webroot /var/lib/letsencrypt)
else
  # dns-01 — caller must configure DNS provider env vars upstream
  ACME_CMD+=(--dns)
fi

[[ "${FORCE}" == "true" ]] && ACME_CMD+=(--force)

# Account email — acme.sh requires it on first call per ACA, idempotent after
if [[ -n "${ACCOUNT_EMAIL}" ]]; then
  "${ACME_BIN}" --register-account --accountemail "${ACCOUNT_EMAIL}" --server letsencrypt --home "${ACME_HOME_DIR}" 2>/dev/null || true
fi

# Apache vhost Alias eşleşmesi için ACME challenge dizinini hazırla
# (vhost template'inde "Alias /.well-known/acme-challenge /var/lib/letsencrypt/..."
#  var; acme.sh webroot bunla aynı olmalı)
mkdir -p "${ACME_WEBROOT_BASE}" 2>/dev/null
chmod 0755 /var/lib/letsencrypt /var/lib/letsencrypt/.well-known "${ACME_WEBROOT_BASE}" 2>/dev/null

# ── Issue certificate ────────────────────────────────────────────────────────
if [[ "${AUTOSSL}" == "true" ]]; then
  onx_log "AutoSSL: multi-SAN cert for ${DOMAIN} (${#DOMAIN_FLAGS[@]} domains incl. SANs)"
else
  onx_log "Running acme.sh issue for domain: ${DOMAIN}"
fi

# acme.sh'in KENDI exit kodunu yakala. set -e BARE komutta exit!=0'da scripti ABORT eder
# (acme.sh "already up-to-date" = exit 2 dahil!) -> "|| ACME_EC=$?" SART: hem kodu yakalar
# hem set -e'yi bu komut icin devre disi birakir. 0 = issued/skip; 2 = up-to-date. IKISI DE OK.
# (Eski hal "| tee" + sadece -ne 2 idi -> skip HATA sayilip vhost-SSL'e ulasilamiyordu.)
ACME_EC=0
"${ACME_CMD[@]}" >>"/var/log/onoxsoft/acme-${DOMAIN}.log" 2>&1 || ACME_EC=$?
if [[ "${ACME_EC}" -ne 0 && "${ACME_EC}" -ne 2 ]]; then
  onx_die 3 "acme.sh --issue failed for ${DOMAIN} (exit ${ACME_EC})"
fi

# ── Install cert to /etc/letsencrypt/live/<domain>/ ─────────────────────────
CERT_FILE="${CERT_INSTALL_DIR}/fullchain.pem"
KEY_FILE="${CERT_INSTALL_DIR}/privkey.pem"
CHAIN_FILE="${CERT_INSTALL_DIR}/chain.pem"

INSTALL_CMD=(
  "${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}"
  --reloadcmd       "systemctl reload httpd 2>/dev/null || true"
)

if ! "${INSTALL_CMD[@]}" 2>&1 | tee -a "/var/log/onoxsoft/acme-${DOMAIN}.log"; then
  onx_die 3 "acme.sh --install-cert failed for ${DOMAIN}"
fi

# ── Read expiry date from cert ───────────────────────────────────────────────
EXPIRES_AT=""
if command -v openssl >/dev/null 2>&1 && [[ -f "${CERT_FILE}" ]]; then
  EXPIRES_AT=$(openssl x509 -enddate -noout -in "${CERT_FILE}" 2>/dev/null \
    | sed 's/notAfter=//' || echo "")
fi

# ── Success ──────────────────────────────────────────────────────────────────
onx_json_out \
  "cert_path"  "${CERT_FILE}" \
  "key_path"   "${KEY_FILE}" \
  "chain_path" "${CHAIN_FILE}" \
  "expires_at" "${EXPIRES_AT}" \
  "issuer"     "Let's Encrypt"
