#!/usr/bin/env bash
set -euo pipefail

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
VENV_DIR="${FGAI_VENV_DIR:-$ROOT_DIR/.venv}"
PORT="${FGAI_SYSLOG_PORT:-5514}"
HOST="${FGAI_SYSLOG_HOST:-0.0.0.0}"
LOG_FILE="${FGAI_SYSLOG_FILE:-$ROOT_DIR/logs/fg_syslog.jsonl}"
LOG_ROTATE_BYTES="${FGAI_LOG_ROTATE_BYTES:-26214400}"
LOG_ROTATE_COUNT="${FGAI_LOG_ROTATE_COUNT:-14}"
LISTENER_LOG="${FGAI_LISTENER_LOG:-$ROOT_DIR/logs/fgai-listener.log}"
POLICY_FILE="${FGAI_POLICY_FILE:-$ROOT_DIR/exports/policies.json}"
STATE_FILE="${FGAI_STATE_FILE:-$ROOT_DIR/state/fgai-status.json}"
CONFIG_FILE="${FGAI_CONFIG_FILE:-$ROOT_DIR/state/fgai-config.json}"
BASELINE_DB="${FGAI_BASELINE_DB:-$ROOT_DIR/state/fgai-baseline.sqlite3}"
HISTORY_DB="${FGAI_HISTORY_DB:-$ROOT_DIR/state/signalscope-history.sqlite3}"
STATUS_CACHE_DB="${FGAI_STATUS_CACHE_DB:-$ROOT_DIR/state/signalscope-status-cache.sqlite3}"
MONITOR_INTERVAL="${FGAI_MONITOR_INTERVAL:-10}"
LLM_ENABLED="${FGAI_LLM:-0}"
LLM_INTERVAL="${FGAI_LLM_INTERVAL:-300}"
LLM_TIMEOUT="${OLLAMA_TIMEOUT:-180}"
LLM_MODEL="${OLLAMA_MODEL:-}"
DASHBOARD_HOST="${FGAI_DASHBOARD_HOST:-127.0.0.1}"
DASHBOARD_PORT="${FGAI_DASHBOARD_PORT:-8088}"
LISTENER_PID_FILE="${FGAI_LISTENER_PID_FILE:-$ROOT_DIR/run/fgai-listener.pid}"
MONITOR_PID_FILE="${FGAI_MONITOR_PID_FILE:-$ROOT_DIR/run/fgai-monitor.pid}"
DASHBOARD_PID_FILE="${FGAI_DASHBOARD_PID_FILE:-$ROOT_DIR/run/fgai-dashboard.pid}"
MONITOR_LOG="${FGAI_MONITOR_LOG:-$ROOT_DIR/logs/fgai-monitor.log}"
DASHBOARD_LOG="${FGAI_DASHBOARD_LOG:-$ROOT_DIR/logs/fgai-dashboard.log}"

usage() {
    printf 'Usage: %s [start|stop|restart|status|tail|analyze|install]\n' "$0"
    printf '\nDefault action: start\n'
    printf '\nEnvironment overrides:\n'
    printf '  FGAI_SYSLOG_PORT=%s\n' "$PORT"
    printf '  FGAI_SYSLOG_HOST=%s\n' "$HOST"
    printf '  FGAI_SYSLOG_FILE=%s\n' "$LOG_FILE"
    printf '  FGAI_LOG_ROTATE_BYTES=%s\n' "$LOG_ROTATE_BYTES"
    printf '  FGAI_LOG_ROTATE_COUNT=%s\n' "$LOG_ROTATE_COUNT"
    printf '  FGAI_LISTENER_LOG=%s\n' "$LISTENER_LOG"
    printf '  FGAI_DASHBOARD_PORT=%s\n' "$DASHBOARD_PORT"
    printf '  FGAI_LLM=%s\n' "$LLM_ENABLED"
}

activate_venv_for_script() {
    # Activation here affects this script process. It cannot modify the parent shell prompt.
    # Use "source .venv/bin/activate" manually if you want your interactive prompt to show it.
    # shellcheck disable=SC1091
    source "$VENV_DIR/bin/activate"
}

install_deps() {
    if [ ! -x "$VENV_DIR/bin/python" ]; then
        printf 'Creating venv: %s\n' "$VENV_DIR"
        python3 -m venv "$VENV_DIR"
    fi

    activate_venv_for_script
    printf 'Installing/updating fgAI dependencies...\n'
    python -m pip install --upgrade pip
    python -m pip install -e "$ROOT_DIR"
}

is_pid_running() {
    [ -f "$1" ] && ps -p "$(cat "$1")" >/dev/null 2>&1
}

needs_privileged_port() {
    [ "$PORT" -lt 1024 ] && [ "${EUID:-$(id -u)}" -ne 0 ]
}

listener_command() {
    "$VENV_DIR/bin/fgai" listen-syslog \
        --host "$HOST" \
        --port "$PORT" \
        --output "$LOG_FILE" \
        --quiet
}

start_listener() {
    install_deps
    mkdir -p "$(dirname "$LOG_FILE")" "$(dirname "$LISTENER_LOG")" "$(dirname "$LISTENER_PID_FILE")" "$(dirname "$STATE_FILE")"
    touch "$LOG_FILE"

    if is_pid_running "$LISTENER_PID_FILE"; then
        printf 'fgAI syslog listener already running, pid %s\n' "$(cat "$LISTENER_PID_FILE")"
        return 0
    fi

    if needs_privileged_port; then
        printf 'Port %s needs elevated privileges; starting listener with sudo.\n' "$PORT"
        sudo nohup "$VENV_DIR/bin/fgai" listen-syslog \
            --host "$HOST" \
            --port "$PORT" \
            --output "$LOG_FILE" \
            --rotate-bytes "$LOG_ROTATE_BYTES" \
            --rotate-count "$LOG_ROTATE_COUNT" \
            --quiet > "$LISTENER_LOG" 2>&1 &
    else
        nohup "$VENV_DIR/bin/fgai" listen-syslog \
            --host "$HOST" \
            --port "$PORT" \
            --output "$LOG_FILE" \
            --rotate-bytes "$LOG_ROTATE_BYTES" \
            --rotate-count "$LOG_ROTATE_COUNT" \
            --quiet > "$LISTENER_LOG" 2>&1 &
    fi
    printf '%s\n' "$!" > "$LISTENER_PID_FILE"

    printf 'Started fgAI syslog listener, pid %s\n' "$(cat "$LISTENER_PID_FILE")"
    printf 'Input: udp://%s:%s\n' "$HOST" "$PORT"
    printf 'Syslog file: %s\n' "$LOG_FILE"
    printf 'Process log: %s\n' "$LISTENER_LOG"
}

start_monitor() {
    install_deps
    mkdir -p "$(dirname "$STATE_FILE")" "$(dirname "$MONITOR_LOG")" "$(dirname "$MONITOR_PID_FILE")"

    if is_pid_running "$MONITOR_PID_FILE"; then
        printf 'fgAI monitor already running, pid %s\n' "$(cat "$MONITOR_PID_FILE")"
        return 0
    fi

    monitor_args=(monitor --logs "$LOG_FILE" --output "$STATE_FILE" --interval "$MONITOR_INTERVAL" --baseline-db "$BASELINE_DB" --history-db "$HISTORY_DB" --status-cache-db "$STATUS_CACHE_DB" --config-file "$CONFIG_FILE")
    if [ -f "$POLICY_FILE" ]; then
        monitor_args+=(--policies "$POLICY_FILE")
    fi
    if [ "$LLM_ENABLED" = "1" ] || [ "$LLM_ENABLED" = "true" ]; then
        monitor_args+=(--llm --llm-interval "$LLM_INTERVAL" --llm-timeout "$LLM_TIMEOUT")
        if [ -n "$LLM_MODEL" ]; then
            monitor_args+=(--model "$LLM_MODEL")
        fi
    fi

    nohup "$VENV_DIR/bin/fgai" "${monitor_args[@]}" > "$MONITOR_LOG" 2>&1 &
    printf '%s\n' "$!" > "$MONITOR_PID_FILE"
    printf 'Started fgAI monitor, pid %s\n' "$(cat "$MONITOR_PID_FILE")"
    printf 'Status file: %s\n' "$STATE_FILE"
}

start_dashboard() {
    install_deps
    mkdir -p "$(dirname "$DASHBOARD_LOG")" "$(dirname "$DASHBOARD_PID_FILE")"

    if is_pid_running "$DASHBOARD_PID_FILE"; then
        printf 'fgAI dashboard already running, pid %s\n' "$(cat "$DASHBOARD_PID_FILE")"
        return 0
    fi

    nohup "$VENV_DIR/bin/fgai" dashboard \
        --host "$DASHBOARD_HOST" \
        --port "$DASHBOARD_PORT" \
        --status-file "$STATE_FILE" \
        --config-file "$CONFIG_FILE" \
        --image-dir "$ROOT_DIR/images" > "$DASHBOARD_LOG" 2>&1 &
    printf '%s\n' "$!" > "$DASHBOARD_PID_FILE"
    printf 'Started fgAI dashboard, pid %s\n' "$(cat "$DASHBOARD_PID_FILE")"
    printf 'Dashboard: http://%s:%s\n' "$DASHBOARD_HOST" "$DASHBOARD_PORT"
}

start_all() {
    start_listener
    start_monitor
    start_dashboard
}

stop_pid() {
    label="$1"
    pid_file="$2"
    if ! is_pid_running "$pid_file"; then
        printf '%s is not running\n' "$label"
        rm -f "$pid_file"
        return 0
    fi

    if ! kill "$(cat "$pid_file")" 2>/dev/null; then
        sudo kill "$(cat "$pid_file")"
    fi
    rm -f "$pid_file"
    printf 'Stopped %s\n' "$label"
}

stop_all() {
    stop_pid "fgAI dashboard" "$DASHBOARD_PID_FILE"
    stop_pid "fgAI monitor" "$MONITOR_PID_FILE"
    stop_pid "fgAI syslog listener" "$LISTENER_PID_FILE"
}

status_one() {
    label="$1"
    pid_file="$2"
    if is_pid_running "$pid_file"; then
        printf '%s running, pid %s\n' "$label" "$(cat "$pid_file")"
        return 0
    fi
    printf '%s is not running\n' "$label"
    return 1
}

status_all() {
    status_one "fgAI syslog listener" "$LISTENER_PID_FILE" || true
    if is_pid_running "$LISTENER_PID_FILE"; then
        printf 'Input: udp://%s:%s\n' "$HOST" "$PORT"
        printf 'Syslog file: %s\n' "$LOG_FILE"
        if command -v ss >/dev/null 2>&1; then
            ss -lunp 2>/dev/null | awk -v port=":$PORT" '$0 ~ port {print}'
        fi
    fi
    status_one "fgAI monitor" "$MONITOR_PID_FILE" || true
    status_one "fgAI dashboard" "$DASHBOARD_PID_FILE" || true
    printf 'Dashboard: http://%s:%s\n' "$DASHBOARD_HOST" "$DASHBOARD_PORT"
    printf 'Status file: %s\n' "$STATE_FILE"
}

command="${1:-start}"
case "$command" in
    start)
        start_all
        ;;
    stop)
        stop_all
        ;;
    restart)
        stop_all
        start_all
        ;;
    status)
        status_all
        ;;
    tail)
        mkdir -p "$(dirname "$LOG_FILE")"
        touch "$LOG_FILE"
        tail -f "$LOG_FILE"
        ;;
    analyze)
        install_deps
        fgai analyze-logs --logs "$LOG_FILE"
        ;;
    install)
        install_deps
        ;;
    -h|--help|help)
        usage
        ;;
    *)
        usage
        exit 2
        ;;
esac
