#!/usr/bin/env bash
set -euo pipefail

ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
if [[ -z "$ROOT" ]]; then
  exit 0
fi

zero_sha="0000000000000000000000000000000000000000"
refs=()
all_changed_files=""

while read -r local_ref local_sha remote_ref remote_sha; do
  refs+=("$local_ref $local_sha $remote_ref $remote_sha")
done

for ref in "${refs[@]}"; do
  read -r local_ref local_sha remote_ref remote_sha <<< "$ref"
  [[ "$local_sha" == "$zero_sha" ]] && continue
  [[ "$local_ref" != refs/heads/* ]] && continue

  if [[ "$remote_sha" == "$zero_sha" ]]; then
    range="$local_sha"
  else
    range="${remote_sha}..${local_sha}"
  fi

  changed_files=$(git diff --name-only "$range" 2>/dev/null || true)
  [[ -z "$changed_files" ]] && continue
  all_changed_files+=$'\n'"$changed_files"
done

changed_go_files=$(printf "%s\n" "$all_changed_files" | awk '/\.go$/ { print }' | sort -u)
CHECK_ALL_GO_FILES=0 CHANGED_GO_FILES="$changed_go_files" bash "$ROOT/scripts/pre-push-checks.sh"

for ref in "${refs[@]}"; do
  read -r local_ref local_sha remote_ref remote_sha <<< "$ref"
  [[ "$local_sha" == "$zero_sha" ]] && continue
  [[ "$local_ref" != refs/heads/* ]] && continue

  # Version bumps are only required for pushes to main.
  [[ "$remote_ref" != "refs/heads/main" ]] && continue

  if [[ "$remote_sha" == "$zero_sha" ]]; then
    range="$local_sha"
  else
    range="${remote_sha}..${local_sha}"
  fi

  changed_files=$(git diff --name-only "$range" 2>/dev/null || true)
  [[ -z "$changed_files" ]] && continue

  if ! echo "$changed_files" | grep -qx "VERSION"; then
    echo ""
    echo "ERROR: push to main blocked — VERSION not updated."
    echo ""
    echo "Run:"
    echo "  bash scripts/bump-version.sh --prepare-push patch"
    echo ""
    echo "Then push again:"
    echo "  git push --follow-tags origin main"
    echo ""
    echo "Bypass (rare): git push --no-verify"
    echo ""
    exit 1
  fi

  version_in_commit=$(git show "$local_sha:VERSION" 2>/dev/null | tr -d '[:space:]' || true)
  if [[ -z "$version_in_commit" || ! "$version_in_commit" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    echo ""
    echo "ERROR: push to main blocked — VERSION in pushed commit is missing or invalid."
    echo "Expected: MAJOR.MINOR.PATCH (for example 0.0.1)"
    echo ""
    exit 1
  fi

  expected_tag="v$version_in_commit"
  tag_obj_type=$(git for-each-ref "refs/tags/$expected_tag" --format='%(objecttype)' | head -1 || true)
  tag_target_sha=$(git rev-list -n 1 "$expected_tag" 2>/dev/null || true)

  if [[ -z "$tag_obj_type" ]]; then
    echo ""
    echo "ERROR: push to main blocked — missing release tag $expected_tag."
    echo ""
    echo "Run:"
    echo "  bash scripts/bump-version.sh --sync-tag"
    echo "  git push --follow-tags origin main"
    echo ""
    exit 1
  fi

  if [[ "$tag_obj_type" != "tag" ]]; then
    echo ""
    echo "ERROR: push to main blocked — $expected_tag must be an annotated tag."
    echo "Fix with:"
    echo "  bash scripts/bump-version.sh --sync-tag"
    echo ""
    exit 1
  fi

  if [[ "$tag_target_sha" != "$local_sha" ]]; then
    echo ""
    echo "ERROR: push to main blocked — tag $expected_tag does not point at pushed main commit."
    echo "Tag points to: $tag_target_sha"
    echo "Pushed commit:  $local_sha"
    echo ""
    echo "Run:"
    echo "  bash scripts/bump-version.sh --sync-tag"
    echo ""
    exit 1
  fi
done

exit 0
