#!/bin/sh
# OwnCord pre-commit hook — fast, staged-file-aware checks that mirror CI's
# cheapest gates so errors surface in seconds instead of a 15-minute CI run.
#
# Enable once per clone:  npm run hooks:install   (git config core.hooksPath .githooks)
# Bypass in an emergency: git commit --no-verify  or  OWNCORD_SKIP_HOOKS=1
# CI still enforces everything — bypassing only defers the failure.

[ "${OWNCORD_SKIP_HOOKS:-0}" = "1" ] && exit 0

repo_root=$(git rev-parse --show-toplevel) || exit 1
cd "$repo_root" || exit 1

staged=$(git diff --cached --name-only --diff-filter=ACMR)
[ -z "$staged" ] && exit 0

fail() {
    printf '\npre-commit: FAIL: %s\n(bypass with --no-verify; CI will still enforce this)\n' "$1" >&2
    exit 1
}

# ---------- Server (Go) ----------
go_staged=$(printf '%s\n' "$staged" | grep '^Server/.*\.go$' | grep -v '^Server/db/dbgen/')
if [ -n "$go_staged" ]; then
    if command -v go >/dev/null 2>&1 && command -v gofmt >/dev/null 2>&1; then
        # Word splitting is intended: repo paths contain no spaces.
        # shellcheck disable=SC2086
        unformatted=$(gofmt -l $go_staged)
        [ -n "$unformatted" ] && fail "gofmt needed (run gofmt -w on): $unformatted"
        (cd Server && go vet ./...) || fail "go vet"
    else
        printf 'pre-commit: WARNING: go/gofmt not installed; skipping Go checks.\n' >&2
    fi
fi

# These two blocks inline what `make sqlc-verify` / `make protocol-verify` reduce
# to (Server/Makefile), rather than shelling out to make. `make` is not on PATH on
# a stock Windows box, and a guard on `go`/`sqlc` does not imply it: the old code
# probed one command and invoked another, so a contributor with Go but no make was
# told "protocol constants are stale" when nothing had been generated or compared.

# sqlc inputs changed -> regenerated db/dbgen must be part of the same commit.
if printf '%s\n' "$staged" | grep -qE '^Server/(db/queries/|migrations/|sqlc\.yaml|sqlc\.version)'; then
    if command -v sqlc >/dev/null 2>&1; then
        (cd Server && sqlc generate && git diff --exit-code db/dbgen) \
            || fail "db/dbgen is stale — run 'sqlc generate' in Server/ and stage the result"
    else
        printf 'pre-commit: WARNING: sqlc not installed; skipping the db/dbgen check. Install the version pinned in Server/sqlc.version. CI will run it.\n' >&2
    fi
fi

# Protocol schema changed -> regenerated Go + TS constants must be in the same commit.
if printf '%s\n' "$staged" | grep -qE '^(protocol/schema\.json|Server/cmd/genprotocol/)'; then
    if command -v go >/dev/null 2>&1; then
        (cd Server && go run ./cmd/genprotocol \
            && git diff --exit-code ws/message_types.go ../Client/src/lib/protocolTypes.ts) \
            || fail "protocol constants are stale — run 'go run ./cmd/genprotocol' in Server/ and stage the result"
    else
        printf 'pre-commit: WARNING: go not installed; skipping the protocol-constants check. CI will run it.\n' >&2
    fi
fi

# Findings ledger changed -> it must still be valid. Unlike the two blocks
# above there is nothing to diff: FINDINGS.md is not tracked (RL-07), so a
# stale rendering cannot be committed. --check is the whole gate here, and it
# writes nothing. render-ledger.mjs is Node-stdlib-only, so `node` alone is the
# probe — no node_modules guard, unlike the prettier block below.
if printf '%s\n' "$staged" | grep -qE '^\.superpowers/(findings-ledger\.json|render-ledger\.mjs)$'; then
    if command -v node >/dev/null 2>&1; then
        node .superpowers/render-ledger.mjs --check \
            || fail "findings-ledger.json is invalid — see the INVALID lines above"
    else
        printf 'pre-commit: WARNING: node not installed; skipping the ledger check. CI will run it.\n' >&2
    fi
fi

# ---------- Formatting (repository-wide) ----------
# Prettier is configured once at the repository root (.prettierrc.json) and
# covers every material tracked source, not just client TypeScript.
# --ignore-unknown drops the Go/Rust/binary paths it has no parser for.
if [ -d node_modules ]; then
    # Word splitting is intended: repo paths contain no spaces.
    # shellcheck disable=SC2086
    npx prettier --check --ignore-unknown $staged || fail "prettier (run: npm run format)"
else
    printf 'pre-commit: WARNING: node_modules missing at the repository root; skipping prettier.\n' >&2
fi

# ---------- Client (TypeScript) ----------
ts_staged=$(printf '%s\n' "$staged" | grep -E '^Client/(src|tests)/.*\.ts$' | grep -v '/generated/')
if [ -n "$ts_staged" ]; then
    if [ ! -d Client/node_modules ]; then
        printf 'pre-commit: WARNING: node_modules missing in Client; skipping client checks (run npm install there).\n' >&2
    else
        rel=$(printf '%s\n' "$ts_staged" | sed 's|^Client/||')
        cd Client || exit 1
        # shellcheck disable=SC2086
        npx oxlint $rel || fail "oxlint"
        npm run -s typecheck || fail "tsc --noEmit"
        cd "$repo_root" || exit 1
    fi
fi

exit 0
