#!/usr/bin/env bash
# uninstall.sultix.ai — interactive uninstaller for the sultix
# controller. Default keeps the data dir (master.key, db, device-ca)
# so a future reinstall comes back with the same state. Pass
# --purge to wipe everything.
#
# Curl-pipe-bash entry:
#
#   curl -fsSL https://uninstall.sultix.ai | bash
#   curl -fsSL https://uninstall.sultix.ai | bash -s -- --yes --purge

set -euo pipefail

if [ -t 1 ]; then
    C_DIM='\033[2m'; C_RESET='\033[0m'
    C_CYAN='\033[1;36m'; C_GREEN='\033[1;32m'
    C_YELLOW='\033[1;33m'; C_RED='\033[1;31m'
else
    C_DIM=; C_RESET=; C_CYAN=; C_GREEN=; C_YELLOW=; C_RED=
fi

say()  { printf "${C_CYAN}▸${C_RESET} %s\n" "$*"; }
ok()   { printf "${C_GREEN}✓${C_RESET} %s\n" "$*"; }
warn() { printf "${C_YELLOW}!${C_RESET} %s\n" "$*" >&2; }
fail() { printf "${C_RED}✗${C_RESET} %s\n" "$*" >&2; exit 1; }
hr()   { printf "${C_DIM}────────────────────────────────────────────────${C_RESET}\n"; }

ASSUME_YES=0
PURGE=0
PURGE_DOCKER=0          # --purge-docker also removes the docker engine + images
PURGE_PROXY=0           # --purge-proxy also removes caddy
PURGE_POSTGRES=0        # --purge-postgres also removes the postgres container + volume
FORCE_PURGE_DOCKER=0    # override "we didn't install docker" check
FORCE_PURGE_PROXY=0     # override "we didn't install caddy" check

while [ $# -gt 0 ]; do
    case "$1" in
        --yes|-y)               ASSUME_YES=1 ;;
        --purge)                PURGE=1 ;;
        --purge-docker)         PURGE=1; PURGE_DOCKER=1 ;;
        --force-purge-docker)   PURGE=1; PURGE_DOCKER=1; FORCE_PURGE_DOCKER=1 ;;
        --purge-proxy)          PURGE_PROXY=1 ;;
        --force-purge-proxy)    PURGE_PROXY=1; FORCE_PURGE_PROXY=1 ;;
        --purge-postgres)       PURGE_POSTGRES=1 ;;
        --help|-h)
            cat <<HELP
sultix uninstaller.

By default removes the systemd unit + binary + sultix-ctrl user, but
KEEPS the data dir (so a future reinstall comes back with same state).

Usage:
    curl -fsSL https://uninstall.sultix.ai | bash
    curl -fsSL https://uninstall.sultix.ai | bash -s -- [flags]

Flags:
    --yes, -y               run unattended; never prompt
    --purge                 also wipe the data dir (master.key, db,
                            device-ca, ALL chats, ALL secrets) —
                            irreversible
    --purge-docker          --purge AND remove docker engine + all
                            images. REFUSED if /etc/sultix/install-
                            manifest says docker was here before us;
                            use --force-purge-docker to override.
    --force-purge-docker    bypass the "we didn't install it" check
    --purge-proxy           remove our caddy site config; also remove
                            the caddy package + its apt source IF
                            sultix installed it. Otherwise the
                            package stays put and just our snippet
                            goes; --force-purge-proxy to override.
    --force-purge-proxy     bypass the "we didn't install it" check
    --purge-postgres        also stop + remove the sultix-postgres
                            container and the sultix-postgres-data
                            named volume (always safe — both are
                            named exclusively for our use)

Examples:
    # Keep data, just remove sultix:
    curl -fsSL https://uninstall.sultix.ai | bash -s -- --yes
    # Wipe everything sultix-related (data, postgres, caddy):
    curl -fsSL https://uninstall.sultix.ai | bash -s -- --yes \\
        --purge --purge-postgres --purge-proxy
    # Reset the host to a virgin state:
    curl -fsSL https://uninstall.sultix.ai | bash -s -- --yes \\
        --purge-docker --purge-postgres --purge-proxy
HELP
            exit 0
            ;;
        *) fail "unknown flag: $1 (try --help)" ;;
    esac
    shift
done

INTERACTIVE=1
[ "$ASSUME_YES" = "1" ] && INTERACTIVE=0
[ ! -e /dev/tty ] && INTERACTIVE=0

confirm() {
    local prompt="$1"
    if [ "$INTERACTIVE" != "1" ]; then return 0; fi
    local ans
    printf "%s [y/N] " "$prompt" > /dev/tty
    read -r ans < /dev/tty || ans=""
    case "${ans}" in
        Y|y|YES|yes) return 0 ;;
        *) return 1 ;;
    esac
}

confirm_destructive() {
    # Two-step prompt for irreversible operations. Requires the
    # user to type a literal token (e.g. "PURGE") before proceeding.
    local prompt="$1" token="$2"
    if [ "$INTERACTIVE" != "1" ]; then return 0; fi
    local ans
    printf "%s\nType %s to confirm: " "$prompt" "$token" > /dev/tty
    read -r ans < /dev/tty || ans=""
    [ "$ans" = "$token" ]
}

case "$(uname -s)" in
    Linux)  OS="linux" ;;
    Darwin) OS="darwin" ;;
    *) fail "unsupported OS: $(uname -s)" ;;
esac

# ── darwin uninstaller (LaunchAgent + user-scoped state) ──────────────
# Mac installs are per-user — LaunchAgent in ~/Library/LaunchAgents,
# binary at ~/.local/bin/sultix, data under ~/Library/Application
# Support/sultix. No system-wide install side-effects (we never
# auto-installed docker on darwin, and there's no Caddy/Postgres
# bring-up). The flow is straight:
#
#   stop LaunchAgent → remove plist → remove binary → optionally
#   wipe data dir + log file.
#
# Returns from the script when done so the Linux-only sections below
# never execute.
darwin_uninstall() {
    if [ "$(id -u)" = "0" ]; then
        fail "macOS: don't run with sudo. Everything is in your user account."
    fi

    DARWIN_LABEL="com.sultix.controller"
    DARWIN_PLIST="$HOME/Library/LaunchAgents/${DARWIN_LABEL}.plist"
    DARWIN_LOG="$HOME/Library/Logs/sultix-controller.log"
    DARWIN_BIN="$HOME/.local/bin/sultix"
    DARWIN_DATA="$HOME/Library/Application Support/sultix"

    hr
    printf "${C_CYAN}sultix uninstaller (macOS)${C_RESET}\n"
    printf "  remove agent     %s\n" "$DARWIN_PLIST"
    printf "  remove binary    %s\n" "$DARWIN_BIN"
    if [ "$PURGE" = "1" ]; then
        printf "  ${C_RED}wipe data dir${C_RESET}    %s (master.key, db, certs, ALL data)\n" "$DARWIN_DATA"
        printf "  ${C_RED}wipe log file${C_RESET}    %s\n" "$DARWIN_LOG"
    else
        printf "  KEEP data dir    %s  (use --purge to wipe)\n" "$DARWIN_DATA"
    fi
    if [ "$PURGE_DOCKER" = "1" ]; then
        warn "--purge-docker ignored on macOS — installer never auto-installed Docker."
    fi
    if [ "$PURGE_PROXY" = "1" ]; then
        warn "--purge-proxy ignored on macOS — installer never auto-installed Caddy."
    fi
    hr

    if [ "$PURGE" = "1" ]; then
        confirm_destructive "This wipes ALL sultix data. Master keys, secrets, chat history — gone forever." "PURGE" \
            || { say "aborted"; exit 0; }
    fi
    confirm "Proceed with uninstall?" || { say "aborted"; exit 0; }

    # ── stop LaunchAgent ─────────────────────────────────────────────
    say "stopping LaunchAgent"
    launchctl bootout "gui/$(id -u)/${DARWIN_LABEL}" 2>/dev/null || true

    # ── remove plist + binary ────────────────────────────────────────
    rm -f "$DARWIN_PLIST"
    rm -f "$DARWIN_BIN"
    ok "LaunchAgent + binary removed"

    # ── purge data + log if requested ────────────────────────────────
    if [ "$PURGE" = "1" ]; then
        rm -rf "$DARWIN_DATA"
        rm -f "$DARWIN_LOG"
        ok "data dir + log wiped"
    fi

    # ── optional: postgres container/volume cleanup ──────────────────
    # On macOS we never auto-bring-up postgres, but a user may have
    # spawned one themselves under the same name. Honor the flag if
    # explicit.
    if [ "$PURGE_POSTGRES" = "1" ] && command -v docker >/dev/null 2>&1; then
        say "removing postgres container + volume (if present)"
        docker rm -f sultix-postgres 2>/dev/null || true
        docker volume rm sultix-postgres-data 2>/dev/null || true
    fi

    hr
    ok "sultix uninstalled."
    [ "$PURGE" != "1" ] && printf "  data preserved at %s — reinstall picks up where you left off\n" "$DARWIN_DATA"
    [ "$PURGE" = "1"  ] && printf "  clean slate. Reinstall: curl -fsSL https://install.sultix.ai | bash\n"
    exit 0
}

if [ "$OS" = "darwin" ]; then
    darwin_uninstall
fi

# ── read install manifest (if any) ────────────────────────────────────
# install.sh records what it actually placed so we can refuse to
# yank user-owned packages we found pre-existing. Missing manifest
# = "we don't know" → conservative default is "don't purge unless
# the user explicitly asks via --force-purge-*".
MANIFEST_FILE="/etc/sultix/install-manifest"
DOCKER_INSTALLED_BY_US=""
CADDY_INSTALLED_BY_US=""
if sudo test -r "$MANIFEST_FILE"; then
    # awk on a missing key prints nothing AND exits 0 (vs grep|cut
    # which exits 1, which under set -e + pipefail kills the script
    # silently — found this exact bug landing this manifest layer).
    DOCKER_INSTALLED_BY_US="$(sudo awk -F= '/^docker_installed_by_sultix=/{print $2}' "$MANIFEST_FILE" 2>/dev/null || true)"
    CADDY_INSTALLED_BY_US="$( sudo awk -F= '/^caddy_installed_by_sultix=/{print $2}'  "$MANIFEST_FILE" 2>/dev/null || true)"
fi

# ── manifest-aware downgrade of --purge-* flags ──────────────────────
# Decide BEFORE the plan is printed so the human sees the truth.
if [ "$PURGE_DOCKER" = "1" ] && [ "$FORCE_PURGE_DOCKER" != "1" ]; then
    if [ "$DOCKER_INSTALLED_BY_US" = "false" ]; then
        warn "docker was already installed before sultix touched this host —"
        warn "  refusing to remove (use --force-purge-docker to override)."
        PURGE_DOCKER=0
    elif [ -z "$DOCKER_INSTALLED_BY_US" ]; then
        warn "no install-manifest found — can't tell if sultix installed docker."
        warn "  Pass --force-purge-docker if you really want it removed."
        PURGE_DOCKER=0
    fi
fi
if [ "$PURGE_PROXY" = "1" ] && [ "$FORCE_PURGE_PROXY" != "1" ]; then
    if [ "$CADDY_INSTALLED_BY_US" = "false" ]; then
        warn "caddy was already installed before sultix touched this host —"
        warn "  refusing to remove (use --force-purge-proxy to override)."
        # We still drop OUR site config; just don't apt-purge the package.
        REMOVE_CADDY_PACKAGE=0
    fi
fi
REMOVE_CADDY_PACKAGE="${REMOVE_CADDY_PACKAGE:-1}"

# ── plan summary up front ─────────────────────────────────────────────
hr
printf "${C_CYAN}sultix uninstaller${C_RESET}\n"
printf "  remove binary    /usr/local/bin/sultix\n"
printf "  remove unit      /etc/systemd/system/sultix-controller.service\n"
printf "  remove user      sultix-ctrl\n"
# Resolve the actual data dir from /etc/sultix/config.yaml so the
# plan summary matches what `sultix uninstall --purge` will actually
# wipe. Falls back to the new default (/opt/sultix) when no config
# was found (e.g. partial install where config.yaml never landed).
DATA_DIR_DETECTED=""
if [ -r /etc/sultix/config.yaml ]; then
    DATA_DIR_DETECTED="$(awk -F: '/^[[:space:]]*data_dir[[:space:]]*:/ {gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); print $2; exit}' /etc/sultix/config.yaml)"
fi
[ -z "$DATA_DIR_DETECTED" ] && DATA_DIR_DETECTED="/opt/sultix"
if [ "$PURGE" = "1" ]; then
    printf "  ${C_RED}wipe data dir${C_RESET}  %s (master.key, db, certs, ALL data)\n" "$DATA_DIR_DETECTED"
    printf "  ${C_RED}wipe config${C_RESET}    /etc/sultix/\n"
else
    printf "  KEEP data dir    %s  (use --purge to wipe)\n" "$DATA_DIR_DETECTED"
    printf "  KEEP config      /etc/sultix/config.yaml\n"
fi
[ "$PURGE_POSTGRES" = "1" ] && printf "  ${C_RED}remove postgres${C_RESET}  container + volume + creds\n"
[ "$PURGE_PROXY" = "1" ]    && printf "  remove caddy     /etc/caddy/sites-available/sultix.caddyfile (apt remove caddy)\n"
[ "$PURGE_DOCKER" = "1" ]   && printf "  ${C_RED}remove docker${C_RESET}    engine + images + /var/lib/docker (entire daemon)\n"
hr

if [ "$PURGE" = "1" ]; then
    confirm_destructive "This wipes ALL sultix data. Master keys, secrets, chat history — gone forever. No backup is offered by this script (see backup & restore in the admin UI)." "PURGE" \
        || { say "aborted"; exit 0; }
fi
confirm "Proceed with uninstall?" || { say "aborted"; exit 0; }

# ── stop service first ────────────────────────────────────────────────
if systemctl list-unit-files sultix-controller.service >/dev/null 2>&1; then
    say "stopping sultix-controller"
    sudo systemctl stop sultix-controller.service 2>/dev/null || true
    sudo systemctl disable sultix-controller.service 2>/dev/null || true
fi

# ── postgres (before docker, in case --purge-docker is on) ────────────
if [ "$PURGE_POSTGRES" = "1" ]; then
    if command -v docker >/dev/null 2>&1; then
        say "removing postgres container + volume"
        sudo -u sultix-ctrl docker rm -f sultix-postgres 2>/dev/null \
            || docker rm -f sultix-postgres 2>/dev/null || true
        sudo -u sultix-ctrl docker volume rm sultix-postgres-data 2>/dev/null \
            || docker volume rm sultix-postgres-data 2>/dev/null || true
        sudo -u sultix-ctrl docker image rm pgvector/pgvector:pg16 2>/dev/null \
            || docker image rm pgvector/pgvector:pg16 2>/dev/null || true
    fi
    sudo rm -f /home/sultix/.sultix-postgres.env /home/sultix-ctrl/.sultix-postgres.env 2>/dev/null || true
    ok "postgres removed"
fi

# ── caddy (proxy) ─────────────────────────────────────────────────────
if [ "$PURGE_PROXY" = "1" ]; then
    say "removing caddy site config"
    sudo rm -f /etc/caddy/sites-available/sultix.caddyfile
    if command -v caddy >/dev/null 2>&1 && [ "$REMOVE_CADDY_PACKAGE" = "1" ]; then
        sudo systemctl reload caddy 2>/dev/null || true
        say "removing caddy package"
        sudo apt-get purge -y caddy 2>&1 | tail -3 || true
        # Caddy ships its own apt source via cloudsmith. Our --purge-proxy
        # claim is "everything we added when --proxy=caddy was passed" —
        # so the source + the keyring go too. Without these the apt index
        # keeps trying to refresh a broken-relevance repo on every update.
        sudo rm -f /etc/apt/sources.list.d/caddy-stable.list \
                   /usr/share/keyrings/caddy-stable-archive-keyring.gpg
    elif command -v caddy >/dev/null 2>&1; then
        # User had caddy before sultix. Reload to pick up our removed
        # snippet, but don't touch the package or the apt source.
        sudo systemctl reload caddy 2>/dev/null || true
        say "caddy package + apt source preserved (was here before sultix)"
    fi
fi

# ── controller binary + systemd unit + user ───────────────────────────
# Use the controller's own uninstall subcommand if the binary still
# exists — it knows exactly what it created and removes it idempotently.
# Falls back to a manual cleanup for hosts where the binary is broken
# or missing.
if [ -x /usr/local/bin/sultix ]; then
    say "running 'sultix uninstall'$([ "$PURGE" = "1" ] && echo ' --purge')"
    if [ "$PURGE" = "1" ]; then
        sudo /usr/local/bin/sultix uninstall --purge || true
    else
        sudo /usr/local/bin/sultix uninstall || true
    fi
fi

# ── manual cleanup fallback (in case the binary couldn't run) ─────────
sudo rm -f /usr/local/bin/sultix
sudo rm -f /etc/systemd/system/sultix-controller.service
sudo systemctl daemon-reload 2>/dev/null || true
if id sultix-ctrl >/dev/null 2>&1; then
    sudo userdel sultix-ctrl 2>/dev/null || true
fi
if [ "$PURGE" = "1" ]; then
    sudo rm -rf "$DATA_DIR_DETECTED"
    sudo rm -rf /var/lib/sultix    # legacy pre-2026-04-29 data path
    sudo rm -rf /opt/sultix        # legacy pre-2026-04-29 binary path (and current data default)
    sudo rm -rf /etc/sultix        # config + install-manifest live here
fi

# ── docker engine ─────────────────────────────────────────────────────
if [ "$PURGE_DOCKER" = "1" ]; then
    if command -v docker >/dev/null 2>&1; then
        say "removing docker engine"
        sudo systemctl stop docker.socket docker.service containerd.service 2>/dev/null || true
        sudo systemctl disable docker.socket docker.service containerd.service 2>/dev/null || true
        sudo apt-get purge -y \
            containerd.io docker-buildx-plugin docker-ce docker-ce-cli \
            docker-ce-rootless-extras docker-compose-plugin 2>&1 | tail -3 || true
        sudo apt-get autoremove --purge -y 2>&1 | tail -3 || true
        sudo rm -rf /var/lib/docker /var/lib/containerd /etc/docker
        sudo rm -f /etc/apt/sources.list.d/docker.list /etc/apt/keyrings/docker.gpg
        sudo groupdel docker 2>/dev/null || true
        ok "docker removed"
    fi
fi

hr
ok "sultix uninstalled"
[ "$PURGE" != "1" ] && printf "  data preserved at %s — reinstall picks up where you left off\n" "$DATA_DIR_DETECTED"
[ "$PURGE" = "1" ]  && printf "  ${C_RED}data wiped${C_RESET}  — irreversible\n"
hr
