#!/bin/zsh

set -euo pipefail

export PATH="/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:${PATH:-}"

LABEL="ai.bifrost.gateway"
PORT="${BIFROST_PORT:-8471}"
SCRIPT_DIR=${0:A:h}
PROJECT_ROOT=${SCRIPT_DIR:h}
SOURCE_PLIST="${PROJECT_ROOT}/config/launchd/${LABEL}.plist"
TARGET_PLIST="${HOME}/Library/LaunchAgents/${LABEL}.plist"
SOURCE_CONFIG="${PROJECT_ROOT}/config/bifrost/config.template.json"
TARGET_CONFIG_DIR="${HOME}/.config/bifrost"
TARGET_CONFIG="${TARGET_CONFIG_DIR}/config.json"
TARGET_CONFIG_DB="${TARGET_CONFIG_DIR}/config.db"
TARGET_CONFIG_DB_SHM="${TARGET_CONFIG_DB}-shm"
TARGET_CONFIG_DB_WAL="${TARGET_CONFIG_DB}-wal"
LEGACY_CONFIG_DB="${PROJECT_ROOT}/config.db"
LEGACY_CONFIG_DB_SHM="${PROJECT_ROOT}/config.db-shm"
LEGACY_CONFIG_DB_WAL="${PROJECT_ROOT}/config.db-wal"
LOG_OUT="${HOME}/.local/state/mcp/logs/bifrost.log"
LOG_ERR="${HOME}/.local/state/mcp/logs/bifrost.err"
READY_FILE="${HOME}/.local/state/mcp/ready/bifrost.ready"
GUI_DOMAIN="gui/$(id -u)"
TOGGLE_HELPER="${SCRIPT_DIR}/bifrost-toggle-claude-url"

usage() {
    print "Usage: bifrost-ctl {install|sync-config|start|stop|restart|rebootstrap|status|tail|foreground}"
}

install_plist() {
    mkdir -p "${HOME}/Library/LaunchAgents"
    cp "${SOURCE_PLIST}" "${TARGET_PLIST}"
    plutil -lint "${TARGET_PLIST}" >/dev/null
}

bootstrap() {
    launchctl bootstrap "${GUI_DOMAIN}" "${TARGET_PLIST}"
}

bootout() {
    launchctl bootout "${GUI_DOMAIN}/${LABEL}" >/dev/null 2>&1 || true
    launchctl bootout "${GUI_DOMAIN}" "${TARGET_PLIST}" >/dev/null 2>&1 || true
}

kill_listener() {
    local pids
    pids=("${(@f)$(lsof -tiTCP:${PORT} -sTCP:LISTEN 2>/dev/null || true)}")
    if (( ${#pids[@]} == 0 )); then
        return 0
    fi

    kill "${pids[@]}" >/dev/null 2>&1 || true
    sleep 1

    pids=("${(@f)$(lsof -tiTCP:${PORT} -sTCP:LISTEN 2>/dev/null || true)}")
    if (( ${#pids[@]} > 0 )); then
        kill -9 "${pids[@]}" >/dev/null 2>&1 || true
    fi
}

rebootstrap_config() {
    mkdir -p "${TARGET_CONFIG_DIR}"
    cp "${SOURCE_CONFIG}" "${TARGET_CONFIG}"
    rm -f "${TARGET_CONFIG_DB}" "${TARGET_CONFIG_DB_SHM}" "${TARGET_CONFIG_DB_WAL}"
    rm -f "${LEGACY_CONFIG_DB}" "${LEGACY_CONFIG_DB_SHM}" "${LEGACY_CONFIG_DB_WAL}"
}

print_ready_state() {
    if [[ -f "${READY_FILE}" ]]; then
        print "ready file: ${READY_FILE}"
    else
        print "ready file missing: ${READY_FILE}"
    fi
}

wait_for_ready_file() {
    local timeout="${1:-60}"
    local i
    for i in $(seq 1 "${timeout}"); do
        if [[ -f "${READY_FILE}" ]]; then
            return 0
        fi
        sleep 1
    done
    return 1
}

toggle_claude_url() {
    local action="$1"
    if [[ ! -x "${TOGGLE_HELPER}" ]]; then
        print "warning: toggle helper not found at ${TOGGLE_HELPER}; skipping"
        return 0
    fi
    python3 "${TOGGLE_HELPER}" "${action}" || true
}

foreground_run() {
    # Run the gateway wrapper directly in this shell. Used when the
    # LaunchAgent-managed start path cannot bind the native binary
    # (e.g., macOS Gatekeeper rejecting an unsigned cross-compiled Go
    # binary). Press Ctrl-C to stop; the trap restores Claude's URL.
    kill_listener
    trap 'toggle_claude_url direct; rm -f "${READY_FILE}"' EXIT INT TERM
    local py="${PROJECT_ROOT}/.venv/bin/python3"
    [[ -x "$py" ]] || py="python3"
    "$py" "${SCRIPT_DIR}/bifrost-gateway.py" &
    local wrapper_pid=$!
    if wait_for_ready_file 60; then
        toggle_claude_url bifrost
    else
        print "warning: ${READY_FILE} not seen within 60s; leaving Claude URL untouched"
    fi
    wait "${wrapper_pid}"
    return $?
}

case "${1:-}" in
    install)
        install_plist
        print "Installed ${TARGET_PLIST}"
        ;;
    sync-config)
        rebootstrap_config
        print "Synced ${TARGET_CONFIG}"
        ;;
    start)
        install_plist
        bootout
        kill_listener
        sleep 1
        bootstrap
        launchctl kickstart -k "${GUI_DOMAIN}/${LABEL}"
        if wait_for_ready_file 60; then
            toggle_claude_url bifrost
        else
            print "warning: ${READY_FILE} not seen within 60s; leaving Claude URL untouched"
        fi
        ;;
    stop)
        toggle_claude_url direct
        bootout
        kill_listener
        rm -f "${READY_FILE}"
        ;;
    restart)
        install_plist
        bootout
        kill_listener
        sleep 1
        bootstrap
        launchctl kickstart -k "${GUI_DOMAIN}/${LABEL}"
        if wait_for_ready_file 60; then
            toggle_claude_url bifrost
        else
            print "warning: ${READY_FILE} not seen within 60s; leaving Claude URL untouched"
        fi
        ;;
    rebootstrap)
        install_plist
        bootout
        kill_listener
        rebootstrap_config
        sleep 1
        bootstrap
        launchctl kickstart -k "${GUI_DOMAIN}/${LABEL}"
        if wait_for_ready_file 60; then
            toggle_claude_url bifrost
        else
            print "warning: ${READY_FILE} not seen within 60s; leaving Claude URL untouched"
        fi
        ;;
    status)
        if launchctl print "${GUI_DOMAIN}/${LABEL}" >/tmp/bifrost-status.$$ 2>/dev/null; then
            rg -n "state =|pid =|last exit code =|path =" /tmp/bifrost-status.$$
            rm -f /tmp/bifrost-status.$$
        else
            rm -f /tmp/bifrost-status.$$
            print "service not loaded: ${LABEL}"
        fi
        lsof -nP -iTCP:"${PORT}" -sTCP:LISTEN || true
        print_ready_state
        toggle_claude_url status
        ;;
    tail)
        tail -F "${LOG_OUT}" "${LOG_ERR}"
        ;;
    foreground)
        foreground_run
        ;;
    *)
        usage
        exit 64
        ;;
esac
