#!/bin/sh
# OwnCord pre-push hook — build-level gates that mirror CI's expensive-but-common
# failure modes (tag-variant compiles, typecheck, type-aware lint).
#
# Bypass: git push --no-verify  or  OWNCORD_SKIP_HOOKS=1
# Extra:  OWNCORD_PREPUSH_TESTS=1 additionally runs the server test suite (-race).

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

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

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

# What changed relative to this branch's base decides which side's gates run.
#
# The base is whichever of origin/dev, origin/main is NEAREST — the one with the
# fewest commits between its merge-base and HEAD. A feature branch cut from dev
# picks dev; dev itself scores 0 against dev (nothing to compare) and so picks
# main, which is right for a dev -> main release PR. Hardcoding origin/main got
# the first case wrong once dev became the integration branch: everything on dev
# and not yet on main counted as "changed", so both sides' gates ran every time.
#
# Markdown/docs changes never trigger builds.
base=""
best=""
for cand in origin/dev origin/main; do
    git rev-parse --verify -q "$cand" >/dev/null 2>&1 || continue
    mb=$(git merge-base "$cand" HEAD 2>/dev/null) || continue
    n=$(git rev-list --count "$mb..HEAD" 2>/dev/null) || continue
    [ "$n" -eq 0 ] && continue
    if [ -z "$best" ] || [ "$n" -lt "$best" ]; then
        base=$cand
        best=$n
    fi
done

if [ -n "$base" ]; then
    changed=$(git diff --name-only "$base...HEAD" 2>/dev/null) || changed="__all__"
else
    changed="__all__"
fi
[ "$changed" = "__all__" ] || changed=$(printf '%s\n' "$changed" | grep -v '\.md$')
[ -z "$changed" ] && exit 0

server_changed=0
client_changed=0
if [ "$changed" = "__all__" ]; then
    server_changed=1
    client_changed=1
else
    if printf '%s\n' "$changed" | grep -q '^Server/'; then server_changed=1; fi
    if printf '%s\n' "$changed" | grep -q '^Client/'; then client_changed=1; fi
    if printf '%s\n' "$changed" | grep -q '^protocol/schema\.json'; then
        server_changed=1
        client_changed=1
    fi
fi

if [ "$server_changed" = 1 ] && command -v go >/dev/null 2>&1; then
    echo "pre-push: server build (all tag variants)..."
    (cd Server \
        && go build ./... \
        && go build -tags otel ./... \
        && go build -tags wazero ./... \
        && go build -tags otel,wazero ./...) || fail "server build (a tag variant failed to compile)"
    if [ "${OWNCORD_PREPUSH_TESTS:-0}" = "1" ]; then
        echo "pre-push: server tests (-race)..."
        (cd Server && go test -race ./...) || fail "server tests"
    fi
fi

if [ "$client_changed" = 1 ]; then
    if [ -d Client/node_modules ]; then
        echo "pre-push: client typecheck + eslint..."
        (cd Client && npm run -s typecheck) || fail "tsc --noEmit"
        (cd Client && npx eslint src/) || fail "eslint"
    else
        printf 'pre-push: WARNING: node_modules missing in Client; skipping client checks.\n' >&2
    fi
fi

exit 0
