#!/usr/bin/env bash
#
# onx-mailserver-install — Mail server (MTA) adapter kur.
#
# Postfix (varsayılan/önerilen — Türkiye sunucularında dominant) veya
# Exim (cPanel migration uyumluluğu için) kurulumu yapar. Pattern olarak
# onx-webserver-install ile aynı multi-driver dispatch — driver agnostic
# scaffolding sayesinde gelecekte sendmail/opensmtpd eklemek trivial.
#
# Input (stdin JSON):
#   {
#     "driver":     "postfix" | "exim",        # zorunlu
#     "package":    "postfix" | "exim",        # ops (driver'dan türetilir)
#     "service":    "postfix" | "exim",        # ops (driver'dan türetilir)
#     "queue_dir":  "/var/spool/postfix",      # ops (override için)
#     "config_dir": "/etc/postfix"             # ops (override için)
#   }
#
# Output (stdout JSON):
#   {
#     "ok":        true,
#     "installed": true,
#     "driver":    "exim",
#     "version":   "4.96",
#     "service":   "exim",
#     "message":   "Exim kuruldu (henüz aktif değil). Aktif etmek için Switch kullanın."
#   }
#
# NOT: Bu script SADECE paketi kurar + systemctl enable yapar. ASLA
# start ETMEZ — sistemde Postfix port 25'i tutuyor olabilir. Aktivasyon
# `onx-mailserver-switch` ile yapılır (eski stop + port serbest + yeni start).
#
# Pattern: onx-webserver-install ile birebir aynı yaklaşım — install →
# enable → switch akışı. AlmaLinux 9 + RHEL/Debian dual support.
#
# Bağımlılıklar:
#   - jq                  (stdin JSON parse)
#   - dnf/apt-get         (paket yöneticisi)
#   - systemctl           (service enable/disable)
#
# Exit kodları (_lib/common.sh'a uyumlu):
#   0 = success, 1 = invalid input, 2 = preflight fail, 3 = install fail

set -uo pipefail

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

require_root

# ─── Input parse ─────────────────────────────────────────────────────────────
INPUT="$(cat 2>/dev/null || echo '{}')"
onx_require_json "$INPUT"

driver="$(onx_json_get "$INPUT" driver)"
package="$(onx_json_get "$INPUT" package)"
service="$(onx_json_get "$INPUT" service)"
config_dir="$(onx_json_get "$INPUT" config_dir)"

[[ -z "$driver" ]] && onx_die 1 "driver required (postfix|exim)"

# Driver'dan varsayılanları türet (panel göndermese de güvenli)
case "$driver" in
    postfix)
        [[ -z "$package" ]]    && package="postfix"
        [[ -z "$service" ]]    && service="postfix"
        [[ -z "$config_dir" ]] && config_dir="/etc/postfix"
        ;;
    exim)
        [[ -z "$package" ]]    && package="exim"
        [[ -z "$service" ]]    && service="exim"
        [[ -z "$config_dir" ]] && config_dir="/etc/exim"
        ;;
    *)
        onx_die 1 "unknown driver '$driver' (postfix|exim only)"
        ;;
esac

# ─── OS detect ───────────────────────────────────────────────────────────────
OS_FAMILY="rhel"
PKG_MGR="dnf"
if [[ -f /etc/debian_version ]]; then
    OS_FAMILY="debian"
    PKG_MGR="apt-get"
fi

onx_log "mailserver-install start driver=${driver} pkg=${package} os=${OS_FAMILY}"

# ─── Driver-specific install fonksiyonları ───────────────────────────────────

install_postfix() {
    # Postfix RHEL/Debian her ikisinde de stock repo'da var.
    # v83.8: --setopt=*.skip_if_unavailable=True — broken 3rd-party repo
    # (örn. rspamd.com timeout) tüm dnf çalışmasını öldürmesin.
    # Log temp dosyaya — fail durumda stderr'e dump (JSON output kirletme).
    local log="/tmp/onx-mailserver-pkg-$$.log"
    local rc=0
    if [[ "$OS_FAMILY" == "rhel" ]]; then
        dnf install -y --setopt='*.skip_if_unavailable=True' \
            postfix cyrus-sasl cyrus-sasl-plain > "$log" 2>&1 || rc=$?
    else
        DEBIAN_FRONTEND=noninteractive apt-get install -y \
            postfix postfix-mysql libsasl2-modules > "$log" 2>&1 || rc=$?
    fi
    [[ $rc -ne 0 ]] && { cat "$log" >&2; onx_log "postfix install fail rc=$rc tail=$(tail -5 "$log" | tr '\n' '|')"; }
    rm -f "$log"
    return $rc
}

install_exim() {
    # Exim RHEL 9'da EPEL gerektirir; Debian'da stock repo'da var.
    # ÖNEMLİ: Port 25 collision'ı önlemek için Exim'i kurarken Postfix
    # ZATEN ÇALIŞIYORSA installer otomatik alternative ayarı YAPAR ama
    # service start ETMEYİZ. Switch sırasında atomic port handoff olur.
    #
    # v83.8: --setopt=*.skip_if_unavailable=True flagi 3rd party repo
    # timeout'larında (rspamd.com unreachable vb.) dnf'nin tüm kuruluma
    # geri çekilmesini önler. Plus stderr no-longer silenced (önceden
    # >/dev/null 2>&1 ile gizleniyordu, debug imkansızdı).
    local install_rc=0
    local log="/tmp/onx-mailserver-pkg-$$.log"
    if [[ "$OS_FAMILY" == "rhel" ]]; then
        # EPEL — AlmaLinux 9 / RHEL 9 / Rocky 9
        if ! rpm -q epel-release >/dev/null 2>&1; then
            dnf install -y --setopt='*.skip_if_unavailable=True' epel-release > "$log" 2>&1 || {
                cat "$log" >&2
                onx_log "mailserver-install: EPEL kurulamadı (Exim için gerekli) — log tail: $(tail -3 "$log" | tr '\n' '|')"
                rm -f "$log"
                return 2
            }
        fi
        # Exim install — broken repolar skip (rspamd.com timeout fix v83.8)
        dnf install -y --setopt='*.skip_if_unavailable=True' exim > "$log" 2>&1 || install_rc=$?
    else
        DEBIAN_FRONTEND=noninteractive apt-get install -y exim4-daemon-light > "$log" 2>&1 || install_rc=$?
    fi

    if [[ $install_rc -ne 0 ]]; then
        cat "$log" >&2
        onx_log "mailserver-install: exim install FAILED rc=${install_rc} tail: $(tail -5 "$log" | tr '\n' '|')"
        rm -f "$log"
        return $install_rc
    fi
    rm -f "$log"

    # ── Minimal Exim config — Postfix-uyumlu virtual domain + Dovecot LMTP ──
    # cPanel migration sonrası /etc/exim/virtual_domains varsa korur. Yoksa
    # boş bir dosya yaratır (admin ileride doldurur). Dovecot zaten kurulu
    # olduğu varsayımı — install.sh chain'i Dovecot'u her hâlükârda kurmuş
    # olur, çünkü mailbox auth oraya bağlı.
    mkdir -p "${config_dir}"
    touch "${config_dir}/virtual_domains"
    chmod 644 "${config_dir}/virtual_domains"

    # Vmail kullanıcısı kontrolü — install.sh'in oluşturduğunu varsayar.
    # Yoksa Exim local_delivery transport'u 5775 (no such user) verir.
    if ! getent passwd vmail >/dev/null 2>&1; then
        onx_log "mailserver-install: vmail user yok (Dovecot install.sh çalışmamış olabilir)"
    fi

    # Minimal Exim config sadece config_dir'de exim.conf YOKSA yaz — RPM
    # default'unu (vendor file) override etmek istemiyoruz, sadece scaffold.
    local exim_cf="${config_dir}/exim.conf"
    if [[ ! -f "${exim_cf}" ]] || ! grep -q 'ONOX-managed' "${exim_cf}" 2>/dev/null; then
        # RPM default'u zaten varsa yedekle
        if [[ -f "${exim_cf}" ]]; then
            cp -a "${exim_cf}" "${exim_cf}.dist-$(date +%s)"
        fi

        cat > "${exim_cf}" <<'EXIMCONF'
# ─────────────────────────────────────────────────────────────────────────
# ONOX-managed Exim configuration — minimal scaffold (driver agnostic)
# Generated by onx-mailserver-install. Edit via Admin → Mail Server → Exim.
# Pattern: cPanel-uyumlu virtual_domains + Dovecot LMTP delivery
# ─────────────────────────────────────────────────────────────────────────

# ─── Main settings ────────────────────────────────────────────────────────
domainlist  local_domains      = @ : localhost
domainlist  relay_to_domains   = lsearch;/etc/exim/virtual_domains
hostlist    relay_from_hosts   = localhost : 127.0.0.1 : ::1

# panel hostname (install.sh'den gelir; FQDN olmalı)
primary_hostname = ${env{HOSTNAME}{$value}{localhost}}

acl_smtp_rcpt        = acl_check_rcpt
acl_smtp_data        = acl_check_data

# vmail user — Maildir delivery target
exim_user            = exim
exim_group           = exim
never_users          = root

# Submission port 587 — kullanıcı authenticated SMTP (Roundcube/Mail clients)
daemon_smtp_ports    = 25 : 587
tls_advertise_hosts  = *

# DKIM signing hook (Rspamd / opendkim dış'ardan yapacaksa boş bırak)
# dkim_domain          = ${sender_address_domain}
# dkim_selector        = default
# dkim_private_key     = /etc/opendkim/keys/${dkim_domain}/default.private

# ─── ACL ─────────────────────────────────────────────────────────────────
begin acl

acl_check_rcpt:
    accept  hosts        = :
    deny    domains      = +local_domains
            local_parts  = ^[.] : ^.*[@%!/|]
    accept  local_parts  = postmaster
            domains      = +local_domains
    accept  domains      = +local_domains
            endpass
            verify       = recipient
    accept  domains      = +relay_to_domains
            endpass
            verify       = recipient
    accept  hosts        = +relay_from_hosts
    accept  authenticated = *
    deny    message      = relay not permitted

acl_check_data:
    # Rspamd hook (kuruluysa)
    # warn    spam        = nobody
    accept

# ─── Routers ─────────────────────────────────────────────────────────────
begin routers

# Local domains → Dovecot LMTP (mailbox tablosu Dovecot SQL backend'inde)
dovecot_lmtp:
    driver           = accept
    domains          = +relay_to_domains
    transport        = dovecot_lmtp_transport

# Diğer her şey → MX lookup (giden mail)
dnslookup:
    driver           = dnslookup
    domains          = ! +local_domains : ! +relay_to_domains
    transport        = remote_smtp
    ignore_target_hosts = 0.0.0.0 : 127.0.0.0/8
    no_more

# ─── Transports ──────────────────────────────────────────────────────────
begin transports

dovecot_lmtp_transport:
    driver           = lmtp
    socket           = /var/run/dovecot/lmtp
    user             = exim
    rcpt_include_affixes = true

remote_smtp:
    driver           = smtp
    helo_data        = $primary_hostname
    # TLS — STARTTLS dış sunucularla
    hosts_require_tls = *

# ─── Retry rules ────────────────────────────────────────────────────────
begin retry
*  *  F,2h,15m; G,16h,1h,1.5; F,4d,8h

# ─── Authenticators (587 submission) ────────────────────────────────────
begin authenticators
# Dovecot SASL üzerinden auth (mailbox tablosu Dovecot'ta)
dovecot_login:
    driver         = dovecot
    public_name    = LOGIN
    server_socket  = /var/run/dovecot/auth-client
    server_set_id  = $auth1

dovecot_plain:
    driver         = dovecot
    public_name    = PLAIN
    server_socket  = /var/run/dovecot/auth-client
    server_set_id  = $auth1
EXIMCONF
    fi

    # Postfix aktifse — Exim'i ENABLE etme, sadece kur. Switch script atomic
    # handoff yapacak. (Aynı anda iki MTA port 25'i tutamaz.)
    if systemctl is-active --quiet postfix 2>/dev/null; then
        onx_log "mailserver-install: Postfix aktif — Exim enabled değil (Switch ile)"
        # Sistemd'de exim disabled bırak — admin Switch'e basana kadar uyusun
        systemctl disable exim >/dev/null 2>&1 || true
    fi

    return 0
}

# ─── Dispatch ────────────────────────────────────────────────────────────────
case "$driver" in
    postfix) install_postfix ;;
    exim)    install_exim ;;
esac
install_rc=$?

if [[ $install_rc -ne 0 ]]; then
    onx_log "mailserver-install FAIL driver=${driver} rc=${install_rc}"
    onx_die 3 "Paket yüklenemedi (driver=${driver}, pkg=${package}, rc=${install_rc}). Çevrimiçi repo erişimini ve EPEL kurulumunu kontrol edin."
fi

# ─── Version detect ──────────────────────────────────────────────────────────
version="unknown"
case "$driver" in
    postfix)
        # postconf -d mail_version → "mail_version = 3.5.8"
        version="$(postconf -d mail_version 2>/dev/null | awk -F'= *' '{print $2}' | head -1)"
        [[ -z "$version" ]] && version="$(rpm -q --qf '%{VERSION}' postfix 2>/dev/null)"
        ;;
    exim)
        # exim -bV ilk satır: "Exim version 4.96 #2 built ..."
        version="$(exim -bV 2>/dev/null | head -1 | grep -oE '[0-9]+\.[0-9]+(\.[0-9]+)?' | head -1)"
        [[ -z "$version" ]] && version="$(rpm -q --qf '%{VERSION}' exim 2>/dev/null)"
        ;;
esac
[[ -z "$version" ]] && version="unknown"

# ─── systemd enable (ama BAŞLATMA) ───────────────────────────────────────────
# Switch akışı stop+start handoff yapacak. Burada sadece marker.
# Postfix zaten aktifse Exim'i enable etme (boot'ta çakışır).
if [[ "$driver" == "postfix" ]] && ! systemctl is-active --quiet exim 2>/dev/null; then
    systemctl enable "$service" >/dev/null 2>&1 || true
fi

onx_log "mailserver-install OK driver=${driver} version=${version}"

# ─── Output ──────────────────────────────────────────────────────────────────
note_msg=""
if [[ "$driver" == "exim" ]]; then
    note_msg="Exim kuruldu (henüz aktif değil). cPanel migration için önerilir; yeni kurulumlarda Postfix tercih edin."
else
    note_msg="Postfix kuruldu (henüz aktif değil). Aktif etmek için Switch kullanın."
fi

onx_json_out \
    ok        true \
    installed true \
    driver    "$driver" \
    version   "$version" \
    service   "$service" \
    message   "$note_msg"
