#!/bin/sh
# Launched by /usr/lib/systemd/user/zia-bridge.service.
# Starts the OpenCode sdk-bridge (Node) with the bundled OpenCode CLI on PATH
# and a stable XDG_STATE_HOME, so logs land where the UI expects them.

set -e

DEFAULT_ENV="/usr/share/zia-forsuryaos/defaults/environment"
SYSTEM_ENV="/etc/zia-forsuryaos/environment"
USER_ENV="${XDG_CONFIG_HOME:-$HOME/.config}/zia-forsuryaos/environment"

BRIDGE_DIR="/usr/libexec/zia-forsuryaos/sdk-bridge"
BRIDGE_SCRIPT="$BRIDGE_DIR/bridge.js"
BUNDLED_BIN="/usr/libexec/zia-forsuryaos/bin"

load_env_file() {
  if [ -f "$1" ]; then
    set -a
    # shellcheck disable=SC1090
    . "$1"
    set +a
  fi
}

load_env_file "$DEFAULT_ENV"
load_env_file "$SYSTEM_ENV"
load_env_file "$USER_ENV"

# Pin a stable state dir so the bridge logs land at the same path the QML UI
# resolves via OpenCodeSDK::eventLogDir(). Only set if the unit didn't already.
: "${XDG_STATE_HOME:=$HOME/.local/state}"
export XDG_STATE_HOME

# Project root containing .opencode/ (agents, skills, opencode.jsonc).
# $HOME is the runtime root; self-heal missing .opencode/ from system bundle.
: "${OPENCODE_PROJECT_ROOT:=$HOME}"
export OPENCODE_PROJECT_ROOT

SYSTEM_OPENCODE="/usr/share/zia-forsuryaos/opencode-project/.opencode"
if [ ! -d "$HOME/.opencode" ] && [ -d "$SYSTEM_OPENCODE" ]; then
  cp -a "$SYSTEM_OPENCODE" "$HOME/.opencode"
  echo "zia-bridge-launcher: seeded $HOME/.opencode from system bundle" >&2
fi

mkdir -p "$XDG_STATE_HOME/opencode-bridge/logs" 2>/dev/null || true

# Bundled OpenCode CLI on PATH so the SDK can spawn it without needing the
# curl|bash installer on the user's machine.
if [ -d "$BUNDLED_BIN" ]; then
  PATH="$BUNDLED_BIN:$PATH"
  export PATH
fi

if [ ! -f "$BRIDGE_SCRIPT" ]; then
  echo "zia-bridge-launcher: bridge script not found at $BRIDGE_SCRIPT" >&2
  exit 1
fi

# Resolve a node binary; prefer the system one (Depends: nodejs in control).
NODE_BIN="${NODE_BIN:-$(command -v node || true)}"
if [ -z "$NODE_BIN" ]; then
  echo "zia-bridge-launcher: node not found on PATH (install nodejs)" >&2
  exit 127
fi

# Reap stale bridge AND opencode-serve processes that may still be holding
# ports from a previous service instance.  Without this cleanup the new bridge
# gets EADDRINUSE and the OmniBar shows "Connection refused".
BRIDGE_PORT="${OPENCODE_BRIDGE_PORT:-8765}"
SDK_PORT="${OPENCODE_SDK_PORT:-4096}"
SELF_PID="$$"

reap_port() {
  port="$1"
  match_pattern="$2"
  pids=""
  if command -v fuser >/dev/null 2>&1; then
    pids="$(fuser -n tcp "$port" 2>/dev/null | tr -s ' \t' '\n' | sed '/^$/d' | sort -u)"
  fi
  if [ -z "$pids" ] && command -v ss >/dev/null 2>&1; then
    pids="$(ss -ltnpH 2>/dev/null | awk -v p=":$port" '$4 ~ p"$" {print $0}' \
      | grep -oE 'pid=[0-9]+' | cut -d= -f2 | sort -u)"
  fi
  [ -z "$pids" ] && return 0
  for pid in $pids; do
    [ "$pid" = "$SELF_PID" ] && continue
    [ "$pid" -gt 0 ] 2>/dev/null || continue
    cmdline=""
    [ -r "/proc/$pid/cmdline" ] && cmdline="$(tr '\0' ' ' < "/proc/$pid/cmdline" 2>/dev/null)"
    case "$cmdline" in
      *$match_pattern*) ;;
      *) continue ;;
    esac
    echo "zia-bridge-launcher: terminating stale pid=$pid (held :$port)" >&2
    kill -TERM "$pid" 2>/dev/null || true
  done
  i=0
  while [ "$i" -lt 30 ]; do
    still=""
    if command -v fuser >/dev/null 2>&1; then
      still="$(fuser -n tcp "$port" 2>/dev/null)"
    fi
    [ -z "$still" ] && break
    sleep 0.1
    i=$((i + 1))
  done
  for pid in $pids; do
    [ "$pid" = "$SELF_PID" ] && continue
    [ -d "/proc/$pid" ] || continue
    echo "zia-bridge-launcher: SIGKILL stale pid=$pid (still on :$port)" >&2
    kill -KILL "$pid" 2>/dev/null || true
  done
}

reap_port "$BRIDGE_PORT" "sdk-bridge/bridge.js"
reap_port "$SDK_PORT" "opencode"

cd "$BRIDGE_DIR" || exit 1
exec "$NODE_BIN" "$BRIDGE_SCRIPT"
