#!/usr/bin/env bash
#
# Install Stalwart mail server as a hardened host systemd service on the AX41.
# Run AFTER bootstrap.sh (and ideally after k3s registration, so cert-sync can
# immediately pull the real cert). Idempotent — safe to re-run to upgrade.
#
#   sudo ./install.sh
#
# What it does: creates the stalwart user + /opt/stalwart layout, downloads a
# pinned Stalwart binary, installs config.toml + the secrets EnvironmentFile,
# drops a self-signed bootstrap cert (replaced later by cert-sync), and installs
# the systemd units (mail service + cert-sync service/timer).

set -euo pipefail

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
info()  { echo -e "${BLUE}[INFO]${NC}  $*"; }
ok()    { echo -e "${GREEN}[OK]${NC}    $*"; }
warn()  { echo -e "${YELLOW}[WARN]${NC}  $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
HOST_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
CONFIG_FILE="${CONFIG_FILE:-$HOST_DIR/config.env}"

PREFIX="/opt/stalwart"
STALWART_REPO="${STALWART_REPO:-stalwartlabs/mail-server}"

if [[ $EUID -ne 0 ]]; then
    error "Run as root."
    exit 1
fi
if [[ ! -f "$CONFIG_FILE" ]]; then
    error "Missing $CONFIG_FILE — fill in the STALWART_* values first."
    exit 1
fi
# shellcheck disable=SC1090
source "$CONFIG_FILE"

: "${STALWART_ADMIN_PASSWORD:?STALWART_ADMIN_PASSWORD required (openssl rand -hex 24)}"
: "${STALWART_WEBHOOK_SECRET:?STALWART_WEBHOOK_SECRET required (openssl rand -hex 32)}"
: "${STALWART_VERSION:=latest}"

# ── Step 1: user + directory layout ────────────────────────────────────────
info "Step 1: stalwart user + ${PREFIX} layout..."
if ! id -u stalwart >/dev/null 2>&1; then
    useradd --system --home-dir "$PREFIX" --shell /usr/sbin/nologin stalwart
fi
install -d -o stalwart -g stalwart -m 0750 "$PREFIX" "$PREFIX/bin" "$PREFIX/data" "$PREFIX/logs"
install -d -o stalwart -g stalwart -m 0750 "$PREFIX/etc" "$PREFIX/etc/tls"
ok "Layout ready."

# ── Step 2: download the Stalwart binary ───────────────────────────────────
info "Step 2: fetching Stalwart binary (${STALWART_REPO}@${STALWART_VERSION})..."
arch="$(uname -m)"
case "$arch" in
    x86_64)  target="x86_64-unknown-linux-gnu" ;;
    aarch64) target="aarch64-unknown-linux-gnu" ;;
    *) error "Unsupported arch: $arch"; exit 1 ;;
esac

if [[ "$STALWART_VERSION" == "latest" ]]; then
    api="https://api.github.com/repos/${STALWART_REPO}/releases/latest"
    warn "Using 'latest' — pin STALWART_VERSION to a tag in config.env after this install."
else
    api="https://api.github.com/repos/${STALWART_REPO}/releases/tags/${STALWART_VERSION}"
fi

asset_url="$(curl -fsSL "$api" \
    | grep -oE "https://[^\"]+${target}[^\"]+\.tar\.gz" \
    | head -n1)"
if [[ -z "$asset_url" ]]; then
    error "Could not find a ${target} .tar.gz asset in ${STALWART_REPO}@${STALWART_VERSION}."
    error "Check the release assets or set STALWART_REPO/STALWART_VERSION."
    exit 1
fi

tmp="$(mktemp -d)"; trap 'rm -rf "$tmp"' EXIT
info "Downloading $asset_url"
curl -fsSL "$asset_url" -o "$tmp/stalwart.tar.gz"
tar -xzf "$tmp/stalwart.tar.gz" -C "$tmp"
bin="$(find "$tmp" -type f \( -name stalwart -o -name stalwart-mail \) | head -n1)"
if [[ -z "$bin" ]]; then
    error "No 'stalwart'/'stalwart-mail' binary found in the archive."
    exit 1
fi
systemctl stop stalwart-mail 2>/dev/null || true
install -o stalwart -g stalwart -m 0755 "$bin" "$PREFIX/bin/stalwart"
ok "Installed $("$PREFIX/bin/stalwart" --version 2>/dev/null || echo 'stalwart binary')."

# ── Step 3: config + secrets EnvironmentFile ───────────────────────────────
info "Step 3: config.toml + secrets env..."
install -o stalwart -g stalwart -m 0640 "$SCRIPT_DIR/config.toml" "$PREFIX/etc/config.toml"
umask 077
cat > "$PREFIX/etc/stalwart.env" <<EOF
# Generated by install.sh from config.env — DO NOT commit.
STALWART_ADMIN_PASSWORD=${STALWART_ADMIN_PASSWORD}
STALWART_WEBHOOK_SECRET=${STALWART_WEBHOOK_SECRET}
EOF
chown root:stalwart "$PREFIX/etc/stalwart.env"
chmod 0640 "$PREFIX/etc/stalwart.env"
ok "Config + secrets installed."

# ── Step 4: self-signed bootstrap cert (only if none yet) ──────────────────
if [[ ! -s "$PREFIX/etc/tls/cert.pem" ]]; then
    info "Step 4: generating self-signed bootstrap cert (cert-sync replaces it)..."
    openssl req -x509 -newkey rsa:2048 -nodes -days 3650 \
        -keyout "$PREFIX/etc/tls/key.pem" \
        -out "$PREFIX/etc/tls/cert.pem" \
        -subj "/CN=mail.dezky.eu" >/dev/null 2>&1
    chown stalwart:stalwart "$PREFIX/etc/tls/"*.pem
    chmod 0644 "$PREFIX/etc/tls/cert.pem"; chmod 0640 "$PREFIX/etc/tls/key.pem"
    ok "Bootstrap cert in place."
else
    ok "Step 4: TLS cert already present — keeping it."
fi

# ── Step 5: cert-sync + systemd units ──────────────────────────────────────
info "Step 5: installing cert-sync + systemd units..."
install -o root -g root -m 0755 "$SCRIPT_DIR/cert-sync.sh" "$PREFIX/cert-sync.sh"
install -m 0644 "$SCRIPT_DIR/stalwart-mail.service"      /etc/systemd/system/stalwart-mail.service
install -m 0644 "$SCRIPT_DIR/stalwart-cert-sync.service" /etc/systemd/system/stalwart-cert-sync.service
install -m 0644 "$SCRIPT_DIR/stalwart-cert-sync.timer"   /etc/systemd/system/stalwart-cert-sync.timer
systemctl daemon-reload
systemctl enable --now stalwart-mail.service
systemctl enable --now stalwart-cert-sync.timer
ok "Services enabled."

# Try an immediate cert sync (no-op until cert-manager has issued the secret)
"$PREFIX/cert-sync.sh" || true

echo ""
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║                 Stalwart installed & running                 ║"
echo "╚══════════════════════════════════════════════════════════════╝"
systemctl --no-pager --lines=0 status stalwart-mail || true
echo ""
warn "Follow-ups:"
warn "  • PTR/rDNS for the server IP MUST be 'mail.dezky.eu' (Hetzner Robot)."
warn "  • Publish DNS at simply.com: MX → mail.dezky.eu, SPF, DMARC; per-domain"
warn "    DKIM records come from Stalwart's dnsZoneFile via platform-api."
warn "  • platform-api (k3s) env:  STALWART_API_URL=http://<node-ip>:8080"
warn "    STALWART_ADMIN_USER=admin  STALWART_ADMIN_PASSWORD=<same as here>"
warn "    STALWART_WEBHOOK_SECRET=<same as here>  STALWART_PROVISIONING_ENABLED=true"
