#!/usr/bin/env bash
# openai-server nestling installer.
#
# Stands alone. Builds the TS bundle, seeds the per-kind config at
# ~/.config/hum/hives/openai-server.json, installs a user systemd
# unit. Pairs with whatever humd is on the machine via the thrum
# socket — no assumption about how humd was installed.
#
# Usage:
#   hives/openai-server/install            # build + install unit + start
#   hives/openai-server/install uninstall  # stop + remove unit + binary
#
# Env:
#   OPENAI_SERVER_PORT  default 14620
#   OPENAI_SERVER_HOST  default 127.0.0.1
#   HUM_THRUM_SOCK      default $XDG_RUNTIME_DIR/hum/thrum.sock
set -euo pipefail

XDG_CONFIG_HOME="${XDG_CONFIG_HOME:-$HOME/.config}"
HUM_CONFIG="$XDG_CONFIG_HOME/hum"
PORT="${OPENAI_SERVER_PORT:-14620}"
HOST="${OPENAI_SERVER_HOST:-127.0.0.1}"

# Canonical thrum socket — matches WIRE.md + hum installer.
if [ -n "${XDG_RUNTIME_DIR:-}" ]; then
  DEFAULT_SOCK="$XDG_RUNTIME_DIR/hum/thrum.sock"
else
  DEFAULT_SOCK="/tmp/hum-$(id -u)/thrum.sock"
fi
THRUM_SOCK="${HUM_THRUM_SOCK:-$DEFAULT_SOCK}"

NESTDIR="$(cd "$(dirname "$0")" && pwd)"
KIND="openai-server"
UNIT_NAME="hum-$KIND"
UNIT="$XDG_CONFIG_HOME/systemd/user/$UNIT_NAME.service"
CFG="$HUM_CONFIG/hives/$KIND.json"
OS="$(uname -s)"

log()  { printf '\033[1m[%s]\033[0m %s\n' "$KIND" "$*"; }
warn() { printf '\033[1;33m[%s]\033[0m %s\n' "$KIND" "$*" >&2; }
fail() { printf '\033[1;31m[%s]\033[0m %s\n' "$KIND" "$*" >&2; exit 1; }

CMD="${1:-install}"

build() {
  local DIST="$NESTDIR/dist/index.js"
  # Pre-built dist (e.g. produced upstream by `./dev/deploy`) is honored
  # so machines without pnpm can still install the systemd unit.
  if [ -s "$DIST" ] && ! command -v pnpm >/dev/null 2>&1; then
    log "pnpm absent; using pre-built $DIST"
    return 0
  fi
  command -v pnpm >/dev/null 2>&1 || fail "pnpm required. https://pnpm.io/installation"
  log "building (pnpm install + build) in $NESTDIR"
  (cd "$NESTDIR" && pnpm install --silent >/dev/null 2>&1)
  (cd "$NESTDIR" && pnpm run build --silent)
  [ -s "$DIST" ] || fail "build did not produce $DIST"
  log "built: $DIST"
}

# Locate node binary. Prefers $PATH; falls back to fnm's default
# installation so people whose login shell doesn't source fnm still
# get a working systemd unit.
find_node() {
  if command -v node >/dev/null 2>&1; then
    command -v node
    return 0
  fi
  local FNM_DIR="${FNM_DIR:-$HOME/.local/share/fnm}"
  if [ -d "$FNM_DIR/node-versions" ]; then
    local CANDIDATE
    CANDIDATE="$(ls -1 "$FNM_DIR/node-versions" 2>/dev/null | sort -V | tail -1)"
    if [ -x "$FNM_DIR/node-versions/$CANDIDATE/installation/bin/node" ]; then
      echo "$FNM_DIR/node-versions/$CANDIDATE/installation/bin/node"
      return 0
    fi
  fi
  return 1
}

seed_config() {
  mkdir -p "$(dirname "$CFG")"
  if [ -s "$CFG" ]; then
    log "config exists: $CFG ✓"
    return 0
  fi
  cat > "$CFG" <<JSON
{
  "host": "$HOST",
  "port": $PORT,
  "apiKey": ""
}
JSON
  log "wrote default config: $CFG"
}

# Resolve svc.sh — try sibling repo first (running from a clone),
# then the rsynced source tree (paradigm 2 installer flow).
_load_svc() {
  for cand in \
    "$NESTDIR/../../scripts/svc.sh" \
    "$HOME/.local/share/hum/src/scripts/svc.sh" \
  ; do
    if [ -f "$cand" ]; then
      # shellcheck source=/dev/null
      . "$cand"
      return 0
    fi
  done
  return 1
}

install_unit() {
  if ! _load_svc; then
    warn "scripts/svc.sh not found — run 'node $NESTDIR/dist/index.js' manually"
    return 0
  fi
  case "$SVC_OS" in
    Linux|Darwin) ;;
    *) warn "service install unsupported on $SVC_OS. Run 'node $NESTDIR/dist/index.js' manually."; return 0 ;;
  esac
  local NODE_BIN
  NODE_BIN="$(find_node || true)"
  [ -n "$NODE_BIN" ] || fail "node missing. Install node ≥ 18."
  log "node: $NODE_BIN"

  svc_install "$UNIT_NAME" "$NODE_BIN $NESTDIR/dist/index.js" \
    --env "XDG_CONFIG_HOME=$XDG_CONFIG_HOME" \
    --env "XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-/run/user/$(id -u)}" \
    --env "HUM_THRUM_SOCK=$THRUM_SOCK"
  svc_restart "$UNIT_NAME" 2>/dev/null || svc_start "$UNIT_NAME" 2>/dev/null || true
  sleep 1
  if svc_is_active "$UNIT_NAME"; then
    log "$UNIT_NAME running on :$PORT ✓"
    log "  test: curl http://$HOST:$PORT/v1/models"
  else
    warn "$UNIT_NAME did not start cleanly"
  fi
}

uninstall() {
  if _load_svc; then
    svc_uninstall "$UNIT_NAME" 2>/dev/null || true
  fi
  log "uninstalled. Config at $CFG preserved."
}

case "$CMD" in
  install|"")
    build
    seed_config
    install_unit
    ;;
  uninstall) uninstall ;;
  *) fail "unknown command: $CMD (try: install, uninstall)" ;;
esac
