#!/usr/bin/env bash
# Evaluator preflight — install required tools or fail.
# Canonical source. Rationale + tool table live in preflight.md (the prose
# contract); this script is the executable contract. Edit this file, not the .md.
# Idempotent. Re-runnable. No-op when everything is installed.
set -euo pipefail

missing=()

# Portable timeout wrapper. macOS has no `timeout` by default; `gtimeout` lives
# in coreutils. If neither is present we run without a cap but warn — the User
# should `brew install coreutils` to restore the 180s guard.
if command -v timeout >/dev/null 2>&1; then
  _timeout() { timeout "$@"; }
elif command -v gtimeout >/dev/null 2>&1; then
  _timeout() { gtimeout "$@"; }
else
  echo "[preflight] warning: no timeout/gtimeout on host — install coreutils for hang-safe installs (brew install coreutils)" >&2
  _timeout() { shift; "$@"; }   # drop the seconds arg, exec the rest
fi

need() {
  local tool="$1"
  local install_cmd="$2"
  if ! command -v "$tool" >/dev/null 2>&1; then
    echo "[preflight] missing: $tool — installing with: $install_cmd" >&2
    # 180s covers slow brew/npm fetches; a stuck package manager fails loud
    # instead of hanging the run indefinitely (falls back to no-cap
    # when timeout/gtimeout is unavailable — see wrapper above).
    _timeout 180 bash -c "$install_cmd" || { echo "[preflight] INSTALL FAILED (or timed out): $tool" >&2; missing+=("$tool"); }
  else
    echo "[preflight] ok: $tool"
  fi
}

# Host prerequisites — do not attempt to install; fail if missing.
for bin in brew jq node npm python3; do
  command -v "$bin" >/dev/null 2>&1 || { echo "[preflight] HOST MISSING: $bin — user must install" >&2; exit 2; }
done

# Homebrew-installable tools
# NOTE: `lizard` is intentionally NOT brew-installed — brew's `lizard` is the
# LZ5 data-compression CLI, which shadows the Python CCN analyzer of the same
# name when on PATH first. We install the Python tool via pipx below and then
# sanity-check that the `lizard` resolved on PATH is the analyzer, not the
# compressor. If a user has `brew install lizard` already they'll need to
# either `brew uninstall lizard` or reorder PATH so `~/.local/bin` is earlier.
need gh             "brew install gh"
need gitleaks       "brew install gitleaks"
need scc            "brew install scc"
need semgrep        "brew install semgrep"
need hadolint       "brew install hadolint"
need ruff           "brew install ruff"
need shellcheck     "brew install shellcheck"
need tree           "brew install tree"
need golangci-lint  "brew install golangci-lint"
need pnpm           "brew install pnpm"
need yarn           "brew install yarn"
need pipx           "brew install pipx && pipx ensurepath"
need trivy          "brew install trivy"

# npm-global tools
need biome          "npm install -g @biomejs/biome"
need knip           "npm install -g knip"

# pipx-installed Python CLIs
need deptry         "pipx install deptry"
need lizard         "pipx install lizard"
need pip-audit      "pipx install pip-audit"

# Go-installed CLIs — only install govulncheck when go is already on PATH.
# Hosts without Go skip this gracefully; Go-repo vuln scans then
# surface as `_NOT_RUN: true` with reason "govulncheck unavailable (go not installed)".
if command -v go >/dev/null 2>&1; then
  need govulncheck  "go install golang.org/x/vuln/cmd/govulncheck@latest"
else
  echo "[preflight] skip: govulncheck (go not on PATH — install go manually + rerun preflight if you need Go dep-vuln scans)"
fi

# Sanity-check: the `lizard` on PATH must be the Python cyclomatic-complexity
# analyzer, not brew's LZ5 compressor. The Python tool's --help output always
# contains "Cyclomatic Complexity Analyzer"; the compressor prints a short
# LZ5-compression usage blurb. Halt loudly on mismatch.
if command -v lizard >/dev/null 2>&1; then
  if ! lizard --help 2>&1 | grep -qi 'Cyclomatic Complexity Analyzer'; then
    echo "[preflight] FAILED — 'lizard' on PATH is not the Python CCN analyzer." >&2
    echo "[preflight]   Resolved: $(command -v lizard)" >&2
    echo "[preflight]   Likely cause: brew's LZ5 compressor is shadowing pipx's lizard." >&2
    echo "[preflight]   Fix: 'brew uninstall lizard' OR move \"\$HOME/.local/bin\" earlier in PATH than \$(brew --prefix)/bin." >&2
    missing+=("lizard (wrong binary — see above)")
  fi
fi

if [ "${#missing[@]}" -gt 0 ]; then
  echo "[preflight] FAILED — these tools could not be installed: ${missing[*]}" >&2
  echo "[preflight] scoring cannot proceed; fix manually and re-run" >&2
  exit 1
fi

echo "[preflight] all tools ready"
