#!/usr/bin/env bash
# .githooks/pre-push — forcing function for verify_gates.sh discipline.
#
# Triggered by every `git push`. Rejects the push if there is no recent
# clean `verify_gates.sh` proof for the current HEAD.
#
# Activation:
#   git config core.hooksPath .githooks
#   (or run ./scripts/install_hooks.sh once per clone)
#
# Acceptance criteria (all must hold for the push to proceed):
#   1. .git/.last-gates-pass file exists
#   2. The HEAD SHA recorded in the marker matches the current HEAD
#   3. The marker's epoch is within $MAX_AGE_SEC seconds of now
#
# Escape hatch:
#   `git push --no-verify` bypasses ALL pre-push hooks. CLAUDE.md
#   `## Quality Gates` proibits this except for emergencies with
#   explicit operator approval + commit-body rationale.
#
# Codified by:
#   MISSION-post-v0_42_2-quality-discipline-2026-05-14.md Phase 2.T2.3
#   feedback_ci_preflight.md Addendum 2026-05-14
#   feedback_no_speculation.md Addendum 2026-05-14

set -euo pipefail

# Cache window: 30 min. Long enough for "run gates, then bump+commit+push"
# (gates run ~10 min, commit + push is seconds), but short enough that
# stale proof from yesterday is invalid.
MAX_AGE_SEC="${SOVYX_GATES_MAX_AGE_SEC:-1800}"

GIT_DIR=$(git rev-parse --git-dir 2>/dev/null || echo ".git")
MARKER="$GIT_DIR/.last-gates-pass"
NOW=$(date +%s)

# Color (only when TTY).
if [[ -t 2 ]]; then
    RED=$(printf '\033[31m')
    GREEN=$(printf '\033[32m')
    YELLOW=$(printf '\033[33m')
    BOLD=$(printf '\033[1m')
    RESET=$(printf '\033[0m')
else
    RED=""; GREEN=""; YELLOW=""; BOLD=""; RESET=""
fi

reject() {
    {
        printf '%s%s🚫 pre-push hook BLOCKED the push.%s\n' "$RED" "$BOLD" "$RESET"
        printf '\n'
        printf 'Reason: %s\n' "$1"
        printf '\n'
        printf '%sFix:%s\n' "$YELLOW" "$RESET"
        printf '  1. Run %s./scripts/verify_gates.sh%s (~10 min).\n' "$BOLD" "$RESET"
        printf '  2. After it prints "all gates verified GREEN", retry %sgit push%s.\n' "$BOLD" "$RESET"
        printf '\n'
        printf 'Escape hatch (emergency only): %sgit push --no-verify%s\n' "$BOLD" "$RESET"
        printf '  -- CLAUDE.md proibits this except with operator approval +\n'
        printf '     commit-body rationale documenting why the gate was skipped.\n'
        printf '\n'
        printf 'Discipline source: MISSION-post-v0_42_2-quality-discipline-2026-05-14.md Phase 2.T2.3\n'
    } >&2
    exit 1
}

# 1. Marker existence
if [[ ! -f "$MARKER" ]]; then
    reject "no .last-gates-pass marker found at $MARKER (gates never ran or last run was red)"
fi

# 2. HEAD SHA match
MARKER_SHA=$(head -n1 "$MARKER" 2>/dev/null || echo "")
HEAD_SHA=$(git rev-parse HEAD 2>/dev/null || echo "")

if [[ -z "$MARKER_SHA" || -z "$HEAD_SHA" ]]; then
    reject "marker file is malformed or HEAD not resolvable"
fi

if [[ "$MARKER_SHA" != "$HEAD_SHA" ]]; then
    reject "marker recorded against HEAD=${MARKER_SHA:0:8} but current HEAD=${HEAD_SHA:0:8} (commit happened after gates ran — re-run)"
fi

# 3. Age
MARKER_EPOCH=$(tail -n1 "$MARKER" 2>/dev/null || echo "0")
if ! [[ "$MARKER_EPOCH" =~ ^[0-9]+$ ]]; then
    reject "marker epoch malformed: '$MARKER_EPOCH'"
fi

AGE=$((NOW - MARKER_EPOCH))
if [[ "$AGE" -gt "$MAX_AGE_SEC" ]]; then
    AGE_MIN=$((AGE / 60))
    MAX_MIN=$((MAX_AGE_SEC / 60))
    reject "marker is stale: ${AGE_MIN} min old (max ${MAX_MIN} min). Re-run gates."
fi

# All checks passed — emit a one-line trail and allow the push.
AGE_MIN=$((AGE / 60))
printf '%s✓%s pre-push: gates verified %d min ago against HEAD=%s\n' "$GREEN" "$RESET" "$AGE_MIN" "${HEAD_SHA:0:8}" >&2

# Drain stdin (git pushes ref info via stdin) so git doesn't get
# upset about an unread pipe.
cat >/dev/null

exit 0
