#!/usr/bin/env bash
# land.sh — rebase onto origin/main, run cheap pre-push checks, push to main.
# Usage: bash scripts/land.sh   (from any worktree with commits to land)
set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"

MAX_ATTEMPTS=5

die() {
  echo "ERROR: $1" >&2
  echo "Next: $2" >&2
  exit 1
}

echo "=== land: verifying clean working tree ==="
status="$(git status --porcelain)"
if [[ -n "$status" ]]; then
  echo "ERROR: working tree is not clean (dirty or untracked non-ignored files):" >&2
  echo "$status" >&2
  echo "Next: commit, stash, or remove the changes above, then re-run bash scripts/land.sh" >&2
  exit 1
fi

echo "=== land: fetching origin/main ==="
git fetch origin main

ahead="$(git rev-list --count origin/main..HEAD)"
if [[ "$ahead" -eq 0 ]]; then
  die "HEAD has no commits ahead of origin/main — nothing to land" \
    "commit your changes, then re-run bash scripts/land.sh"
fi

run_prepush_checks() {
  local local_sha remote_sha
  local_sha="$(git rev-parse HEAD)"
  remote_sha="$(git rev-parse origin/main)"
  printf 'refs/heads/main %s refs/heads/main %s\n' "$local_sha" "$remote_sha" \
    | node "$ROOT/scripts/pre-push.mjs"
}

for attempt in $(seq 1 "$MAX_ATTEMPTS"); do
  echo "=== land: attempt $attempt/$MAX_ATTEMPTS ==="
  git fetch origin main

  if ! git rebase origin/main; then
    mapfile -t conflicts < <(git diff --name-only --diff-filter=U 2>/dev/null || true)
    if [[ ${#conflicts[@]} -eq 0 ]]; then
      mapfile -t conflicts < <(git status --porcelain | awk '/^(UU|AA|DD)/{print $2}')
    fi
    git rebase --abort
    echo "ERROR: rebase onto origin/main failed due to conflicts" >&2
    if [[ ${#conflicts[@]} -gt 0 ]]; then
      echo "Conflicting files:" >&2
      printf '  %s\n' "${conflicts[@]}" >&2
    fi
    echo "Next: resolve conflicts and re-run bash scripts/land.sh" >&2
    exit 1
  fi

  echo "=== land: pre-push checks ==="
  run_prepush_checks

  echo "=== land: pushing to origin/main ==="
  push_output=""
  push_status=0
  push_output="$(git push origin HEAD:refs/heads/main 2>&1)" || push_status=$?

  if [[ "$push_status" -eq 0 ]]; then
    landed_sha="$(git rev-parse HEAD)"
    echo "landed $landed_sha"
    exit 0
  fi

  if echo "$push_output" | grep -qiE 'non-fast-forward|fetch first|rejected'; then
    echo "Push rejected (concurrent land on main); retrying after fetch/rebase..." >&2
    continue
  fi

  echo "$push_output" >&2
  die "git push to origin/main failed (exit $push_status)" \
    "fix the push error above and re-run bash scripts/land.sh"
done

die "failed to land after $MAX_ATTEMPTS attempts (concurrent pushes to main)" \
  "wait for other landers to finish, then re-run bash scripts/land.sh"
