#!/bin/bash
# SwarmAI Backend Daemon — wrapper script for launchd
#
# Runs the PyInstaller-built backend binary from ~/.swarm-ai/daemon/.
# This binary is produced by `./dev.sh deploy` and copied here automatically.
#
# IMPORTANT: The daemon NEVER runs from the dev source directory.
# Code changes only take effect after: ./dev.sh deploy
# This prevents untested changes from crashing the production daemon.
#
# Fallback: if no binary exists (first install), falls back to venv Python.
#
# Usage: launchd runs this via com.swarmai.backend.plist
#        Manual: ./swarmai_backend.sh
#
# Port conflict: if 18321 is already bound, exits 0 (launchd won't retry).

set -euo pipefail

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

DAEMON_PORT=18321
DAEMON_BINARY="${HOME}/.swarm-ai/daemon/python-backend"
LOG_DIR="${HOME}/.swarm-ai/logs"

# Fallback: source directory (only used if binary not built yet)
if [ -n "${SWARMAI_BACKEND_DIR:-}" ]; then
    BACKEND_DIR="${SWARMAI_BACKEND_DIR}"
else
    BACKEND_DIR="$(cd "$(dirname "$0")/.." && pwd)"
fi
VENV_PYTHON="${BACKEND_DIR}/.venv/bin/python"

# ---------------------------------------------------------------------------
# Port conflict check
# ---------------------------------------------------------------------------

FAIL_STAMP="${HOME}/.swarm-ai/.daemon-port-fail"
if nc -z 127.0.0.1 "${DAEMON_PORT}" 2>/dev/null; then
    FAIL_COUNT=$(cat "$FAIL_STAMP" 2>/dev/null || echo 0)
    FAIL_COUNT=$((FAIL_COUNT + 1))
    echo "$FAIL_COUNT" > "$FAIL_STAMP"
    if [ "$FAIL_COUNT" -ge 3 ]; then
        echo "[swarmai-backend] Port ${DAEMON_PORT} occupied ${FAIL_COUNT}x — giving up (exit 0)"
        rm -f "$FAIL_STAMP"
        exit 0  # Stop retrying — something else genuinely owns this port
    fi
    echo "[swarmai-backend] Port ${DAEMON_PORT} in use (attempt ${FAIL_COUNT}/3) — retrying via launchd"
    exit 1  # Non-zero → launchd KeepAlive triggers retry after ThrottleInterval
fi
rm -f "$FAIL_STAMP"  # Port is free — reset failure counter

# ---------------------------------------------------------------------------
# Environment — inherit user's login shell PATH
# ---------------------------------------------------------------------------
# launchd starts daemons with a minimal PATH (/usr/bin:/bin:/usr/sbin:/sbin).
# The Claude CLI subprocess needs the full user PATH to resolve:
#   - credential_process (ada → ~/.toolbox/bin/ada)
#   - mise-managed runtimes (node, python)
#   - homebrew tools
# Source the login shell to pick up PATH additions from .zprofile/.bash_profile.

_login_shell="$(dscl . -read /Users/"$(whoami)" UserShell 2>/dev/null | awk '{print $2}')"
_login_shell="${_login_shell:-/bin/zsh}"
if _full_path="$("${_login_shell}" -l -c 'echo $PATH' 2>/dev/null)"; then
    export PATH="${_full_path}"
fi

# Fallback: ensure common tool directories are on PATH even if shell
# sourcing failed (e.g. non-interactive shell, missing profile).
for _dir in \
    "${HOME}/.toolbox/bin" \
    "${HOME}/.local/bin" \
    "${HOME}/.local/share/mise/shims" \
    "/opt/homebrew/bin" \
    "/usr/local/bin"; do
    case ":${PATH}:" in
        *":${_dir}:"*) ;;  # already present
        *) [ -d "${_dir}" ] && export PATH="${_dir}:${PATH}" ;;
    esac
done

mkdir -p "${LOG_DIR}"

# Fixed port for daemon mode (overrides config.py default)
export SWARMAI_PORT="${DAEMON_PORT}"

# Mark as daemon mode — Tauri reads this via /api/system/mode
export SWARMAI_MODE="daemon"

# Ensure AWS credentials are accessible (SSO tokens are file-based)
export HOME="${HOME}"

# Strip proxy vars — daemon manages its own networking
unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy ALL_PROXY all_proxy NO_PROXY no_proxy 2>/dev/null || true

# ---------------------------------------------------------------------------
# Resolve backend executable
# ---------------------------------------------------------------------------
# Priority: PyInstaller binary > venv Python (fallback)
# The binary is placed by `./dev.sh deploy` into ~/.swarm-ai/daemon/.
# This ensures the daemon ONLY runs tested, built code.

if [ -x "${DAEMON_BINARY}" ]; then
    LAUNCH_MODE="binary"
    echo "[swarmai-backend] Starting BINARY on port ${DAEMON_PORT} at $(date '+%Y-%m-%d %H:%M:%S')"
    echo "[swarmai-backend] Binary: ${DAEMON_BINARY}"
    echo "[swarmai-backend] Binary age: $(( ($(date +%s) - $(stat -f %m "${DAEMON_BINARY}")) / 60 ))min"
    VERSION_FILE="${HOME}/.swarm-ai/daemon/.version"
    if [ -f "${VERSION_FILE}" ]; then
        echo "[swarmai-backend] Binary version: $(cat "${VERSION_FILE}")"
    fi
    echo "[swarmai-backend] PATH: ${PATH}"
    echo "[swarmai-backend] ada: $(which ada 2>/dev/null || echo 'NOT FOUND')"

    # caffeinate -i: prevent idle sleep only (allow lid-close/system sleep to save battery)
    exec caffeinate -i "${DAEMON_BINARY}" \
        --host 127.0.0.1 \
        --port "${DAEMON_PORT}"

elif [ -x "${VENV_PYTHON}" ]; then
    LAUNCH_MODE="venv-fallback"
    echo "[swarmai-backend] WARNING: No binary at ${DAEMON_BINARY}"
    echo "[swarmai-backend] Falling back to venv Python (run './dev.sh deploy' to fix)"
    echo "[swarmai-backend] Starting VENV FALLBACK on port ${DAEMON_PORT} at $(date '+%Y-%m-%d %H:%M:%S')"
    echo "[swarmai-backend] Backend dir: ${BACKEND_DIR}"
    echo "[swarmai-backend] Python: ${VENV_PYTHON}"
    echo "[swarmai-backend] PATH: ${PATH}"
    echo "[swarmai-backend] ada: $(which ada 2>/dev/null || echo 'NOT FOUND')"

    cd "${BACKEND_DIR}"
    exec caffeinate -i "${VENV_PYTHON}" -m uvicorn main:app \
        --host 127.0.0.1 \
        --port "${DAEMON_PORT}" \
        --log-level info

else
    echo "[swarmai-backend] ERROR: No backend binary or venv found" >&2
    echo "[swarmai-backend]   Binary: ${DAEMON_BINARY} (not found)" >&2
    echo "[swarmai-backend]   Venv:   ${VENV_PYTHON} (not found)" >&2
    echo "[swarmai-backend]   Run './dev.sh deploy' to create the binary" >&2
    exit 1
fi
