#!/bin/bash
# archivmail Updater
# Zieht die neueste Version aus Gitea, baut Frontend + Backend und startet Dienste neu.
#
# Aufruf (auf dem Server als root):
#   bash /opt/archivmail/update.sh
#
# Oder direkt von Gitea laden und ausführen:
#   curl -fsSL https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh | bash

set -euo pipefail

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
log()  { echo -e "${GREEN}[OK]${NC}  $*"; }
info() { echo -e "${BLUE}[..]${NC}  $*"; }
warn() { echo -e "${YELLOW}[!!]${NC}  $*"; }
die()  { echo -e "${RED}[ERR]${NC} $*" >&2; exit 1; }

[[ $EUID -eq 0 ]] || die "Bitte als root ausführen: sudo bash update.sh"

REPO_URL="${REPO_URL:-https://gitea.perlbach24.de/scripte/archivmail.git}"
INSTALL_DIR="/opt/archivmail"
BUILD_DIR="/opt/archivmail/_build"
FRONTEND_DIR="/opt/archivmail/web"
BIN_DIR="/opt/archivmail/bin"

echo ""
echo "  ╔══════════════════════════════════════╗"
echo "  ║     archivmail Updater               ║"
echo "  ╚══════════════════════════════════════╝"
echo ""

# ── Script selbst aktualisieren ──────────────────────────────────────────

SCRIPT_URL="https://gitea.perlbach24.de/scripte/archivmail/raw/branch/main/update.sh"
SELF="$INSTALL_DIR/update.sh"
if [[ -f "$SELF" ]] && command -v curl >/dev/null; then
  curl -fsSL "$SCRIPT_URL" -o "$SELF.new" 2>/dev/null && mv "$SELF.new" "$SELF" && chmod +x "$SELF" \
    && info "Script aktualisiert" || rm -f "$SELF.new"
fi

# ── Go: Version sicherstellen (OS-versions-agnostisch) ───────────────────
# Go wird unter /usr/local/go installiert — unabhängig von apt und Debian-Version.
# Das gilt nach einem OS-Upgrade auf Debian 14+ genauso wie auf trixie.

GO_REQUIRED="1.24.4"
export PATH="$PATH:/usr/local/go/bin"

_go_ok=0
if command -v go >/dev/null 2>&1; then
  _go_installed=$(go version 2>/dev/null | grep -oP 'go\K[0-9]+\.[0-9]+' | head -1)
  _go_major=${_go_installed%%.*}
  _go_minor=${_go_installed#*.}
  # >= 1.24 gilt als ausreichend
  if [[ "$_go_major" -gt 1 ]] || [[ "$_go_major" -eq 1 && "$_go_minor" -ge 24 ]]; then
    _go_ok=1
  fi
fi

if [[ $_go_ok -eq 0 ]]; then
  info "Go < 1.24 oder nicht gefunden — installiere Go ${GO_REQUIRED} von upstream..."
  _go_arch="amd64"
  [[ "$(uname -m)" == "aarch64" ]] && _go_arch="arm64"
  curl -fsSL "https://dl.google.com/go/go${GO_REQUIRED}.linux-${_go_arch}.tar.gz" \
      | tar -C /usr/local -xz
  ln -sf /usr/local/go/bin/go    /usr/local/bin/go
  ln -sf /usr/local/go/bin/gofmt /usr/local/bin/gofmt
  log "Go $(go version | awk '{print $3}') installiert"
else
  log "Go $(go version | awk '{print $3}') OK"
fi

# ── Sonstige Voraussetzungen ──────────────────────────────────────────────

command -v git  >/dev/null || die "git nicht gefunden — apt-get install git"
command -v node >/dev/null || die "node nicht gefunden — apt-get install nodejs"
command -v npm  >/dev/null || die "npm nicht gefunden — apt-get install npm"

# ── Manticore Search prüfen / installieren ────────────────────────────────
# Paket ist an bookworm gebunden — funktioniert auch auf trixie und Debian 14+,
# da Manticore kein OS-spezifisches ABI nutzt.

if ! command -v searchd >/dev/null 2>&1 && ! systemctl is-active --quiet manticore 2>/dev/null; then
  info "Manticore Search nicht gefunden — installiere..."
  _mc_arch="amd64"
  [[ "$(uname -m)" == "aarch64" ]] && _mc_arch="arm64"
  wget -q -O /tmp/manticore.deb \
    "https://repo.manticoresearch.com/repository/manticoresearch_bookworm/pool/main/m/manticoresearch/manticoresearch_6.3.6_${_mc_arch}.deb" 2>/dev/null \
    || wget -q -O /tmp/manticore.deb \
       "https://github.com/manticoresoftware/manticoresearch/releases/download/6.3.6/manticoresearch_6.3.6.202408011246.4c39781ba-1+bookworm_${_mc_arch}.deb" 2>/dev/null \
    || true
  if [[ -f /tmp/manticore.deb ]]; then
    dpkg -i /tmp/manticore.deb 2>/dev/null || apt-get install -f -y -qq 2>/dev/null || true
    rm -f /tmp/manticore.deb
    log "Manticore Search installiert"
  else
    warn "Manticore Search konnte nicht automatisch installiert werden — bitte manuell installieren"
    warn "Siehe: https://manticoresearch.com/install/"
  fi
fi

if systemctl list-unit-files manticore.service >/dev/null 2>&1; then
  systemctl enable manticore 2>/dev/null || true
  systemctl is-active --quiet manticore || systemctl start manticore 2>/dev/null || warn "Manticore-Dienst konnte nicht gestartet werden"
  systemctl is-active --quiet manticore && log "Manticore Search läuft"
fi

# ── OCR-Tools (PROJ-35: tesseract + poppler) ──────────────────────────────
# Optional: ohne diese Tools fällt OCR auf "deaktiviert" zurück, kein Abbruch.
if ! command -v tesseract >/dev/null 2>&1 || ! command -v pdftotext >/dev/null 2>&1; then
  info "Installiere OCR-Tools (tesseract, poppler-utils)..."
  apt-get install -y tesseract-ocr tesseract-ocr-deu poppler-utils 2>/dev/null || \
    warn "OCR-Tools konnten nicht installiert werden — OCR wird deaktiviert"
fi
if command -v tesseract >/dev/null 2>&1 && command -v pdftotext >/dev/null 2>&1; then
  log "OCR-Tools verfügbar (tesseract $(tesseract --version 2>&1 | head -1 | awk '{print $2}'))"
fi

# ── Quellcode holen ───────────────────────────────────────────────────────

if [[ -d "$BUILD_DIR/.git" ]]; then
  info "Aktualisiere Quellcode aus Gitea..."
  git config --global --add safe.directory "$BUILD_DIR" 2>/dev/null || true
  git -C "$BUILD_DIR" fetch origin
  git -C "$BUILD_DIR" reset --hard origin/main
  log "Quellcode aktualisiert ($(git -C "$BUILD_DIR" log -1 --format='%h %s'))"
else
  info "Lade Quellcode von $REPO_URL ..."
  mkdir -p "$BUILD_DIR"
  git clone "$REPO_URL" "$BUILD_DIR"
  log "Quellcode geladen"
fi

# ── Go Backend bauen ──────────────────────────────────────────────────────

info "Baue Go Backend..."
cd "$BUILD_DIR"
go mod tidy && go mod download
CGO_ENABLED=0 go build -buildvcs=false -o "$BUILD_DIR/archivmail-new" ./cmd/archivmail/
log "Go Backend gebaut"

# ── Next.js Frontend bauen ────────────────────────────────────────────────

info "Installiere Node-Abhängigkeiten..."
npm ci --prefer-offline 2>/dev/null || npm ci
log "Node-Abhängigkeiten installiert"

info "Baue Next.js Frontend..."
npm run build
log "Frontend gebaut"

# ── Dienste stoppen ───────────────────────────────────────────────────────

info "Stoppe Dienste..."
systemctl stop archivmail-web 2>/dev/null || warn "archivmail-web nicht aktiv"
systemctl stop archivmail     2>/dev/null || warn "archivmail nicht aktiv"

# ── Manticore als Standard-Backend in config.yml setzen ──────────────────
CONFIG_FILE="/etc/archivmail/config.yml"
if [[ -f "$CONFIG_FILE" ]]; then
  # Backend auf manticore umstellen falls noch nicht gesetzt
  if grep -q 'backend:' "$CONFIG_FILE"; then
    if ! grep -q 'backend: manticore' "$CONFIG_FILE"; then
      sed -i 's/^\([[:space:]]*\)backend:.*/\1backend: manticore/' "$CONFIG_FILE"
      info "Index-Backend auf 'manticore' gesetzt"
    fi
  else
    # backend: Zeile unter index: einfuegen
    sed -i '/^index:/a\  backend: manticore' "$CONFIG_FILE"
    info "Index-Backend 'manticore' hinzugefuegt"
  fi
  # manticore_dsn setzen falls nicht vorhanden
  if ! grep -q 'manticore_dsn' "$CONFIG_FILE"; then
    sed -i '/backend: manticore/a\  manticore_dsn: "manticore@tcp(127.0.0.1:9306)/"' "$CONFIG_FILE"
    info "Manticore-DSN gesetzt"
  fi
  log "Manticore-Konfiguration aktualisiert"
fi

# ── Dateien einspielen ────────────────────────────────────────────────────

info "Spiele Backend ein..."
mkdir -p "$BIN_DIR"
cp "$BUILD_DIR/archivmail-new" "$BIN_DIR/archivmail"
chmod +x "$BIN_DIR/archivmail"
# Service-Binary direkt überschreiben (nach systemctl stop)
cp "$BIN_DIR/archivmail" "$INSTALL_DIR/archivmail"
ln -sf "$BIN_DIR/archivmail" /usr/local/bin/archivmail
log "Backend eingespielt"

info "Spiele Cron-Jobs ein..."
cp "$BUILD_DIR/deploy/cron.d/archivmail" /etc/cron.d/archivmail
chmod 644 /etc/cron.d/archivmail
for script in "$BUILD_DIR"/deploy/cron.d/*.sh; do
  cp "$script" "/usr/local/bin/$(basename "$script")"
  chmod 755 "/usr/local/bin/$(basename "$script")"
done
log "Cron-Jobs eingespielt (/etc/cron.d/archivmail + Wrapper-Skripte)"

info "Spiele Frontend ein (standalone)..."
# Next.js standalone mirrors the absolute build path — find the dir that contains server.js.
# The path is typically: .next/standalone/<build-dir>/server.js
STANDALONE_SERVER=$(find "$BUILD_DIR/.next/standalone" -maxdepth 3 -name "server.js" | head -1)
[[ -n "$STANDALONE_SERVER" ]] || die "server.js nicht im standalone-Build gefunden"
STANDALONE_ROOT=$(dirname "$STANDALONE_SERVER")
# Clean destination and copy fresh standalone output
rm -rf "$FRONTEND_DIR"
mkdir -p "$FRONTEND_DIR"
rsync -a "$STANDALONE_ROOT/" "$FRONTEND_DIR/"
# Copy static assets from the full build (standalone doesn't include them)
mkdir -p "$FRONTEND_DIR/.next/static"
rsync -a --delete "$BUILD_DIR/.next/static/" "$FRONTEND_DIR/.next/static/"
if [[ -d "$BUILD_DIR/public" ]]; then
  rsync -a "$BUILD_DIR/public/" "$FRONTEND_DIR/public/"
fi
log "Frontend eingespielt"

# ── systemd Units synchronisieren ─────────────────────────────────────────
# install.sh schreibt die Unit-Dateien nur beim Erst-Setup. Ohne diesen
# Schritt bleiben bereits installierte Server auf dem Stand von damals
# eingefroren, selbst wenn sich die Unit-Definition im Repo ändert (z.B.
# CAP_NET_ADMIN für die Security-Tab-Firewall-Aktion, nachträglich ergänzt —
# Server die vor dieser Änderung installiert wurden, hatten die Capability
# bis zu diesem Fix hier gefehlt). Bei jedem Deploy neu schreiben + reload,
# damit Unit-Änderungen aus install.sh automatisch nachgezogen werden.
info "Synchronisiere systemd Units..."
STORE_DIR="/var/archivmail"
LOG_DIR="/var/log/archivmail"
CONFIG_DIR="/etc/archivmail"
SSL_DIR="/etc/ssl/archivmail"
AM_USER="archivmail"

cat > /etc/systemd/system/archivmail.service << UNIT
[Unit]
Description=archivmail Mail Archive Daemon
After=network.target postgresql.service manticore.service
Requires=postgresql.service manticore.service

[Service]
Type=simple
User=${AM_USER}
Group=${AM_USER}
# CAP_NET_ADMIN: required for the admin "enable firewall" action (nft -f /etc/nftables.conf)
AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMIN
ExecStart=${INSTALL_DIR}/archivmail --config ${CONFIG_DIR}/config.yml
ExecReload=/bin/kill -HUP \$MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=archivmail
NoNewPrivileges=false
ProtectSystem=strict
ReadWritePaths=${STORE_DIR} ${LOG_DIR}
ReadOnlyPaths=${CONFIG_DIR} ${SSL_DIR}

[Install]
WantedBy=multi-user.target
UNIT

cat > /etc/systemd/system/archivmail-web.service << UNIT
[Unit]
Description=archivmail Web Frontend
After=network.target archivmail.service

[Service]
Type=simple
User=${AM_USER}
Group=${AM_USER}
WorkingDirectory=${INSTALL_DIR}/web
ExecStart=/usr/bin/node server.js
Environment=NODE_ENV=production
Environment=PORT=3000
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=archivmail-web

[Install]
WantedBy=multi-user.target
UNIT

systemctl daemon-reload
systemctl enable archivmail archivmail-web --quiet
log "systemd Units synchronisiert"

# ── Dienste starten ───────────────────────────────────────────────────────

info "Starte Dienste..."
systemctl start archivmail
systemctl start archivmail-web
log "Dienste gestartet"

# ── Status prüfen ─────────────────────────────────────────────────────────
# Hinweis: Kein automatischer Manticore-Reindex mehr bei jedem Update.
# Neu importierte Mails (IMAP/SMTP/POP3/EML) werden synchron indiziert
# (siehe internal/imap/importer.go IndexSync) — ein Reindex ist nur nach
# Schema-Änderungen am Index nötig: manuell mit
#   archivmail reindex --config /etc/archivmail/config.yml

BACKEND_OK=0
FRONTEND_OK=0

# Health-Check statt nur systemd-Status: Backend muss tatsächlich auf
# HTTP antworten (Prozess kann laufen, aber z.B. an DB-Connect hängen).
info "Prüfe Backend-Health (/api/health)..."
for i in $(seq 1 15); do
  if systemctl is-active --quiet archivmail && curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:8080/api/health 2>/dev/null; then
    BACKEND_OK=1
    break
  fi
  sleep 1
done

info "Prüfe Frontend-Health (Port 3000)..."
for i in $(seq 1 15); do
  if systemctl is-active --quiet archivmail-web && curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:3000/ 2>/dev/null; then
    FRONTEND_OK=1
    break
  fi
  sleep 1
done

echo ""
echo "  ┌──────────────────────────────────────┐"
[[ $BACKEND_OK  -eq 1 ]] && echo "  │  Backend   ✓ läuft                   │" \
                         || echo "  │  Backend   ✗ nicht aktiv             │"
[[ $FRONTEND_OK -eq 1 ]] && echo "  │  Frontend  ✓ läuft                   │" \
                         || echo "  │  Frontend  ✗ nicht aktiv             │"
echo "  └──────────────────────────────────────┘"
echo ""

[[ $BACKEND_OK -eq 1 && $FRONTEND_OK -eq 1 ]] && log "Update abgeschlossen." \
  || warn "Ein oder mehrere Dienste sind nicht aktiv. Prüfe: journalctl -u archivmail -u archivmail-web"
