#!/usr/bin/env bash
# pre-push — CAB gate for pushes to main/master
#
# Only blocks when critical files change. Non-critical changes
# (docs, markdown, comms) pass automatically — no trailer needed.
#
# Critical paths (CAB required):
#   p2ptb_agent/**   — daemon logic
#   p2ptb/**         — vendored SDK
#   agent.toml       — runtime config
#   scripts/hooks/** — the hooks themselves
#
# Non-critical (auto-pass):
#   docs/**  *.md  comms/**  README*  — anything else
#
# P1 emergency bypass: git push --no-verify  (creates a retrospective obligation)
#
# Install via: bash scripts/install-hooks.sh <repo-path>

set -euo pipefail

remote="$1"
# url="$2"  # available if needed

GATE_BRANCHES=("main" "master")
APPROVE_VALUES=("APPROVE" "APPROVE_WITH_CONDITIONS" "EXEMPT")

needs_gate() {
  local remote_ref="$1"
  local branch="${remote_ref#refs/heads/}"
  for b in "${GATE_BRANCHES[@]}"; do
    [[ "$branch" == "$b" ]] && return 0
  done
  return 1
}

trailer_value() {
  local commit="$1" key="$2"
  git log -1 --format="%(trailers:key=${key},valueonly)" "$commit" \
    | tr -d '[:space:]'
}

# Returns 0 (critical) if commit touches any file that requires CAB review
commit_is_critical() {
  local commit="$1"
  local f
  while IFS= read -r f; do
    [[ "$f" == p2ptb_agent/* ]] && return 0
    [[ "$f" == p2ptb/* ]]       && return 0
    [[ "$f" == agent.toml ]]    && return 0
    [[ "$f" == scripts/hooks/* ]] && return 0
  done < <(git diff-tree --no-commit-id -r --name-only "$commit" 2>/dev/null)
  return 1
}

# Lists the critical files touched by a commit
critical_files_in() {
  local commit="$1"
  git diff-tree --no-commit-id -r --name-only "$commit" 2>/dev/null \
    | grep -E '^(p2ptb_agent/|p2ptb/|agent\.toml$|scripts/hooks/)' \
    || echo "(unknown)"
}

fail() {
  echo "❌  CAB gate: $*" >&2
}

while IFS=' ' read -r local_ref local_sha remote_ref remote_sha; do
  # Skip branch deletions
  [[ "$local_sha" == "0000000000000000000000000000000000000000" ]] && continue

  # Only gate gated branches
  needs_gate "$remote_ref" || continue

  # Compute range of new commits
  if [[ "$remote_sha" == "0000000000000000000000000000000000000000" ]]; then
    # New branch being pushed — check all commits not yet on remote
    commits=$(git log --format="%H" "$local_sha" 2>/dev/null || true)
  else
    commits=$(git log --format="%H" "${remote_sha}..${local_sha}" 2>/dev/null || true)
  fi

  [[ -z "$commits" ]] && continue

  for commit in $commits; do
    subject=$(git log -1 --format="%s" "$commit")
    short="${commit:0:8}"

    # ── Non-critical fast pass ───────────────────────────────────────────────
    if ! commit_is_critical "$commit"; then
      echo "✅  CAB gate: ${short} — no critical files, auto-pass" >&2
      continue
    fi

    # ── Critical commit — check trailer ─────────────────────────────────────
    tier=$(trailer_value "$commit" "CAB-tier")
    verdict=$(trailer_value "$commit" "CAB-verdict")

    # T1 tier or EXEMPT verdict → no review needed
    if [[ "$tier" == "T1" || "$verdict" == "EXEMPT" ]]; then
      continue
    fi

    # Check verdict is an accepted approve value
    approved=false
    for v in "${APPROVE_VALUES[@]}"; do
      [[ "$verdict" == "$v" ]] && approved=true && break
    done

    if [[ "$approved" == "false" ]]; then
      critical_files="$(critical_files_in "$commit")"

      fail "commit ${short} touches critical files — CAB approval required."
      echo "" >&2
      echo "  Commit:         ${short} — ${subject}" >&2
      echo "  Critical files: $(echo "$critical_files" | tr '\n' ' ')" >&2
      echo "  Verdict found:  '${verdict:-<none>}' | Tier found: '${tier:-<none>}'" >&2
      echo "" >&2
      echo "  To pass, add ONE of these to the commit message (after a blank line):" >&2
      echo "" >&2
      echo "    CAB-tier: T1                         # trivial — no review needed" >&2
      echo "    CAB-verdict: APPROVE                 # CAB reviewed and approved" >&2
      echo "    CAB-verdict: APPROVE_WITH_CONDITIONS" >&2
      echo "" >&2
      echo "  Get CAB review:  bash scripts/request-cab.sh [T1|T2|T3]" >&2
      echo "  Amend trailer:   git commit --amend --trailer 'CAB-verdict: APPROVE'" >&2
      echo "  P1 bypass:       git push --no-verify  (creates a retrospective obligation)" >&2
      echo "" >&2

      # Notify chief-architect via Discord webhook (best-effort, non-blocking)
      BRANCH_NAME="$(git symbolic-ref --short HEAD 2>/dev/null || echo unknown)"
      ALERTS_PY="$HOME/agents/p2ptb-bridge/p2ptb/alerts.py"
      if [[ -f "$ALERTS_PY" ]]; then
        python3 "$ALERTS_PY" \
          "🚧 **CAB gate triggered** — push to \`main\` blocked
Commit: \`${short}\` on \`${BRANCH_NAME}\`
Subject: ${subject}
Critical files: $(echo "$critical_files" | head -5 | tr '\n' ' ')
Run \`bash scripts/request-cab.sh\` to request review." \
          --username "CAB Gate" 2>/dev/null || true
      fi

      exit 1
    fi
  done
done

exit 0
