#!/bin/bash
# CI pre-push hook: enforce versioning and branching rules
# Install: git config core.hooksPath .githooks

zero="0000000000000000000000000000000000000000"

while read local_ref local_oid remote_ref remote_oid; do
  if [ "$local_oid" = "$zero" ]; then
    continue
  fi

  # Check pushed tags
  if echo "$local_ref" | grep -qE "^refs/tags/"; then
    tag_name=$(echo "$local_ref" | sed 's|^refs/tags/||')

    # Validate semver format
    if echo "$tag_name" | grep -qE "^v[0-9]+\.[0-9]+\.[0-9]+$"; then
      tag_major=$(echo "$tag_name" | sed 's/v\([0-9]*\)\.[0-9]*\.[0-9]*/\1/')
      tag_minor=$(echo "$tag_name" | sed 's/v[0-9]*\.\([0-9]*\)\.[0-9]*/\1/')
      tag_patch=$(echo "$tag_name" | sed 's/v[0-9]*\.[0-9]*\.\([0-9]*\)/\1/')

      # Check for semver ordering violations
      for existing_tag in $(git tag -l "v${tag_major}.${tag_minor}.*" 2>/dev/null); do
        if [ "$existing_tag" = "$tag_name" ]; then
          continue
        fi
        existing_patch=$(echo "$existing_tag" | sed 's/v[0-9]*\.[0-9]*\.\([0-9]*\)/\1/')
        if [ "$existing_patch" -ge "$tag_patch" ] && [ "$tag_patch" -le "$existing_patch" ]; then
          echo "ERROR: Tag $tag_name is not greater than existing tag $existing_tag"
          echo "  Milestone tags must be the NEXT version (e.g., v0.6.0 after v0.5.1-5, NOT v0.5.0)"
          exit 1
        fi
      done

      # Check for milestone-tags-below-phase-tags
      # If this is a .0 tag (milestone), verify no .N tags exist with higher patch
      if [ "$tag_patch" = "0" ]; then
        for existing_tag in $(git tag -l "v${tag_major}.${tag_minor}.*" 2>/dev/null); do
          existing_patch=$(echo "$existing_tag" | sed 's/v[0-9]*\.[0-9]*\.\([0-9]*\)/\1/')
          if [ "$existing_patch" -gt 0 ] && [ "$existing_patch" -gt "$tag_patch" ]; then
            echo "ERROR: Milestone tag $tag_name is below existing phase tags (e.g., $existing_tag)"
            echo "  Feature milestone completion must be tagged as v${tag_major}.$(($tag_minor + 1)).0, not v${tag_major}.${tag_minor}.0"
            exit 1
          fi
        done
      fi
    fi
  fi

  # Check branch merges: reject direct-to-main pushes if milestone branch exists
  if echo "$local_ref" | grep -qE "^refs/heads/main$"; then
    milestone_branches=$(git branch -r 2>/dev/null | grep 'milestone/v' | grep -v ':$' || true)
    if [ -n "$milestone_branches" ]; then
      # Allow if this is a merge commit from a milestone branch
      merge_parents=$(git cat-file -p "$local_oid" 2>/dev/null | grep "^parent" | wc -l)
      if [ "$merge_parents" -lt 2 ]; then
        # Not a merge commit — check if there are active milestone branches
        active_milestones=""
        for mb in $milestone_branches; do
          clean_name=$(echo "$mb" | sed 's|^[^/]*/||' | tr -d ' ')
          merged=$(git branch -r --merged origin/main 2>/dev/null | grep "$clean_name" || true)
          if [ -z "$merged" ]; then
            active_milestones="$active_milestones $clean_name"
          fi
        done
        if [ -n "$active_milestones" ]; then
          echo "WARNING: Pushing directly to main while active milestone branches exist:"
          for ms in $active_milestones; do
            echo "  - $ms"
          done
          echo "  Phase branches should merge into the milestone branch first."
          # Warning only — not blocking. The code-level enforcement in git-branch.ts
          # is the hard gate; this hook is a safety net.
        fi
      fi
    fi
  fi
done

exit 0