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

# git-cherry-pick-review.sh
#
# Purpose:
#   Help you safely review a cherry-pick conflict by collecting context,
#   checking repository state, and verifying the result before you continue.
#
# What this script does:
#   - Validates that you are in a Git repository
#   - Shows the current cherry-pick state (if any)
#   - Displays status and conflicted files
#   - Optionally shows the cherry-picked commit with git show
#   - Optionally shows a focused diff after you resolve conflicts
#   - Optionally runs a user-specified verification command
#   - Optionally continues or aborts the cherry-pick after prompting
#
# What this script does not do:
#   - It does not edit files for you
#   - It does not stage changes automatically
#   - It does not delete worktree changes
#   - It does not continue or abort unless you explicitly request it
#
# Usage:
#   ./git-cherry-pick-review.sh [options]
#
# Options:
#   -c, --commit <sha>     Commit SHA to inspect with git show
#   -v, --verify <cmd>     Verification command to run after resolution
#   --continue             Prompt before running git cherry-pick --continue
#   --abort                Prompt before running git cherry-pick --abort
#   -h, --help             Show help
#
# Examples:
#   ./git-cherry-pick-review.sh --commit abc1234
#   ./git-cherry-pick-review.sh --commit abc1234 --verify 'git diff --check && git test'
#   ./git-cherry-pick-review.sh --continue
#
# Notes:
#   - Run this from the repository root or any subdirectory inside the repo.
#   - If you are in a conflicted state, resolve the files manually first,
#     then use this script to review and verify before continuing.

COMMIT_SHA=""
VERIFY_CMD=""
DO_CONTINUE=0
DO_ABORT=0

usage() {
  cat <<'EOF'
Usage: git-cherry-pick-review.sh [options]

Options:
  -c, --commit <sha>     Commit SHA to inspect with git show
  -v, --verify <cmd>     Verification command to run after resolution
  --continue             Prompt before running git cherry-pick --continue
  --abort                Prompt before running git cherry-pick --abort
  -h, --help             Show help
EOF
}

confirm() {
  local prompt="$1"
  local reply=""
  read -r -p "${prompt} [y/N] " reply || true
  case "${reply}" in
    y|Y|yes|YES)
      return 0
      ;;
    *)
      return 1
      ;;
  esac
}

require_git_repo() {
  if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    echo "Error: not inside a Git repository." >&2
    exit 1
  fi
}

show_repo_context() {
  echo "== Repository context =="
  echo "Branch: $(git branch --show-current 2>/dev/null || echo 'detached-or-unknown')"
  echo "Root:   $(git rev-parse --show-toplevel)"
  echo
}

show_cherry_pick_state() {
  echo "== Cherry-pick state =="
  if [ -d "$(git rev-parse --git-path sequencer 2>/dev/null)" ] || [ -f "$(git rev-parse --git-path CHERRY_PICK_HEAD 2>/dev/null)" ]; then
    echo "A cherry-pick appears to be in progress."
  else
    echo "No obvious cherry-pick state detected."
  fi
  echo
}

show_status() {
  echo "== Git status =="
  git status --short --branch
  echo
}

show_conflicts() {
  echo "== Conflicted files =="
  local conflicts
  conflicts="$(git diff --name-only --diff-filter=U || true)"
  if [ -n "${conflicts}" ]; then
    printf '%s\n' "${conflicts}"
  else
    echo "No unmerged files detected."
  fi
  echo
}

show_commit() {
  local sha="$1"
  echo "== Commit details: ${sha} =="
  git show --stat --summary --decorate=short --format=fuller "${sha}"
  echo
}

show_post_resolution_diff() {
  echo "== Current working diff =="
  git diff --check || true
  echo
  git diff --stat || true
  echo
}

run_verification() {
  local cmd="$1"
  echo "== Verification command =="
  echo "${cmd}"
  echo
  bash -lc "${cmd}"
  echo
}

continue_cherry_pick() {
  if confirm "Run git cherry-pick --continue now?"; then
    git cherry-pick --continue
  else
    echo "Skipped cherry-pick --continue."
  fi
}

abort_cherry_pick() {
  if confirm "Run git cherry-pick --abort now?"; then
    git cherry-pick --abort
  else
    echo "Skipped cherry-pick --abort."
  fi
}

while [ $# -gt 0 ]; do
  case "$1" in
    -c|--commit)
      if [ $# -lt 2 ]; then
        echo "Error: --commit requires a SHA." >&2
        exit 1
      fi
      COMMIT_SHA="$2"
      shift 2
      ;;
    -v|--verify)
      if [ $# -lt 2 ]; then
        echo "Error: --verify requires a command string." >&2
        exit 1
      fi
      VERIFY_CMD="$2"
      shift 2
      ;;
    --continue)
      DO_CONTINUE=1
      shift
      ;;
    --abort)
      DO_ABORT=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Error: unknown argument: $1" >&2
      usage >&2
      exit 1
      ;;
  esac
done

if [ "${DO_CONTINUE}" -eq 1 ] && [ "${DO_ABORT}" -eq 1 ]; then
  echo "Error: choose only one of --continue or --abort." >&2
  exit 1
fi

require_git_repo
show_repo_context
show_cherry_pick_state
show_status
show_conflicts

if [ -n "${COMMIT_SHA}" ]; then
  if git rev-parse --verify --quiet "${COMMIT_SHA}^{commit}" >/dev/null; then
    show_commit "${COMMIT_SHA}"
  else
    echo "Warning: commit not found or not a valid commit: ${COMMIT_SHA}" >&2
    echo
  fi
fi

show_post_resolution_diff

if [ -n "${VERIFY_CMD}" ]; then
  if confirm "Run verification command?"; then
    run_verification "${VERIFY_CMD}"
  else
    echo "Skipped verification command."
  fi
fi

if [ "${DO_CONTINUE}" -eq 1 ]; then
  continue_cherry_pick
fi

if [ "${DO_ABORT}" -eq 1 ]; then
  abort_cherry_pick
fi

echo "Done. Review the status output above before making any further changes."