#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
export LANG=C

default_arch() {
  local arch
  arch="$(uname -m)"
  case "$arch" in
    x86_64|amd64) arch="x64" ;;
    aarch64) arch="arm64" ;;
  esac
  printf '%s\n' "$arch"
}

TARGET="${FERMAT_TARGET:-${FILETOFISH_TARGET:-$(uname -s | tr '[:upper:]' '[:lower:]')-$(default_arch)}}"
INSTALL_ROOT="${FERMAT_INSTALL_ROOT:-${FILETOFISH_INSTALL_ROOT:-$HOME/.local/share/fermat/runtime}}"
BIN_DIR="${FERMAT_BIN_DIR:-${FILETOFISH_BIN_DIR:-$HOME/.local/bin}}"
SHIM_NAME="${FERMAT_SHIM_NAME:-${FILETOFISH_SHIM_NAME:-claude}}"
DEFAULT_MANIFEST_URL="${FERMAT_DEFAULT_MANIFEST_URL:-https://downloads.quotientlabs.com/fermat/$TARGET/manifest.json}"
MANIFEST_URL="${FERMAT_MANIFEST_URL:-${FILETOFISH_MANIFEST_URL:-$DEFAULT_MANIFEST_URL}}"
ARCHIVE="${FERMAT_ARCHIVE:-${FILETOFISH_ARCHIVE:-}}"
SHA256="${FERMAT_SHA256:-${FILETOFISH_SHA256:-}}"
UPSTREAM_CLAUDE_NAME="claude-anthropic"
TMP_DIR="$(mktemp -d)"

cleanup() {
  rm -rf "$TMP_DIR"
}
trap cleanup EXIT

need() {
  command -v "$1" >/dev/null 2>&1 || {
    echo "fermat install: missing required command: $1" >&2
    exit 1
  }
}

copy_tree() {
  local source="$1"
  local target="$2"
  rm -rf "$target"
  mkdir -p "$(dirname "$target")"
  cp -R "$source" "$target"
}

is_owned_command() {
  local target="$1"
  grep -Fq '# fermat cli wrapper v1' "$target" 2>/dev/null \
    || grep -Fq '# fermat shim v1' "$target" 2>/dev/null \
    || grep -Fq '# filetofish cli wrapper v1' "$target" 2>/dev/null \
    || grep -Fq '# filetofish shim v3' "$target" 2>/dev/null
}

check_node_bin() {
  local command="$1"
  local target="$BIN_DIR/$command"
  if [ -e "$target" ] && ! is_owned_command "$target"; then
    echo "fermat install: command already exists and is not Fermat-owned: $target" >&2
    exit 1
  fi
}

is_claude_code_command() {
  local candidate="$1"
  [ -n "$candidate" ] || return 1
  [ -x "$candidate" ] || return 1
  "$candidate" --version 2>&1 | grep -Fq "Claude Code"
}

ensure_claude_code_available() {
  local target="$BIN_DIR/$SHIM_NAME"
  local preserved="$BIN_DIR/$UPSTREAM_CLAUDE_NAME"
  local candidate

  if [ -n "${FERMAT_CLAUDE_BIN:-${FILETOFISH_CLAUDE_BIN:-}}" ]; then
    candidate="${FERMAT_CLAUDE_BIN:-$FILETOFISH_CLAUDE_BIN}"
    if is_claude_code_command "$candidate"; then
      return 0
    fi
    echo "fermat install: FERMAT_CLAUDE_BIN does not point to Claude Code: $candidate" >&2
    exit 1
  fi

  # Upgrades run while the public `claude` path is already our shim. The
  # original Claude Code binary was preserved under this sibling name by the
  # first install, so recognize it before searching PATH again.
  if [ "$SHIM_NAME" = "claude" ] && is_claude_code_command "$preserved"; then
    return 0
  fi

  if [ -e "$target" ] && ! is_owned_command "$target" && is_claude_code_command "$target"; then
    return 0
  fi

  while IFS= read -r candidate; do
    [ -n "$candidate" ] || continue
    if is_claude_code_command "$candidate"; then
      return 0
    fi
  done < <(which -a claude 2>/dev/null || true)

  echo "fermat install: Claude Code is required but was not found" >&2
  echo "  install Claude Code first, verify 'claude --version' prints 'Claude Code', then rerun this installer." >&2
  echo "  if Claude Code is installed in a custom location, rerun with FERMAT_CLAUDE_BIN=/path/to/claude." >&2
  exit 1
}

preserve_existing_claude_target() {
  [ "$SHIM_NAME" = "claude" ] || return 0
  local target="$BIN_DIR/claude"
  local preserved="$BIN_DIR/$UPSTREAM_CLAUDE_NAME"
  [ -e "$target" ] || return 0
  is_owned_command "$target" && return 0

  if ! is_claude_code_command "$target"; then
    echo "fermat install: command already exists and is not Fermat-owned or Claude Code: $target" >&2
    exit 1
  fi
  if [ -e "$preserved" ]; then
    echo "fermat install: cannot preserve existing Claude Code because $preserved already exists" >&2
    echo "  remove or rename that file, then rerun the installer." >&2
    exit 1
  fi
  mkdir -p "$(dirname "$preserved")"
  mv "$target" "$preserved"
}

stop_existing_daemon() {
  local control="$BIN_DIR/fermat"
  local server="$INSTALL_ROOT/server.js"
  local pid command
  local -a pids=()

  # Prefer the old runtime's own graceful stop path while its files are still
  # present. This covers the normal case where runtime.json is healthy.
  if [ -x "$control" ] && is_owned_command "$control"; then
    "$control" stop >/dev/null 2>&1 || true
  fi

  # A stale/missing runtime.json used to strand a detached daemon across an
  # upgrade. Only terminate processes whose command line contains this exact
  # install root's server entrypoint.
  [ -f "$server" ] || return 0
  command -v pgrep >/dev/null 2>&1 || return 0
  while IFS= read -r pid; do
    [ -n "$pid" ] || continue
    command="$(ps -p "$pid" -o command= 2>/dev/null || true)"
    case "$command" in
      *"$server"*)
        kill -TERM "$pid" 2>/dev/null || true
        pids+=("$pid")
        ;;
    esac
  done < <(pgrep -f "$server" 2>/dev/null || true)

  for pid in "${pids[@]}"; do
    for _ in {1..50}; do
      kill -0 "$pid" 2>/dev/null || break
      sleep 0.1
    done
    if kill -0 "$pid" 2>/dev/null; then
      kill -KILL "$pid" 2>/dev/null || true
    fi
  done
}

write_node_bin() {
  local command="$1"
  local entry="$2"
  local target="$BIN_DIR/$command"
  local quoted_entry
  quoted_entry="$(printf '%q' "$entry")"
  check_node_bin "$command"
  mkdir -p "$(dirname "$target")"
  cat > "$target" <<EOF
#!/usr/bin/env bash
# fermat cli wrapper v1
set -euo pipefail
exec node $quoted_entry "\$@"
EOF
  chmod +x "$target"
}

need node
need tar
need shasum

if [ "$(id -u)" = "0" ] && [ "${FERMAT_ALLOW_ROOT_INSTALL:-${FILETOFISH_ALLOW_ROOT_INSTALL:-}}" != "1" ]; then
  echo "fermat install: do not run the standard installer with sudo/root" >&2
  echo "  it writes per-user Claude config; run as your normal user or set FERMAT_ALLOW_ROOT_INSTALL=1 intentionally" >&2
  exit 1
fi

NODE_MAJOR="$(node -p 'Number(process.versions.node.split(".")[0])' 2>/dev/null || echo 0)"
if [ "${NODE_MAJOR:-0}" -lt 20 ]; then
  echo "fermat install: Node.js 20 or newer is required (found $(node -v 2>/dev/null || echo unknown))" >&2
  exit 1
fi

ensure_claude_code_available

if [ -z "$ARCHIVE" ]; then
  need curl
  if [ -z "$MANIFEST_URL" ]; then
    echo "fermat install: set FERMAT_MANIFEST_URL or FERMAT_ARCHIVE" >&2
    exit 2
  fi
  MANIFEST="$TMP_DIR/manifest.json"
  curl -fsSL "$MANIFEST_URL" -o "$MANIFEST"
  read -r ARCHIVE SHA256 MANIFEST_TARGET < <(node - "$MANIFEST" "$MANIFEST_URL" <<'NODE'
const fs = require('fs');
const manifestPath = process.argv[2];
const manifestUrl = process.argv[3];
const m = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
const archive = m.archive_url || m.archive;
if (!archive || !m.sha256) process.exit(2);
const resolved = /^https?:\/\//.test(archive) ? archive : new URL(archive, manifestUrl).href;
console.log(`${resolved} ${m.sha256} ${m.target || ''}`);
NODE
  )
  if [ -n "${MANIFEST_TARGET:-}" ] && [ "$MANIFEST_TARGET" != "$TARGET" ]; then
    echo "fermat install: artifact target mismatch" >&2
    echo "  expected: $TARGET" >&2
    echo "  manifest: $MANIFEST_TARGET" >&2
    exit 1
  fi
fi

if [ -z "$SHA256" ]; then
  echo "fermat install: missing SHA-256 for archive" >&2
  exit 2
fi

if [[ "$ARCHIVE" =~ ^https?:// ]]; then
  need curl
  ARCHIVE_PATH="$TMP_DIR/fermat-runtime-$TARGET.tar.gz"
  printf 'Downloading Fermat…\n' >&2
  # -S surfaces errors, --progress-bar shows a simple download bar (both on stderr).
  curl -fSL --progress-bar "$ARCHIVE" -o "$ARCHIVE_PATH"
else
  ARCHIVE_PATH="$ARCHIVE"
fi

ACTUAL_SHA="$(shasum -a 256 "$ARCHIVE_PATH" | awk '{print $1}')"
if [ "$ACTUAL_SHA" != "$SHA256" ]; then
  echo "fermat install: checksum mismatch" >&2
  echo "  expected: $SHA256" >&2
  echo "  actual:   $ACTUAL_SHA" >&2
  exit 1
fi

EXTRACT_DIR="$TMP_DIR/extract"
mkdir -p "$EXTRACT_DIR"
tar -xzf "$ARCHIVE_PATH" -C "$EXTRACT_DIR"
PACKAGE_ROOT="$(find "$EXTRACT_DIR" -mindepth 1 -maxdepth 1 -type d | head -1)"
if [ -z "$PACKAGE_ROOT" ]; then
  echo "fermat install: archive did not contain a package root" >&2
  exit 1
fi

preserve_existing_claude_target
check_node_bin "$SHIM_NAME"
check_node_bin fermat
stop_existing_daemon
copy_tree "$PACKAGE_ROOT/lib/fermat-runtime" "$INSTALL_ROOT"
write_node_bin fermat "$INSTALL_ROOT/cli.js"
if [ "$SHIM_NAME" != "claude" ]; then
  check_node_bin "$SHIM_NAME"
  write_node_bin "$SHIM_NAME" "$INSTALL_ROOT/cli.js"
fi

"$BIN_DIR/fermat" install --shim-name "$SHIM_NAME" --shim-dir "$BIN_DIR"
