#!/usr/bin/env bash
#
# DucKI Agent — Installer (macOS / Linux / Raspberry Pi)
# Installiert den selbstgehosteten Opensource-Agenten sicher & stabil.
#
#   curl -fsSL https://ducki.cloud/install.sh | bash
#
# Idempotent: mehrfaches Ausführen aktualisiert eine bestehende Installation.
# Nichts wird als root ausgeführt; Prereqs werden nur mit deiner Bestätigung installiert.
set -euo pipefail

REPO_URL="https://github.com/davidduckwitz/ducKI-Agent.git"
DUCKI_HOME="${DUCKI_HOME:-$HOME/.ducki-agent}"
APP_DIR="$DUCKI_HOME/app"
NODE_MIN=20
PORT="${DUCKI_PORT:-3001}"
# Origins, die die Plugin-UIs des Agenten einbetten dürfen (die gehostete Web-UI + lokal).
FRAME_ANCESTORS="${DUCKI_FRAME_ANCESTORS:-https://ducki.cloud}"

c_green="\033[0;32m"; c_yellow="\033[0;33m"; c_red="\033[0;31m"; c_blue="\033[0;34m"; c_reset="\033[0m"
info()  { printf "${c_blue}▶${c_reset} %s\n" "$1"; }
ok()    { printf "${c_green}✓${c_reset} %s\n" "$1"; }
warn()  { printf "${c_yellow}!${c_reset} %s\n" "$1"; }
die()   { printf "${c_red}✗ %s${c_reset}\n" "$1" >&2; exit 1; }
have()  { command -v "$1" >/dev/null 2>&1; }

OS="$(uname -s)"; ARCH="$(uname -m)"
case "$OS" in
  Darwin) PLATFORM="macos" ;;
  Linux)  PLATFORM="linux" ;;
  *) die "Nicht unterstütztes Betriebssystem: $OS (nutze den manuellen Weg auf der Website)." ;;
esac

printf "\n${c_green}DucKI Agent — Installer${c_reset}  (%s/%s)\n\n" "$PLATFORM" "$ARCH"

# --- 1) git ---------------------------------------------------------------
if ! have git; then
  warn "git fehlt — versuche Installation…"
  if [ "$PLATFORM" = "macos" ] && have brew; then brew install git
  elif have apt-get; then sudo apt-get update -y && sudo apt-get install -y git
  elif have dnf; then sudo dnf install -y git
  elif have pacman; then sudo pacman -S --noconfirm git
  else die "git nicht gefunden und keine bekannte Paketverwaltung. Bitte git manuell installieren."; fi
fi
ok "git vorhanden"

# --- 2) Node.js (>=20) ----------------------------------------------------
node_major() { node -v 2>/dev/null | sed 's/^v//; s/\..*//'; }
need_node=1
if have node && [ "$(node_major)" -ge "$NODE_MIN" ] 2>/dev/null; then need_node=0; fi

if [ "$need_node" -eq 1 ]; then
  warn "Node.js >= $NODE_MIN wird benötigt — installiere via fnm (kein root, kein Systemeingriff)…"
  if ! have fnm; then
    curl -fsSL https://fnm.vercel.app/install | bash -s -- --skip-shell || die "fnm-Installation fehlgeschlagen."
    export PATH="$HOME/.local/share/fnm:$HOME/.fnm:$PATH"
    have fnm || eval "$("$HOME/.local/share/fnm/fnm" env 2>/dev/null || true)"
  fi
  export PATH="$HOME/.local/share/fnm:$HOME/.fnm:$PATH"
  eval "$(fnm env 2>/dev/null || true)"
  fnm install 22 >/dev/null 2>&1 || fnm install 20 || die "Node-Installation via fnm fehlgeschlagen."
  fnm use 22 >/dev/null 2>&1 || fnm use 20 || true
fi
have node || die "Node.js nicht verfügbar. Bitte Node >= $NODE_MIN manuell installieren (https://nodejs.org)."
ok "Node.js $(node -v)"

# --- 3) pnpm via corepack -------------------------------------------------
if ! have pnpm; then
  info "Aktiviere pnpm via corepack…"
  corepack enable >/dev/null 2>&1 || npm install -g corepack >/dev/null 2>&1 && corepack enable >/dev/null 2>&1 || true
fi
have pnpm || corepack prepare pnpm@latest --activate >/dev/null 2>&1 || true
have pnpm || die "pnpm konnte nicht aktiviert werden. Versuche: corepack enable"
ok "pnpm $(pnpm -v)"

# --- 4) Repo klonen / aktualisieren --------------------------------------
mkdir -p "$DUCKI_HOME"
if [ -d "$APP_DIR/.git" ]; then
  info "Aktualisiere bestehende Installation…"
  git -C "$APP_DIR" fetch --depth 1 origin || die "Update fehlgeschlagen: Quellcode konnte nicht geladen werden (Internetverbindung?)."
  # Hard-Reset auf den geholten Stand, damit lokale Änderungen an eingecheckten
  # Build-Artefakten (z. B. tsconfig.tsbuildinfo) das Update nicht blockieren.
  # Nutzerdaten unter shared-workspace/ sind gitignored und bleiben unberührt.
  git -C "$APP_DIR" reset --hard FETCH_HEAD || die "Update fehlgeschlagen: Quellcode konnte nicht angewendet werden."
else
  info "Lade Agent nach $APP_DIR …"
  git clone --depth 1 "$REPO_URL" "$APP_DIR" || die "Download fehlgeschlagen (Internetverbindung?)."
fi
ok "Quellcode bereit"

# --- 5) Abhängigkeiten & Build -------------------------------------------
cd "$APP_DIR"
info "Installiere Abhängigkeiten (kann einige Minuten dauern)…"
pnpm install --prod=false || die "Installation der Abhängigkeiten fehlgeschlagen."
# build:server baut den Server UND alle @ducki/*-Workspace-Pakete (in
# Abhängigkeitsreihenfolge). Nur den Server zu bauen laesst z. B.
# @ducki/agent/dist fehlen -> Agent crasht beim Start mit ERR_MODULE_NOT_FOUND.
info "Baue Agent (Server + Pakete)…"
pnpm build:server || die "Build fehlgeschlagen. Siehe Fehler oben."
ok "Build abgeschlossen"

# --- 6) Autostart-Dienst --------------------------------------------------
START_CMD="pnpm --filter @ducki/server start"
setup_linux_service() {
  local unit_dir="$HOME/.config/systemd/user"
  mkdir -p "$unit_dir"
  cat > "$unit_dir/ducki-agent.service" <<EOF
[Unit]
Description=DucKI Agent (selfhosted)
After=network-online.target

[Service]
Type=simple
WorkingDirectory=$APP_DIR
Environment=PORT=$PORT
Environment="DUCKI_FRAME_ANCESTORS=$FRAME_ANCESTORS"
ExecStart=$(command -v pnpm) --filter @ducki/server start
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target
EOF
  systemctl --user daemon-reload
  systemctl --user enable --now ducki-agent.service
  loginctl enable-linger "$USER" >/dev/null 2>&1 || warn "Autostart nach Reboot ggf. eingeschränkt (enable-linger nicht möglich)."
}
setup_macos_service() {
  local plist="$HOME/Library/LaunchAgents/cloud.ducki.agent.plist"
  mkdir -p "$HOME/Library/LaunchAgents"
  cat > "$plist" <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
  <key>Label</key><string>cloud.ducki.agent</string>
  <key>ProgramArguments</key><array>
    <string>$(command -v pnpm)</string><string>--filter</string><string>@ducki/server</string><string>start</string>
  </array>
  <key>WorkingDirectory</key><string>$APP_DIR</string>
  <key>EnvironmentVariables</key><dict><key>PORT</key><string>$PORT</string><key>DUCKI_FRAME_ANCESTORS</key><string>$FRAME_ANCESTORS</string></dict>
  <key>RunAtLoad</key><true/><key>KeepAlive</key><true/>
</dict></plist>
EOF
  launchctl unload "$plist" >/dev/null 2>&1 || true
  launchctl load "$plist"
}

if [ "$PLATFORM" = "linux" ] && have systemctl; then
  info "Richte systemd-Dienst ein (Autostart + Neustart bei Absturz)…"
  setup_linux_service && ok "Dienst aktiv: systemctl --user status ducki-agent"
elif [ "$PLATFORM" = "macos" ]; then
  info "Richte launchd-Dienst ein…"
  setup_macos_service && ok "Dienst aktiv (launchd)"
else
  warn "Kein Dienst-Manager gefunden — starte im Hintergrund (kein Autostart nach Reboot)."
  nohup env PORT="$PORT" DUCKI_FRAME_ANCESTORS="$FRAME_ANCESTORS" $START_CMD >"$DUCKI_HOME/agent.log" 2>&1 &
  ok "Agent gestartet (Logs: $DUCKI_HOME/agent.log)"
fi

# --- 7) Health-Check ------------------------------------------------------
info "Warte auf den Agenten…"
for i in $(seq 1 30); do
  if curl -fsS "http://localhost:$PORT/api/health" >/dev/null 2>&1; then ok "Agent läuft auf http://localhost:$PORT"; break; fi
  sleep 1
  [ "$i" -eq 30 ] && warn "Agent antwortet noch nicht — prüfe die Logs ($DUCKI_HOME/agent.log)."
done

cat <<EOF

${c_green}Fertig!${c_reset}
  • Agent-URL:   http://localhost:$PORT
  • Installiert: $APP_DIR
  • Aktualisieren: curl -fsSL https://ducki.cloud/install.sh | bash

Öffne jetzt die Web-UI (Free-Modus) — sie verbindet sich automatisch mit
http://localhost:$PORT. Falls nicht: unter „Backend-Verbindung" diese URL eintragen.
EOF
