#!/usr/bin/env bash
# rizoma-mail — installer / updater.
# Usage:
#   curl -fsSL https://repo.rizomarl.com/mail/install.sh | sudo bash
#   curl -fsSL https://repo.rizomarl.com/mail/install.sh | sudo bash -s -- --version 0.1.0
#   curl -fsSL https://repo.rizomarl.com/mail/install.sh | sudo bash -s -- --check
#   curl -fsSL https://repo.rizomarl.com/mail/install.sh | sudo bash -s -- --channel beta
#
# Installs the maild binary + systemd unit. Mail data dirs are created
# maild-owned. Does NOT configure domains/accounts/certs — see README
# (maild domain add / dkim show / account add) after install.
set -euo pipefail

REPO="${RIZOMA_MAIL_REPO:-https://repo.rizomarl.com/mail}"
CHANNEL="stable"
PIN_VERSION=""
CHECK_ONLY=0
FORCE=0
VERBOSE=0
BIN_DIR="${MAILD_BIN_DIR:-/opt/rizoma-mail/bin}"
ENV_FILE="${MAILD_ENV_FILE:-/etc/rizoma/maild.env}"
SYSTEMD_DIR="${MAILD_SYSTEMD_DIR:-/etc/systemd/system}"
DATA_DIR="${MAILD_DATA_DIR:-/var/lib/rizoma-mail}"
MAIL_DIR="${MAILD_MAIL_DIR:-/var/mail/rizoma}"
LOG_DIR="${MAILD_LOG_DIR:-/var/log/rizoma-mail}"

while [ $# -gt 0 ]; do
  case "$1" in
    --channel) CHANNEL="$2"; shift 2 ;;
    --version) PIN_VERSION="$2"; shift 2 ;;
    --check) CHECK_ONLY=1; shift ;;
    --force) FORCE=1; shift ;;
    --verbose) VERBOSE=1; shift ;;
    *) echo "unknown arg: $1 (want --channel|--version|--check|--force|--verbose)" >&2; exit 1 ;;
  esac
done

need() { command -v "$1" >/dev/null 2>&1 || { echo "missing: $1" >&2; exit 1; }; }
need curl; need sha256sum; need systemctl

arch="$(uname -m)"
case "$arch" in
  x86_64) arch=amd64 ;;
  aarch64|arm64) arch=arm64 ;;
  *) echo "unsupported arch: $arch" >&2; exit 1 ;;
esac

remote_version() { curl -fsSL "$REPO/version.json" | python3 -c 'import json,sys;print(json.load(sys.stdin)["version"])'; }
local_version() {
  [ -x "$BIN_DIR/maild" ] && "$BIN_DIR/maild" --version 2>/dev/null | awk '{print $2}' || echo "none"
}

RV="$(remote_version)"
LV="$(local_version)"
[ "$VERBOSE" = 1 ] && echo "channel=$CHANNEL arch=$arch local=$LV remote=$RV"

if [ "$CHECK_ONLY" = 1 ]; then
  [ "$LV" = "$RV" ] && echo "up to date" || echo "update available: $LV -> $RV"
  exit 0
fi

TARGET="${PIN_VERSION:-$RV}"
[ -n "$TARGET" ] || { echo "cannot resolve target version" >&2; exit 1; }
if [ "$LV" = "$TARGET" ] && [ "$FORCE" != 1 ]; then
  if [ -f "$SYSTEMD_DIR/rizoma-maild.service" ] && systemctl is-active --quiet rizoma-maild 2>/dev/null; then
    echo "already at $TARGET (service active)"
    exit 0
  fi
  echo "version $TARGET present but installation incomplete — completing"
fi

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT
cd "$tmp"
echo "==> download maild-$TARGET-linux-$arch"
curl -fsSL -O "$REPO/$CHANNEL/maild-$TARGET-linux-$arch"
curl -fsSL "$REPO/$CHANNEL/SHA256SUMS" -o SHA256SUMS
echo "==> verify checksum"
grep "maild-$TARGET-linux-$arch" SHA256SUMS | sha256sum -c -
if curl -fsSL -O "$REPO/$CHANNEL/SHA256SUMS.sig" 2>/dev/null; then
  echo "==> verify gpg signature"
  if [ -f "$REPO/keys/rizoma-archive-keyring.gpg" ] || curl -fsSL "$REPO/keys/rizoma-archive-keyring.gpg" -o /tmp/rizoma-mail-repo.gpg 2>/dev/null; then
    keyring=/tmp/rizoma-mail-repo.gpg
    [ -f "$REPO/keys/rizoma-archive-keyring.gpg" ] && keyring="$REPO/keys/rizoma-archive-keyring.gpg"
    gpg --no-default-keyring --keyring "$keyring" --verify SHA256SUMS.sig SHA256SUMS
  else
    echo "(no repo key published; checksum verified, signature present but unchecked)"
  fi
fi

id maild >/dev/null 2>&1 || useradd -r -s /usr/sbin/nologin maild
mkdir -p "$BIN_DIR"

if [ -x "$BIN_DIR/maild" ]; then
  bak="$BIN_DIR/maild.bak-$(date +%Y%m%d-%H%M%S)"
  echo "==> backup current binary -> $bak"
  cp -p "$BIN_DIR/maild" "$bak"
fi
echo "==> install $TARGET"
install -o maild -g maild -m 0755 "maild-$TARGET-linux-$arch" "$BIN_DIR/maild"

# Directories the daemon writes (ProtectSystem=full in the unit requires
# them to exist, and maild runs as the maild user).
for d in "$DATA_DIR" "$MAIL_DIR" "$LOG_DIR" "$DATA_DIR/acme-cache"; do
  mkdir -p "$d"
  chown maild:maild "$d" 2>/dev/null || true
  if [ "$d" = "$DATA_DIR/acme-cache" ]; then
    chmod 0700 "$d" 2>/dev/null || true
  else
    chmod 0750 "$d" 2>/dev/null || true
  fi
done

# Default env file (operator edits paths/ports/hostname/certs here).
if [ ! -f "$ENV_FILE" ]; then
  mkdir -p "$(dirname "$ENV_FILE")"
  cat > "$ENV_FILE" <<EOF
RIZOMA_MAIL_BIND=0.0.0.0
RIZOMA_MAIL_DB=$DATA_DIR/mail.db
RIZOMA_MAIL_MAILDIR=$MAIL_DIR
RIZOMA_MAIL_HOSTNAME=mx.local
# TLS identity: either static files...
#RIZOMA_MAIL_TLS_CERT=/etc/rizoma/maild-tls/mx.example.com.crt
#RIZOMA_MAIL_TLS_KEY=/etc/rizoma/maild-tls/mx.example.com.key
# ...or native ACME (no Caddy/certbot/cron). Authoritative when enabled:
# obtains + auto-renews a public cert for HOSTNAME via HTTP-01 on port 80.
#RIZOMA_MAIL_ACME_ENABLE=1
#RIZOMA_MAIL_ACME_DIRECTORY=https://acme-staging-v02.api.letsencrypt.org/directory
#RIZOMA_MAIL_ACME_CACHE=$DATA_DIR/acme-cache
#RIZOMA_MAIL_ACME_EMAIL=postmaster@example.com
# SRS for forwarded mail (aliases to external addresses). Generated below
# on fresh installs; without it external forwarding is refused (fail closed).
EOF
  chmod 0600 "$ENV_FILE"
  chown maild:maild "$ENV_FILE" 2>/dev/null || true
  echo "==> wrote default $ENV_FILE (set HOSTNAME + TLS cert/key before serving publicly)"
fi

# SRS secret: forwarding signatures need a stable secret. Generate once;
# never rotate silently (old rewritten addresses carry a TTL anyway).
if ! grep -q "RIZOMA_MAIL_SRS_SECRET=" "$ENV_FILE" 2>/dev/null; then
  if command -v openssl >/dev/null 2>&1; then
    SRS_SECRET=$(openssl rand -hex 32)
  else
    SRS_SECRET=$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')
  fi
  {
    echo ""
    echo "# SRS secret (auto-generated $(date -u +%F); keep stable across reinstalls)"
    echo "RIZOMA_MAIL_SRS_SECRET=$SRS_SECRET"
  } >> "$ENV_FILE"
  echo "==> generated RIZOMA_MAIL_SRS_SECRET in $ENV_FILE"
fi

if [ ! -f "$SYSTEMD_DIR/rizoma-maild.service" ]; then
  echo "==> installing systemd unit"
  curl -fsSL "$REPO/rizoma-maild.service" -o "$SYSTEMD_DIR/rizoma-maild.service" 2>/dev/null || {
    echo "unit not on repo; copy packaging/systemd/rizoma-maild.service manually" >&2
  }
  systemctl daemon-reload
  systemctl enable rizoma-maild >/dev/null 2>&1 || true
fi

# Daily DMARC aggregate report sender (oneshot + timer). Enabled on fresh
# installs; existing installs: copy the two files from the repo and
# `systemctl enable --now rizoma-maild-dmarc-reports.timer`.
if [ ! -f "$SYSTEMD_DIR/rizoma-maild-dmarc-reports.timer" ]; then
  echo "==> installing dmarc-reports timer"
  curl -fsSL "$REPO/rizoma-maild-dmarc-reports.service" -o "$SYSTEMD_DIR/rizoma-maild-dmarc-reports.service" 2>/dev/null || {
    echo "timer unit not on repo; copy packaging/systemd/rizoma-maild-dmarc-reports.* manually" >&2
  }
  curl -fsSL "$REPO/rizoma-maild-dmarc-reports.timer" -o "$SYSTEMD_DIR/rizoma-maild-dmarc-reports.timer" 2>/dev/null || true
  systemctl daemon-reload
  systemctl enable rizoma-maild-dmarc-reports.timer >/dev/null 2>&1 || true
fi

echo "==> restart"
systemctl restart rizoma-maild
echo "==> waiting for service"
for i in $(seq 1 30); do
  if systemctl is-active --quiet rizoma-maild 2>/dev/null; then
    echo "service active"
    break
  fi
  if [ "$i" = 30 ]; then
    echo "service did not become active; see journalctl -u rizoma-maild" >&2
    systemctl is-active rizoma-maild || true
    exit 1
  fi
  sleep 2
done

echo "==> health"
ok=0
for port in 25 587 993; do
  if timeout 3 bash -c "echo > /dev/tcp/127.0.0.1/$port" 2>/dev/null; then
    echo "port $port listening"
    ok=1
  fi
done
[ "$ok" = 1 ] || { echo "no mail ports listening; see journalctl -u rizoma-maild" >&2; exit 1; }
"$BIN_DIR/maild" --version
cat <<'EOF'

Next steps (see README):
  1. Edit /etc/rizoma/maild.env (HOSTNAME, TLS cert/key), restart.
  2. maild domain add <domain> && maild dkim show <domain>  # DNS TXT
  3. RIZOMA_MAIL_ACCOUNT_PASS=... maild account add <user@domain>
EOF
