#!/usr/bin/env bash
# install.sh — Install dugnad-agent on Linux, Termux, or a VPS.
#
# Usage:
#   curl -sSL install.dugnad.cloud | sh -s -- --token <device-token>
#   curl -sSL install.dugnad.cloud | sh -s -- --update
#
# Flags:
#   --token <token>         Device registration token (first install only).
#   --coordinator <url>     Coordinator URL (default: https://api.dugnad.cloud).
#   --label <name>          Human-readable node name (default: hostname).
#   --update                Upgrade binary only. Skip token + config checks.
#   --dry-run               Print actions without executing.
#   --help                  Show this message.
#
# Re-running without flags upgrades the binary, keeps the keypair and config.

set -euo pipefail

COORDINATOR="https://api.dugnad.cloud"
DOWNLOAD_BASE="https://downloads.sptk.be/dugnad-agent/latest"
TOKEN=""
LABEL=""
UPDATE_ONLY=false
DRY_RUN=false

log()   { printf '\033[1;34m[install]\033[0m %s\n' "$*"; }
warn()  { printf '\033[1;33m[warn]\033[0m %s\n' "$*" >&2; }
fail()  { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
run()   { if $DRY_RUN; then printf '\033[2m$ %s\033[0m\n' "$*"; else eval "$*"; fi; }

usage() { sed -n '2,17p' "$0" | sed 's/^# \{0,1\}//'; exit "${1:-0}"; }

# ─── Parse args ────────────────────────────────────────────────────────────
while [ $# -gt 0 ]; do
    case "$1" in
        --token)       TOKEN="${2:?--token requires a value}"; shift 2 ;;
        --coordinator) COORDINATOR="${2:?--coordinator requires a value}"; shift 2 ;;
        --label)       LABEL="${2:?--label requires a value}"; shift 2 ;;
        --update)      UPDATE_ONLY=true; shift ;;
        --dry-run)     DRY_RUN=true; shift ;;
        --help|-h)     usage 0 ;;
        *)             warn "unknown flag: $1"; usage 1 ;;
    esac
done

# ─── Detect platform ───────────────────────────────────────────────────────
IS_TERMUX=false
if [ -n "${TERMUX_VERSION:-}" ] || [ -d /data/data/com.termux/files/usr ]; then
    IS_TERMUX=true
fi

MACHINE="$(uname -m)"
case "$MACHINE" in
    x86_64|amd64)
        ARCH_DIR="x86_64"
        $IS_TERMUX && fail "x86_64 on Termux is not supported (no Android x86_64 build)"
        ;;
    aarch64|arm64)
        ARCH_DIR="aarch64"
        if ! $IS_TERMUX; then
            fail "aarch64 Linux is not supported yet — only aarch64 Android/Termux binaries exist. Track: https://github.com/SPTK-EPB/dugnad-agent/issues (add aarch64 musl target)"
        fi
        ;;
    armv7l|armv7|arm)
        ARCH_DIR="armv7"
        $IS_TERMUX || fail "armv7 Linux is not supported yet — only armv7 Android/Termux binaries exist."
        ;;
    *)
        fail "unsupported architecture: $MACHINE"
        ;;
esac

BINARY_URL="$DOWNLOAD_BASE/$ARCH_DIR/dugnad-agent"
CHECKSUM_URL="$BINARY_URL.sha256"

# ─── Choose install mode ───────────────────────────────────────────────────
# termux           → runit under ~/.dugnad/sv
# root + systemd   → system service
# user + systemd   → user service (~/.config/systemd/user)
MODE=""
if $IS_TERMUX; then
    MODE="termux"
elif [ "$(id -u)" = "0" ]; then
    command -v systemctl >/dev/null || fail "root install requires systemd (systemctl not found)"
    MODE="system"
else
    command -v systemctl >/dev/null || fail "user install requires systemd (systemctl not found). Re-run as root, or install Termux for Android."
    systemctl --user show-environment >/dev/null 2>&1 \
        || fail "user systemd is not available in this session. Re-run as root, or enable lingering with: sudo loginctl enable-linger $(id -un)"
    MODE="user"
fi

# ─── Paths ─────────────────────────────────────────────────────────────────
case "$MODE" in
    termux)
        BIN_DIR="${PREFIX:-/data/data/com.termux/files/usr}/bin"
        CONFIG_DIR="$HOME/.dugnad"
        LOG_DIR="$CONFIG_DIR/logs"
        SVDIR="${PREFIX:-/data/data/com.termux/files/usr}/var/service"
        SERVICE_DIR="$SVDIR/dugnad-agent"
        ;;
    system)
        BIN_DIR="/usr/local/bin"
        CONFIG_DIR="/etc/dugnad-agent"
        LOG_DIR="/var/log/dugnad-agent"
        SERVICE_FILE="/etc/systemd/system/dugnad-agent.service"
        ;;
    user)
        BIN_DIR="$HOME/.local/bin"
        CONFIG_DIR="$HOME/.dugnad"
        LOG_DIR="$CONFIG_DIR/logs"
        SERVICE_FILE="$HOME/.config/systemd/user/dugnad-agent.service"
        ;;
esac
BINARY="$BIN_DIR/dugnad-agent"
CONFIG_FILE="$CONFIG_DIR/config.toml"

log "platform: $MACHINE ($ARCH_DIR) — mode: $MODE"
log "install paths: binary=$BINARY config=$CONFIG_FILE"

# ─── Verify token state ────────────────────────────────────────────────────
if ! $UPDATE_ONLY; then
    if [ -z "$TOKEN" ] && [ ! -f "$CONFIG_FILE" ]; then
        fail "--token is required on first install. Create one in the dashboard and re-run."
    fi
    if [ -n "$TOKEN" ] && [ -f "$CONFIG_FILE" ]; then
        warn "existing config found — ignoring --token (already registered)"
        TOKEN=""
    fi
fi

# ─── Ensure dirs ───────────────────────────────────────────────────────────
run "mkdir -p '$BIN_DIR' '$CONFIG_DIR' '$LOG_DIR'"
[ "$MODE" = "user" ] && run "mkdir -p '$(dirname "$SERVICE_FILE")'"

# ─── Download binary ───────────────────────────────────────────────────────
TMP_BINARY="$CONFIG_DIR/.dugnad-agent.new"
TMP_CHECKSUM="$CONFIG_DIR/.dugnad-agent.sha256"
log "downloading $BINARY_URL"
if $DRY_RUN; then
    run "curl -fSL --retry 3 --max-time 300 '$BINARY_URL' -o '$TMP_BINARY'"
    run "curl -fSL --retry 3 --max-time 60 '$CHECKSUM_URL' -o '$TMP_CHECKSUM'"
else
    curl -fSL --retry 3 --max-time 300 "$BINARY_URL" -o "$TMP_BINARY" \
        || fail "download failed from $BINARY_URL"
    curl -fSL --retry 3 --max-time 60 "$CHECKSUM_URL" -o "$TMP_CHECKSUM" \
        || fail "checksum download failed from $CHECKSUM_URL"
    command -v sha256sum >/dev/null \
        || fail "sha256sum is required for checksum verification (install coreutils)"
    EXPECTED_SHA=$(awk '{print $1}' "$TMP_CHECKSUM")
    [ -n "$EXPECTED_SHA" ] || fail "checksum file is empty or malformed: $CHECKSUM_URL"
    ACTUAL_SHA=$(sha256sum "$TMP_BINARY" | awk '{print $1}')
    if [ "$EXPECTED_SHA" != "$ACTUAL_SHA" ]; then
        rm -f "$TMP_BINARY" "$TMP_CHECKSUM"
        fail "checksum mismatch — binary may be tampered. expected=$EXPECTED_SHA got=$ACTUAL_SHA"
    fi
    rm -f "$TMP_CHECKSUM"
    log "checksum verified: $EXPECTED_SHA"
    chmod +x "$TMP_BINARY"
fi

# ─── Stop service before replacing binary (avoid ETXTBSY) ──────────────────
SERVICE_WAS_RUNNING=false
case "$MODE" in
    termux)
        if [ -d "$SERVICE_DIR" ]; then
            SERVICE_WAS_RUNNING=true
            log "stopping dugnad-agent (runit)"
            run "echo -n t > '$SERVICE_DIR/supervise/control' 2>/dev/null || true"
            sleep 1
        fi
        ;;
    system)
        if systemctl is-active --quiet dugnad-agent 2>/dev/null; then
            SERVICE_WAS_RUNNING=true
            log "stopping dugnad-agent (systemd)"
            run "systemctl stop dugnad-agent"
        fi
        ;;
    user)
        if systemctl --user is-active --quiet dugnad-agent 2>/dev/null; then
            SERVICE_WAS_RUNNING=true
            log "stopping dugnad-agent (systemd --user)"
            run "systemctl --user stop dugnad-agent"
        fi
        ;;
esac

run "mv '$TMP_BINARY' '$BINARY'"
log "binary installed: $(${DRY_RUN} && echo '<dry-run>' || "$BINARY" --version 2>/dev/null || echo 'installed')"

# ─── Write config (first install only) ─────────────────────────────────────
if [ ! -f "$CONFIG_FILE" ]; then
    NODE_LABEL="${LABEL:-$(hostname -s 2>/dev/null || hostname 2>/dev/null || echo dugnad)}"
    log "writing $CONFIG_FILE"
    if $DRY_RUN; then
        echo "  # config content would include: coordinator_url, node_name=$NODE_LABEL, registration_token, log_dir"
    else
        cat > "$CONFIG_FILE" <<EOF
[agent]
transport = "http"
coordinator_url = "$COORDINATOR"
heartbeat_interval_secs = 30
node_name = "$NODE_LABEL"
log_dir = "$LOG_DIR"
registration_token = "$TOKEN"

[capabilities.health]
enabled = true
interval_secs = 60
EOF
        chmod 600 "$CONFIG_FILE"
    fi
else
    log "keeping existing config at $CONFIG_FILE"
fi

# ─── Write service unit ────────────────────────────────────────────────────
case "$MODE" in
    termux)
        log "installing runit service at $SERVICE_DIR"
        run "mkdir -p '$SERVICE_DIR' '$SERVICE_DIR/log'"
        if ! $DRY_RUN; then
            cat > "$SERVICE_DIR/run" <<EOF
#!/data/data/com.termux/files/usr/bin/sh
exec 2>&1
exec $BINARY $CONFIG_FILE
EOF
            chmod +x "$SERVICE_DIR/run"
            cat > "$SERVICE_DIR/log/run" <<EOF
#!/data/data/com.termux/files/usr/bin/sh
exec svlogd -tt $LOG_DIR
EOF
            chmod +x "$SERVICE_DIR/log/run"
        fi
        ;;
    system)
        log "installing systemd unit at $SERVICE_FILE"
        if ! $DRY_RUN; then
            cat > "$SERVICE_FILE" <<EOF
[Unit]
Description=Dugnad Agent — P2P job execution
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=$BINARY $CONFIG_FILE
Restart=always
RestartSec=5
Environment=RUST_LOG=info

[Install]
WantedBy=multi-user.target
EOF
        fi
        run "systemctl daemon-reload"
        run "systemctl enable dugnad-agent"
        ;;
    user)
        log "installing user systemd unit at $SERVICE_FILE"
        if ! $DRY_RUN; then
            cat > "$SERVICE_FILE" <<EOF
[Unit]
Description=Dugnad Agent — P2P job execution
After=network-online.target

[Service]
Type=simple
ExecStart=$BINARY $CONFIG_FILE
Restart=always
RestartSec=5
Environment=RUST_LOG=info

[Install]
WantedBy=default.target
EOF
        fi
        run "systemctl --user daemon-reload"
        run "systemctl --user enable dugnad-agent"
        if ! systemctl --user show-environment 2>/dev/null | grep -q XDG_RUNTIME_DIR; then
            warn "systemd --user may stop when you log out. Enable lingering with: sudo loginctl enable-linger $(id -un)"
        fi
        ;;
esac

# ─── Start service ─────────────────────────────────────────────────────────
case "$MODE" in
    termux)
        # runsvdir picks up new services within 5s of SVDIR scan
        log "starting dugnad-agent (runit will pick it up within 5s)"
        # Nudge runsvdir if not running
        if ! pgrep -x runsvdir >/dev/null 2>&1; then
            warn "runsvdir is not running — starting it"
            run "setsid runsvdir -P '$SVDIR' >/dev/null 2>&1 &"
        fi
        ;;
    system)
        run "systemctl start dugnad-agent"
        ;;
    user)
        run "systemctl --user start dugnad-agent"
        ;;
esac

# ─── Post-install summary ──────────────────────────────────────────────────
log "done. dugnad-agent is installed and starting."
case "$MODE" in
    termux) echo "    check status: sv status dugnad-agent"
            echo "    tail logs:    tail -f $LOG_DIR/current" ;;
    system) echo "    check status: systemctl status dugnad-agent"
            echo "    tail logs:    journalctl -u dugnad-agent -f" ;;
    user)   echo "    check status: systemctl --user status dugnad-agent"
            echo "    tail logs:    journalctl --user -u dugnad-agent -f" ;;
esac
echo "    coordinator:  $COORDINATOR"
if [ -n "$TOKEN" ]; then
    echo "    registration: pending (will bind on first successful heartbeat)"
fi
