#!/usr/bin/env bash
# pre-push hook: quality gate for the *pushed* commits — a poor man's CI.
# Install with: make setup  (sets core.hooksPath = .githooks)
#
# Why a throwaway worktree: a gate must judge what you publish, not the state of
# your desk. Reading the live working tree lets uncommitted WIP either break the
# gate or sneak past it. So we check out the exact commit being pushed into a
# clean, isolated worktree and run the checks there.
set -euo pipefail

REPO_ROOT=$(git rev-parse --show-toplevel)
# shellcheck source=../tools.versions
source "${REPO_ROOT}/tools.versions"

run_checks() { # cwd is a clean checkout of the pushed commit
  echo "  → gofmt"
  local unformatted
  unformatted=$(gofmt -l $(git ls-files '*.go'))
  if [ -n "$unformatted" ]; then
    echo "  FAIL: the following files are not gofmt-formatted:"
    echo "$unformatted" | sed 's/^/    /'
    echo "  Fix with: make lint-fix"
    return 1
  fi

  echo "  → go vet"
  go vet ./...

  echo "  → golangci-lint"
  go run github.com/golangci/golangci-lint/cmd/golangci-lint@"${GOLANGCI_LINT_VERSION}" run ./...

  echo "  → gosec"
  go run github.com/securego/gosec/v2/cmd/gosec@"${GOSEC_VERSION}" -quiet ./...

  # govulncheck is intentionally omitted (network + slow).
  # Run it manually with: make security
}

# pre-push feeds one "<local_ref> <local_sha> <remote_ref> <remote_sha>" line
# per pushed ref on stdin.
while read -r _local_ref local_sha _remote_ref _remote_sha; do
  # Branch deletion (all-zero sha): nothing to check.
  [[ "$local_sha" =~ ^0+$ ]] && continue

  echo "pre-push: checking ${local_sha:0:12} in a clean worktree..."
  tmp=$(mktemp -d)
  git worktree add --detach --quiet "$tmp" "$local_sha"
  if ( cd "$tmp" && run_checks ); then
    git worktree remove --force "$tmp"
  else
    git worktree remove --force "$tmp"
    echo "pre-push: checks FAILED for ${local_sha:0:12}"
    exit 1
  fi
done

echo "pre-push: all checks passed."
