#!/bin/bash
# khaosd-ctl — daemon lifecycle helper for Khaos Machine
# Uses launchctl (macOS) or systemctl (Linux) to manage khaosd.
set -euo pipefail

# The agent Khaos App carries in its bundle and registers through SMAppService.
LABEL="studio.khaos.app.khaosd"
RUNTIME_JSON="${HOME}/.khaos/runtime.json"
KHAOSD_BIN="/usr/local/bin/khaosd"

usage() {
  cat <<EOF
Usage: khaosd-ctl <command>

Commands:
  start          Start the khaosd daemon
  stop           Stop the khaosd daemon
  restart        Restart the khaosd daemon
  status         Show daemon status (PID, port, version)
  logs           Follow the daemon console log
  logs --errors  Show recent error entries only

EOF
  exit 1
}

# --- platform helpers --------------------------------------------------------

is_macos() { [ "$(uname -s)" = "Darwin" ]; }

macos_service_target() { echo "gui/$(id -u)/${LABEL}"; }

macos_agent_loaded() {
  launchctl print "$(macos_service_target)" >/dev/null 2>&1
}

macos_agent_running() {
  local state
  state=$(launchctl print "$(macos_service_target)" 2>/dev/null | awk '/^\tstate =/{print $3; exit}')
  [ "$state" = "running" ]
}

linux_unit_exists() {
  systemctl --user cat khaosd.service >/dev/null 2>&1
}

# --- runtime.json reader -----------------------------------------------------

read_runtime() {
  if [ -f "$RUNTIME_JSON" ]; then
    local pid port version
    pid=$(grep -o '"pid": *[0-9]*' "$RUNTIME_JSON" | grep -o '[0-9]*')
    port=$(grep -o '"port": *[0-9]*' "$RUNTIME_JSON" | grep -o '[0-9]*')
    version=$(grep -o '"version": *"[^"]*"' "$RUNTIME_JSON" | sed 's/.*"\([^"]*\)"$/\1/')
    echo "$pid $port $version"
  fi
}

# --- commands ----------------------------------------------------------------

do_start() {
  if is_macos; then
    if macos_agent_loaded; then
      launchctl kickstart "$(macos_service_target)" 2>/dev/null || true
      echo "khaosd starting via LaunchAgent"
    else
      echo "LaunchAgent not loaded — starting khaosd directly"
      nohup "$KHAOSD_BIN" >/dev/null 2>&1 &
    fi
  else
    if linux_unit_exists; then
      systemctl --user start khaosd
      echo "khaosd starting via systemd"
    else
      echo "systemd unit not found — starting khaosd directly"
      nohup "$KHAOSD_BIN" >/dev/null 2>&1 &
    fi
  fi
}

do_stop() {
  if is_macos; then
    if macos_agent_loaded; then
      launchctl kill SIGTERM "$(macos_service_target)" 2>/dev/null || true
      echo "khaosd stop requested via LaunchAgent"
    else
      # Fallback: send SIGTERM to PID from runtime.json
      local info
      info=$(read_runtime)
      if [ -n "$info" ]; then
        local pid
        pid=$(echo "$info" | awk '{print $1}')
        if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
          kill -TERM "$pid" 2>/dev/null || true
          echo "khaosd (pid $pid) sent SIGTERM"
        fi
      else
        echo "khaosd is not running"
      fi
    fi
  else
    if linux_unit_exists; then
      systemctl --user stop khaosd
      echo "khaosd stopped via systemd"
    else
      local info
      info=$(read_runtime)
      if [ -n "$info" ]; then
        local pid
        pid=$(echo "$info" | awk '{print $1}')
        if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
          kill -TERM "$pid" 2>/dev/null || true
          echo "khaosd (pid $pid) sent SIGTERM"
        fi
      else
        echo "khaosd is not running"
      fi
    fi
  fi
}

# Wait for khaosd to finish its own shutdown, however long that takes. khaosd
# bounds it (server shutdown, job cancel, service stop), then removes
# runtime.json and releases its lock before exiting, so the pid being gone is
# the signal that both have happened. A guessed sleep either starts a second
# khaosd that loses the lock, or kickstarts a LaunchAgent job that is still
# running and so does nothing; either way khaosd ends up stopped.
wait_for_exit() {
  local pid="$1" waited=0
  while kill -0 "$pid" 2>/dev/null; do
    if [ "$waited" -gt 0 ] && [ $((waited % 5)) -eq 0 ]; then
      echo "waiting for khaosd (pid $pid) to finish shutting down (${waited}s)"
    fi
    sleep 1
    waited=$((waited + 1))
  done
  if [ -f "$RUNTIME_JSON" ] && grep -Eq "\"pid\": *${pid}([^0-9]|$)" "$RUNTIME_JSON"; then
    echo "khaosd (pid $pid) exited without removing $RUNTIME_JSON"
  fi
}

do_restart() {
  local info pid=""
  info=$(read_runtime)
  if [ -n "$info" ]; then
    pid=$(echo "$info" | awk '{print $1}')
  fi
  do_stop
  if [ -n "$pid" ]; then
    wait_for_exit "$pid"
  fi
  do_start
}

do_status() {
  local running="no"
  local info pid port version

  # Check via service manager first
  if is_macos; then
    if macos_agent_loaded && macos_agent_running; then
      running="yes (LaunchAgent)"
    fi
  else
    if linux_unit_exists && systemctl --user is-active --quiet khaosd 2>/dev/null; then
      running="yes (systemd)"
    fi
  fi

  # Read runtime.json for details
  info=$(read_runtime)
  if [ -n "$info" ]; then
    pid=$(echo "$info" | awk '{print $1}')
    port=$(echo "$info" | awk '{print $2}')
    version=$(echo "$info" | awk '{print $3}')

    # Validate PID is alive
    if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
      [ "$running" = "no" ] && running="yes (direct)"
      echo "Status:  running"
      echo "PID:     $pid"
      echo "Port:    $port"
      echo "Version: $version"
      echo "Managed: $running"
      return 0
    else
      # Stale runtime.json
      echo "Status:  stopped (stale runtime.json found)"
      return 1
    fi
  fi

  if [ "$running" != "no" ]; then
    echo "Status:  starting (no runtime.json yet)"
    return 0
  fi

  echo "Status:  stopped"
  return 1
}

# --- main --------------------------------------------------------------------

[ $# -lt 1 ] && usage

do_logs() {
  local log_dir="${HOME}/.khaos/logs"
  local console_log="$log_dir/khaosd-console.log"

  if [ ! -d "$log_dir" ]; then
    echo "Log directory not found: $log_dir"
    echo "Falling back to console API..."
    # Fallback: try the API
    local info
    info=$(read_runtime)
    if [ -n "$info" ]; then
      local port
      port=$(echo "$info" | awk '{print $2}')
      if [ -n "$port" ]; then
        # Dump raw NDJSON from console API (pipe through jq for formatting)
        curl -s "http://127.0.0.1:${port}/api/console/entries" 2>/dev/null
      fi
    fi
    return 0
  fi

  if [ "${2:-}" = "--errors" ]; then
    if [ -f "$console_log" ]; then
      grep '"level":"error"' "$console_log" 2>/dev/null | tail -50
    else
      echo "No console log found yet at $console_log"
      echo "Hint: persistent console logging requires khaosd with file-backed console (coming soon)"
    fi
  else
    if [ -f "$console_log" ]; then
      tail -f "$console_log"
    else
      echo "No console log found yet at $console_log"
      echo "Hint: persistent console logging requires khaosd with file-backed console (coming soon)"
      echo ""
      echo "Current logs available:"
      ls -la "$log_dir"/ 2>/dev/null || echo "  (empty)"
    fi
  fi
}

case "${1}" in
  start)   do_start   ;;
  stop)    do_stop    ;;
  restart) do_restart ;;
  status)  do_status  ;;
  logs)    do_logs "${2:-}" ;;
  *)       usage      ;;
esac
