#!/usr/bin/env bash

set -euo pipefail

# This script maintains a custom release branch on top of an upstream release
# line while keeping your own local custom commits.
# It is designed for flows such as:
# - base tag:              v1.26.0-rc0
# - upstream release line: release/v1.26
# - custom maintenance:    release/v1.26-custom
# - custom release tags:   v1.26.0-custom, v1.26.1-custom
# It:
# 1. fetches the upstream release line and upstream compare branch;
# 2. creates or reuses a persistent custom maintenance branch;
# 3. cherry-picks missing upstream release commits onto that branch;
# 4. cherry-picks only your custom commits from your source branch;
# 5. keeps a backup branch, exact worktree snapshot, and saved stash so the
#    original state can be restored safely if something is not OK.

BASE_TAG="${BASE_TAG:-v1.26.0-rc0}"
UPSTREAM_RELEASE_BRANCH="${UPSTREAM_RELEASE_BRANCH:-release/v1.26}"
UPSTREAM_RELEASE_TARGET_REF="${UPSTREAM_RELEASE_TARGET_REF:-}"
MAINTENANCE_BRANCH="${MAINTENANCE_BRANCH:-release/v1.26-custom}"
CUSTOM_SOURCE_BRANCH="${CUSTOM_SOURCE_BRANCH:-main}"
UPSTREAM_COMPARE_BRANCH="${UPSTREAM_COMPARE_BRANCH:-main}"
CUSTOM_TAG_SUFFIX="${CUSTOM_TAG_SUFFIX:--custom}"
REMOTE_NAME="${REMOTE_NAME:-upstream}"
REMOTE_URL="${REMOTE_URL:-https://github.com/go-gitea/gitea.git}"
RUNTIME_ENV_FILE="${RUNTIME_ENV_FILE:-/tmp/.maintain-custom-release.env}"

DEFAULT_BASE_TAG="$BASE_TAG"
DEFAULT_UPSTREAM_RELEASE_BRANCH="$UPSTREAM_RELEASE_BRANCH"
DEFAULT_UPSTREAM_RELEASE_TARGET_REF="$UPSTREAM_RELEASE_TARGET_REF"
DEFAULT_MAINTENANCE_BRANCH="$MAINTENANCE_BRANCH"
DEFAULT_CUSTOM_SOURCE_BRANCH="$CUSTOM_SOURCE_BRANCH"
DEFAULT_UPSTREAM_COMPARE_BRANCH="$UPSTREAM_COMPARE_BRANCH"
DEFAULT_CUSTOM_TAG_SUFFIX="$CUSTOM_TAG_SUFFIX"

REPO_ROOT=""
GIT_DIR=""
STATE_FILE=""
SNAPSHOT_ROOT=""
RESTORE_POINT_ROOT=""
LEGACY_RESTORE_POINT_ROOT=""
CURRENT_BRANCH=""
BACKUP_BRANCH=""
STASH_REF=""
STASH_HASH=""
STATE_BRANCH=""
STATE_ENTRY_BRANCH=""
STATE_BACKUP_BRANCH=""
STATE_STASH_HASH=""
STATE_REMOTE_NAME=""
STATE_REMOTE_URL=""
STATE_BASE_TAG=""
STATE_UPSTREAM_RELEASE_BRANCH=""
STATE_UPSTREAM_RELEASE_TARGET_REF=""
STATE_UPSTREAM_COMPARE_BRANCH=""
STATE_CUSTOM_SOURCE_BRANCH=""
STATE_MAINTENANCE_BRANCH=""
STATE_START_HEAD=""
STATE_SNAPSHOT_PATH=""
STATE_PENDING_COMMITS=""
STATE_ACTION_LABEL=""
STATE_STATUS=""
STATE_FETCH_REF_STATES=""
STATE_CREATED_MAINTENANCE_BRANCH=""
STATE_UPDATED_AT=""
FETCH_REF_STATES=""
MAINTENANCE_BRANCH_WAS_CREATED="0"
SELECTED_RESTORE_POINT=""
SELECTED_STASH_TARGET=""
SELECTED_SNAPSHOT_TARGET=""

say() {
  printf '%s\n' "$*"
}

die() {
  say "ERROR: $*" >&2
  exit 1
}

save_runtime_settings() {
  cat >"$RUNTIME_ENV_FILE" <<EOF
BASE_TAG=$(printf '%q' "$BASE_TAG")
UPSTREAM_RELEASE_BRANCH=$(printf '%q' "$UPSTREAM_RELEASE_BRANCH")
UPSTREAM_RELEASE_TARGET_REF=$(printf '%q' "$UPSTREAM_RELEASE_TARGET_REF")
MAINTENANCE_BRANCH=$(printf '%q' "$MAINTENANCE_BRANCH")
CUSTOM_SOURCE_BRANCH=$(printf '%q' "$CUSTOM_SOURCE_BRANCH")
UPSTREAM_COMPARE_BRANCH=$(printf '%q' "$UPSTREAM_COMPARE_BRANCH")
CUSTOM_TAG_SUFFIX=$(printf '%q' "$CUSTOM_TAG_SUFFIX")
EOF
}

load_runtime_settings() {
  if [ -f "$RUNTIME_ENV_FILE" ]; then
    # shellcheck disable=SC1090
    . "$RUNTIME_ENV_FILE"
  fi

  BASE_TAG="${BASE_TAG:-$DEFAULT_BASE_TAG}"
  UPSTREAM_RELEASE_BRANCH="${UPSTREAM_RELEASE_BRANCH:-$DEFAULT_UPSTREAM_RELEASE_BRANCH}"
  UPSTREAM_RELEASE_TARGET_REF="${UPSTREAM_RELEASE_TARGET_REF:-$DEFAULT_UPSTREAM_RELEASE_TARGET_REF}"
  MAINTENANCE_BRANCH="${MAINTENANCE_BRANCH:-$DEFAULT_MAINTENANCE_BRANCH}"
  CUSTOM_SOURCE_BRANCH="${CUSTOM_SOURCE_BRANCH:-$DEFAULT_CUSTOM_SOURCE_BRANCH}"
  UPSTREAM_COMPARE_BRANCH="${UPSTREAM_COMPARE_BRANCH:-$DEFAULT_UPSTREAM_COMPARE_BRANCH}"
  CUSTOM_TAG_SUFFIX="${CUSTOM_TAG_SUFFIX:-$DEFAULT_CUSTOM_TAG_SUFFIX}"

  save_runtime_settings
}

show_usage() {
  cat <<EOF
Usage: $(basename "$0") [command]

Environment defaults:
  BASE_TAG=$BASE_TAG
  UPSTREAM_RELEASE_BRANCH=$UPSTREAM_RELEASE_BRANCH
  UPSTREAM_RELEASE_TARGET_REF=${UPSTREAM_RELEASE_TARGET_REF:-<branch-head>}
  MAINTENANCE_BRANCH=$MAINTENANCE_BRANCH
  CUSTOM_SOURCE_BRANCH=$CUSTOM_SOURCE_BRANCH
  UPSTREAM_COMPARE_BRANCH=$UPSTREAM_COMPARE_BRANCH
  CUSTOM_TAG_SUFFIX=$CUSTOM_TAG_SUFFIX

Available commands:
  configure
          Interactively update the current in-memory config values for this run.
  create-restore-point [label]
          Create a manual restore point for the current state, including a backup branch and an exact worktree snapshot.
  list-restore-points
          List available manual restore points created by this script.
  restore-point [restore-point-dir-or-name]
          Restore a manual restore point by path or by its final directory name. If omitted, the latest point for the current branch is used.
  delete-restore-point <restore-point-dir-or-name>
          Delete a manual restore point and its associated backup branch.
  status
          Show the current config, branch state, and saved recovery metadata.
  bootstrap
          Create or switch to the maintenance branch from BASE_TAG without importing any commits.
  fetch
          Fetch both the upstream compare branch and the upstream release target ref.
  fetch-upstream-compare
          Fetch only upstream/$UPSTREAM_COMPARE_BRANCH.
  fetch-upstream-target
          Fetch only the configured upstream release target ref, or upstream/$UPSTREAM_RELEASE_BRANCH when no target ref is set.
  plan
          Show which upstream release commits and which custom commits would be imported next.
  sync-upstream-compare
          Import only the missing commits from upstream/\$UPSTREAM_COMPARE_BRANCH, usually upstream/main.
  sync-upstream-target
          Import only the missing commits from the configured upstream release target ref, or from upstream/\$UPSTREAM_RELEASE_BRANCH when no target ref is set.
  sync-custom
          Import only your custom commits from \$CUSTOM_SOURCE_BRANCH, cherry-picking them from oldest to newest.
  sync-all
          Import missing upstream compare-branch commits, then upstream release-target commits, and finally your custom commits.
  continue
          Continue an interrupted cherry-pick sequence and finish any remaining queued commits.
  rollback [backup-branch|snapshot-dir]
          Restore the saved pre-import state, or an explicit backup branch / snapshot.
  restore-stash
          Re-apply the saved pre-import local stash from the last recorded state.
  restore-snapshot [snapshot-dir]
          Restore the exact saved repository snapshot from the last recorded real action, or from a specific snapshot directory.
  tag <upstream-version-tag>
          Create an annotated custom release tag like <tag>\$CUSTOM_TAG_SUFFIX on the maintenance branch.
  help
          Show this help text.

If no command is provided and the script is run from a terminal, an interactive
menu is shown.

Interactive menu structure:
  - Manual Backups >
      create, list, restore, delete manual restore points
  - Fetch upstreams >
      fetch upstream/main compare ref or the configured release target ref
  - Sync >
      sync compare commits, release-target commits, custom commits, or all
  - Rollback >
      choose the saved rollback state, a saved backup branch, or a snapshot
  - Restore >
      restore the saved stash or an exact snapshot, or open Delete Restore >

In every submenu:
  - press Enter for Back
  - or type b / B for Back
  - type 0 for Exit

Recommended order:
  1. Run:  ./.maintain-custom-release.sh status
  2. Optional but recommended:  ./.maintain-custom-release.sh create-restore-point before-custom-release-work
  3. First release on a new series:
     - run: ./.maintain-custom-release.sh bootstrap
  4. Fetch what you need:
     - upstream/main or your configured compare branch: ./.maintain-custom-release.sh fetch-upstream-compare
     - upstream release target ref: ./.maintain-custom-release.sh fetch-upstream-target
     - or both: ./.maintain-custom-release.sh fetch
  5. Run:  ./.maintain-custom-release.sh plan
  6. Then import in the order you want:
     - upstream/main or your configured compare branch first: ./.maintain-custom-release.sh sync-upstream-compare
     - upstream release target next: ./.maintain-custom-release.sh sync-upstream-target
     - only your custom commits: ./.maintain-custom-release.sh sync-custom
     - or both in one step: ./.maintain-custom-release.sh sync-all
     - for a fixed upstream release such as v1.26.0, set UPSTREAM_RELEASE_TARGET_REF first
  7. Later patch releases on the same series:
     - keep the same upstream minor release branch, for example release/v1.26
     - run the sync step you want, usually: ./.maintain-custom-release.sh sync-all
  8. If cherry-pick stops with conflicts:
     - either resolve them and continue with: ./.maintain-custom-release.sh continue
     - or return safely with: ./.maintain-custom-release.sh rollback
  9. If you want to return to an explicitly saved manual checkpoint:
     - run: ./.maintain-custom-release.sh restore-point
  10. When the branch looks correct:
     - run: ./.maintain-custom-release.sh tag v1.26.0
       which creates: v1.26.0-custom
EOF
}

prompt_with_default() {
  local prompt="$1" current_value="$2" reply=""

  printf '%s [%s]: ' "$prompt" "$current_value" >&2
  read -r reply
  if [ -n "$reply" ]; then
    printf '%s\n' "$reply"
  else
    printf '%s\n' "$current_value"
  fi
}

prompt_with_default_allow_clear() {
  local prompt="$1" current_value="$2" reply=""

  printf '%s [%s]: ' "$prompt" "$current_value" >&2
  read -r reply
  if [ "$reply" = "-" ]; then
    printf '\n'
  elif [ -n "$reply" ]; then
    printf '%s\n' "$reply"
  else
    printf '%s\n' "$current_value"
  fi
}

self_update_external_copy_if_needed() {
  local repo_root="" invoked_path="" canonical_path="" tmp_runtime_path="/tmp/.maintain-custom-release.sh"

  repo_root="$(git rev-parse --show-toplevel 2>/dev/null || true)"

  case "$0" in
    /*) invoked_path="$0" ;;
    *) invoked_path="$(pwd -P)/$0" ;;
  esac
  [ -f "$invoked_path" ] || invoked_path="$tmp_runtime_path"
  if [ -f "$invoked_path" ]; then
    invoked_path="$(cd "$(dirname "$invoked_path")" && pwd -P)/$(basename "$invoked_path")"
  fi

  if [ -n "$repo_root" ]; then
    canonical_path="$(cd "$repo_root" && pwd -P)/.maintain-custom-release.sh"
  else
    canonical_path=""
  fi

  if [ -n "$canonical_path" ] && [ -f "$canonical_path" ]; then
    if [ ! -f "$tmp_runtime_path" ] || ! cmp -s "$tmp_runtime_path" "$canonical_path"; then
      cp "$canonical_path" "$tmp_runtime_path"
      chmod +x "$tmp_runtime_path" >/dev/null 2>&1 || true
      say "Updated the temporary runtime script copy: $tmp_runtime_path"
    fi
    if [ "$invoked_path" != "$tmp_runtime_path" ]; then
      exec "$tmp_runtime_path" "$@"
    fi
    return 0
  fi

  if [ -f "$tmp_runtime_path" ] && [ "$invoked_path" != "$tmp_runtime_path" ]; then
    say "Repo copy is unavailable in the current checkout. Relaunching from the temporary runtime copy: $tmp_runtime_path"
    exec "$tmp_runtime_path" "$@"
  fi

  return 0
}

normalize_upstream_release_branch() {
  local fallback_branch=""

  if git rev-parse --verify "refs/remotes/$REMOTE_NAME/$UPSTREAM_RELEASE_BRANCH" >/dev/null 2>&1; then
    return
  fi

  if [[ "$UPSTREAM_RELEASE_BRANCH" =~ ^release/v([0-9]+)\.([0-9]+)\.[0-9]+$ ]]; then
    fallback_branch="release/v${BASH_REMATCH[1]}.${BASH_REMATCH[2]}"
    if git rev-parse --verify "refs/remotes/$REMOTE_NAME/$fallback_branch" >/dev/null 2>&1; then
      say "Configured upstream release branch '$UPSTREAM_RELEASE_BRANCH' does not exist. Using '$fallback_branch' instead."
      UPSTREAM_RELEASE_BRANCH="$fallback_branch"
      save_runtime_settings
      return
    fi
  fi

  die "Remote branch '$REMOTE_NAME/$UPSTREAM_RELEASE_BRANCH' was not found."
}

ensure_git_repo() {
  local raw_git_dir

  REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || die "This script must be run inside a git repository."
  raw_git_dir="$(git rev-parse --git-dir)"
  case "$raw_git_dir" in
    /*) GIT_DIR="$raw_git_dir" ;;
    *) GIT_DIR="$REPO_ROOT/$raw_git_dir" ;;
  esac
  STATE_FILE="$GIT_DIR/.maintain-custom-release-state"
  SNAPSHOT_ROOT="$GIT_DIR/.maintain-custom-release-snapshots"
  RESTORE_POINT_ROOT="$GIT_DIR/.maintain-custom-release-restore-points"
  LEGACY_RESTORE_POINT_ROOT="$GIT_DIR/.manual-restore-points"
}

write_state() {
  {
    printf 'STATE_BRANCH=%q\n' "$STATE_BRANCH"
    printf 'STATE_ENTRY_BRANCH=%q\n' "$STATE_ENTRY_BRANCH"
    printf 'STATE_BACKUP_BRANCH=%q\n' "$STATE_BACKUP_BRANCH"
    printf 'STATE_STASH_HASH=%q\n' "$STATE_STASH_HASH"
    printf 'STATE_REMOTE_NAME=%q\n' "$STATE_REMOTE_NAME"
    printf 'STATE_REMOTE_URL=%q\n' "$STATE_REMOTE_URL"
    printf 'STATE_BASE_TAG=%q\n' "$STATE_BASE_TAG"
    printf 'STATE_UPSTREAM_RELEASE_BRANCH=%q\n' "$STATE_UPSTREAM_RELEASE_BRANCH"
    printf 'STATE_UPSTREAM_RELEASE_TARGET_REF=%q\n' "$STATE_UPSTREAM_RELEASE_TARGET_REF"
    printf 'STATE_UPSTREAM_COMPARE_BRANCH=%q\n' "$STATE_UPSTREAM_COMPARE_BRANCH"
    printf 'STATE_CUSTOM_SOURCE_BRANCH=%q\n' "$STATE_CUSTOM_SOURCE_BRANCH"
    printf 'STATE_MAINTENANCE_BRANCH=%q\n' "$STATE_MAINTENANCE_BRANCH"
    printf 'STATE_START_HEAD=%q\n' "$STATE_START_HEAD"
    printf 'STATE_SNAPSHOT_PATH=%q\n' "$STATE_SNAPSHOT_PATH"
    printf 'STATE_PENDING_COMMITS=%q\n' "$STATE_PENDING_COMMITS"
    printf 'STATE_ACTION_LABEL=%q\n' "$STATE_ACTION_LABEL"
    printf 'STATE_STATUS=%q\n' "$STATE_STATUS"
    printf 'STATE_FETCH_REF_STATES=%q\n' "$STATE_FETCH_REF_STATES"
    printf 'STATE_CREATED_MAINTENANCE_BRANCH=%q\n' "$STATE_CREATED_MAINTENANCE_BRANCH"
    printf 'STATE_UPDATED_AT=%q\n' "$(date +%Y-%m-%dT%H:%M:%S)"
  } >"$STATE_FILE"
}

load_state() {
  ensure_git_repo
  [ -f "$STATE_FILE" ] || return 1
  # shellcheck disable=SC1090
  . "$STATE_FILE"
  [ -n "${STATE_BASE_TAG:-}" ] && BASE_TAG="$STATE_BASE_TAG"
  [ -n "${STATE_UPSTREAM_RELEASE_BRANCH:-}" ] && UPSTREAM_RELEASE_BRANCH="$STATE_UPSTREAM_RELEASE_BRANCH"
  if [ -n "${STATE_UPSTREAM_RELEASE_TARGET_REF:-}" ] || [ "${STATE_UPSTREAM_RELEASE_TARGET_REF+x}" = "x" ]; then
    UPSTREAM_RELEASE_TARGET_REF="${STATE_UPSTREAM_RELEASE_TARGET_REF:-}"
  fi
  [ -n "${STATE_UPSTREAM_COMPARE_BRANCH:-}" ] && UPSTREAM_COMPARE_BRANCH="$STATE_UPSTREAM_COMPARE_BRANCH"
  [ -n "${STATE_CUSTOM_SOURCE_BRANCH:-}" ] && CUSTOM_SOURCE_BRANCH="$STATE_CUSTOM_SOURCE_BRANCH"
  [ -n "${STATE_MAINTENANCE_BRANCH:-}" ] && MAINTENANCE_BRANCH="$STATE_MAINTENANCE_BRANCH"
  return 0
}

worktree_has_local_changes() {
  ! git diff --quiet || ! git diff --cached --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]
}

has_cherry_pick_in_progress() {
  [ -e "$(git rev-parse --git-path CHERRY_PICK_HEAD)" ]
}

sanitize_ref_name() {
  printf '%s\n' "${1//\//-}"
}

sanitize_storage_name() {
  local raw_value="${1:-}" sanitized=""

  sanitized="${raw_value//\//-}"
  sanitized="${sanitized// /-}"
  sanitized="${sanitized//:/-}"
  sanitized="${sanitized//[^[:alnum:]._-]/-}"
  printf '%s\n' "$sanitized"
}

ensure_rsync_available() {
  command -v rsync >/dev/null 2>&1 || die "rsync is required for exact repository snapshots."
}

snapshot_repo_dir() {
  printf '%s\n' "$1/repo"
}

is_valid_snapshot_dir() {
  [ -d "$1" ] && [ -d "$(snapshot_repo_dir "$1")" ]
}

snapshot_metadata_value() {
  local snapshot_dir="$1" key="$2"

  [ -f "$snapshot_dir/metadata.txt" ] || return 1
  sed -n "s/^${key}=//p" "$snapshot_dir/metadata.txt" | head -n 1
}

restore_point_refs_file() {
  printf '%s\n' "$1/script-managed-refs.txt"
}

restore_point_snapshots_file() {
  printf '%s\n' "$1/script-managed-snapshots.txt"
}

capture_script_managed_refs() {
  git for-each-ref --format='%(refname)|%(objectname)' \
    "refs/remotes/$REMOTE_NAME" \
    "refs/heads/$MAINTENANCE_BRANCH" \
    "refs/heads/backup/maint-"
}

cleanup_current_script_managed_refs() {
  local current_ref current_oid

  while IFS='|' read -r current_ref current_oid; do
    [ -n "$current_ref" ] || continue
    git update-ref -d "$current_ref" >/dev/null 2>&1 || true
  done < <(capture_script_managed_refs)
}

save_script_managed_restore_state() {
  local restore_point_dir="$1" refs_file snapshots_file

  refs_file="$(restore_point_refs_file "$restore_point_dir")"
  snapshots_file="$(restore_point_snapshots_file "$restore_point_dir")"

  capture_script_managed_refs | sort >"$refs_file"

  if [ -d "$SNAPSHOT_ROOT" ]; then
    find "$SNAPSHOT_ROOT" -mindepth 2 -maxdepth 2 -type d -printf '%P\n' | sort >"$snapshots_file"
  else
    : >"$snapshots_file"
  fi

  if [ -f "$STATE_FILE" ]; then
    cp "$STATE_FILE" "$restore_point_dir/.maintain-custom-release-state.saved"
  else
    rm -f "$restore_point_dir/.maintain-custom-release-state.saved"
  fi
}

restore_script_managed_refs() {
  local restore_point_dir="$1" refs_file current_ref current_oid saved_oid

  refs_file="$(restore_point_refs_file "$restore_point_dir")"
  if [ ! -f "$refs_file" ]; then
    cleanup_current_script_managed_refs
    return 0
  fi

  while IFS='|' read -r current_ref current_oid; do
    [ -n "$current_ref" ] || continue
    if ! grep -Fq "${current_ref}|" "$refs_file"; then
      git update-ref -d "$current_ref" >/dev/null 2>&1 || true
    fi
  done < <(capture_script_managed_refs)

  while IFS='|' read -r current_ref saved_oid; do
    [ -n "$current_ref" ] || continue
    [ -n "$saved_oid" ] || continue
    git update-ref "$current_ref" "$saved_oid"
  done <"$refs_file"
}

restore_script_managed_snapshots() {
  local restore_point_dir="$1" snapshots_file current_snapshot rel_path current_branch_dir

  snapshots_file="$(restore_point_snapshots_file "$restore_point_dir")"
  if [ ! -f "$snapshots_file" ]; then
    rm -rf "$SNAPSHOT_ROOT"
    return 0
  fi
  [ -d "$SNAPSHOT_ROOT" ] || return 0

  while IFS= read -r current_snapshot; do
    [ -n "$current_snapshot" ] || continue
    rel_path="${current_snapshot#$SNAPSHOT_ROOT/}"
    if ! grep -Fxq "$rel_path" "$snapshots_file"; then
      rm -rf "$current_snapshot"
    fi
  done < <(find "$SNAPSHOT_ROOT" -mindepth 2 -maxdepth 2 -type d | sort)

  while IFS= read -r current_branch_dir; do
    [ -n "$current_branch_dir" ] || continue
    if [ -z "$(find "$current_branch_dir" -mindepth 1 -maxdepth 1 -type d -print -quit)" ]; then
      rmdir "$current_branch_dir" 2>/dev/null || true
    fi
  done < <(find "$SNAPSHOT_ROOT" -mindepth 1 -maxdepth 1 -type d | sort)

  if [ -z "$(find "$SNAPSHOT_ROOT" -mindepth 1 -maxdepth 1 -print -quit)" ]; then
    rmdir "$SNAPSHOT_ROOT" 2>/dev/null || true
  fi
}

restore_script_managed_state_file() {
  local restore_point_dir="$1" saved_state_file

  saved_state_file="$restore_point_dir/.maintain-custom-release-state.saved"
  if [ -f "$saved_state_file" ]; then
    cp "$saved_state_file" "$STATE_FILE"
  else
    rm -f "$STATE_FILE"
  fi
}

cleanup_temporary_restore_artifacts() {
  local safety_backup_branch="${1:-}" safety_snapshot_dir="${2:-}"

  if [ -n "$safety_backup_branch" ] && git show-ref --verify --quiet "refs/heads/$safety_backup_branch"; then
    git branch -D "$safety_backup_branch" >/dev/null
  fi
  if [ -n "$safety_snapshot_dir" ] && [ -d "$safety_snapshot_dir" ]; then
    rm -rf "$safety_snapshot_dir"
  fi
}

create_worktree_snapshot_for_reason() {
  local reason="$1" safe_branch_name timestamp snapshot_dir snapshot_dir_repo

  ensure_rsync_available
  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  timestamp="$(date +%Y%m%d-%H%M%S)"
  snapshot_dir="$SNAPSHOT_ROOT/$safe_branch_name/${timestamp}-${reason}"
  snapshot_dir_repo="$(snapshot_repo_dir "$snapshot_dir")"

  mkdir -p "$snapshot_dir_repo"
  rsync --archive --delete --exclude='.git' "$REPO_ROOT"/ "$snapshot_dir_repo"/

  {
    printf 'branch=%s\n' "$CURRENT_BRANCH"
    printf 'head=%s\n' "$(git rev-parse HEAD)"
    printf 'created_at=%s\n' "$(date +%Y-%m-%dT%H:%M:%S)"
    printf 'reason=%s\n' "$reason"
  } >"$snapshot_dir/metadata.txt"

  printf '%s\n' "$snapshot_dir"
}

restore_worktree_snapshot() {
  local snapshot_dir="$1" snapshot_dir_repo

  ensure_rsync_available
  is_valid_snapshot_dir "$snapshot_dir" || die "Snapshot directory '$snapshot_dir' is not valid."
  snapshot_dir_repo="$(snapshot_repo_dir "$snapshot_dir")"

  rsync --archive --delete --exclude='.git' "$snapshot_dir_repo"/ "$REPO_ROOT"/
}

find_latest_snapshot_for_current() {
  local safe_branch_name snapshot_branch_dir

  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  snapshot_branch_dir="$SNAPSHOT_ROOT/$safe_branch_name"
  [ -d "$snapshot_branch_dir" ] || return 1
  find "$snapshot_branch_dir" -mindepth 1 -maxdepth 1 -type d | sort -r | head -n 1
}

find_latest_restore_point_for_current() {
  local validation_mode="${1:-valid}" restore_point_dir source_branch

  while IFS= read -r restore_point_dir; do
    [ -n "$restore_point_dir" ] || continue
    restore_point_matches_mode "$restore_point_dir" "$validation_mode" || continue
    source_branch="$(snapshot_metadata_value "$restore_point_dir" source_branch || true)"
    if [ "$source_branch" = "$CURRENT_BRANCH" ]; then
      printf '%s\n' "$restore_point_dir"
      return 0
    fi
  done < <(list_all_restore_points)

  return 1
}

list_all_restore_points() {
  {
    if [ -d "$RESTORE_POINT_ROOT" ]; then
      find "$RESTORE_POINT_ROOT" -mindepth 2 -maxdepth 2 -type d
    fi
    if [ -d "$LEGACY_RESTORE_POINT_ROOT" ]; then
      find "$LEGACY_RESTORE_POINT_ROOT" -mindepth 1 -maxdepth 1 -type d
    fi
  } | sort -r
}

is_restore_point_candidate_dir() {
  local target_dir="$1"

  [ -d "$target_dir" ] || return 1
  case "$target_dir" in
    "$RESTORE_POINT_ROOT"/*) ;;
    "$LEGACY_RESTORE_POINT_ROOT"/*) ;;
    *) return 1 ;;
  esac
  is_valid_snapshot_dir "$target_dir"
}

restore_point_has_live_backup_branch() {
  local target_dir="$1" backup_branch=""

  backup_branch="$(snapshot_metadata_value "$target_dir" backup_branch || true)"
  [ -n "$backup_branch" ] || return 0
  git show-ref --verify --quiet "refs/heads/$backup_branch"
}

is_valid_restore_point_dir() {
  local target_dir="$1"

  is_restore_point_candidate_dir "$target_dir" || return 1
  restore_point_has_live_backup_branch "$target_dir"
}

restore_point_matches_mode() {
  local target_dir="$1" validation_mode="${2:-valid}"

  case "$validation_mode" in
    valid) is_valid_restore_point_dir "$target_dir" ;;
    candidate) is_restore_point_candidate_dir "$target_dir" ;;
    *) die "Unknown restore-point validation mode: $validation_mode" ;;
  esac
}

resolve_restore_point_dir() {
  local requested_target="${1:-}" validation_mode="${2:-valid}" direct_target="" branch_target=""
  local -a matches=()

  if [ -z "$requested_target" ]; then
    find_latest_restore_point_for_current "$validation_mode"
    return
  fi

  if [ -d "$requested_target" ]; then
    direct_target="$(cd "$requested_target" && pwd -P)"
    if restore_point_matches_mode "$direct_target" "$validation_mode"; then
      printf '%s\n' "$direct_target"
      return
    fi
  fi

  branch_target="$RESTORE_POINT_ROOT/$(sanitize_ref_name "$CURRENT_BRANCH")/$requested_target"
  if [ -d "$branch_target" ] && restore_point_matches_mode "$branch_target" "$validation_mode"; then
    printf '%s\n' "$branch_target"
    return
  fi

  mapfile -t matches < <(list_all_restore_points | grep -E "/${requested_target}$" || true)
  if [ "${#matches[@]}" -eq 1 ] && restore_point_matches_mode "${matches[0]}" "$validation_mode"; then
    printf '%s\n' "${matches[0]}"
    return
  fi
  if [ "${#matches[@]}" -gt 1 ]; then
    die "More than one restore point matches '$requested_target'. Use the full path."
  fi

  die "Restore point '$requested_target' was not found."
}

create_restore_point_branch_for_label() {
  local label="$1" safe_branch_name safe_label timestamp branch_name

  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  safe_label="$(sanitize_storage_name "$label")"
  [ -n "$safe_label" ] || safe_label="manual"
  timestamp="$(date +%Y%m%d-%H%M%S)"
  branch_name="backup/restore-point-${safe_branch_name}-${safe_label}-${timestamp}"

  git branch "$branch_name" HEAD >/dev/null
  printf '%s\n' "$branch_name"
}

create_manual_restore_point() {
  local label="${1:-manual}" safe_branch_name safe_label timestamp restore_point_dir restore_point_repo_dir
  local restore_point_backup_branch current_head

  ensure_rsync_available
  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  safe_label="$(sanitize_storage_name "$label")"
  [ -n "$safe_label" ] || safe_label="manual"
  timestamp="$(date +%Y%m%d-%H%M%S)"
  restore_point_dir="$RESTORE_POINT_ROOT/$safe_branch_name/${timestamp}-${safe_label}"
  restore_point_repo_dir="$(snapshot_repo_dir "$restore_point_dir")"
  restore_point_backup_branch="$(create_restore_point_branch_for_label "$safe_label")"
  current_head="$(git rev-parse HEAD)"

  mkdir -p "$restore_point_repo_dir"
  rsync --archive --delete --exclude='.git' "$REPO_ROOT"/ "$restore_point_repo_dir"/

  {
    printf 'branch=%s\n' "$CURRENT_BRANCH"
    printf 'source_branch=%s\n' "$CURRENT_BRANCH"
    printf 'head=%s\n' "$current_head"
    printf 'created_at=%s\n' "$(date +%Y-%m-%dT%H:%M:%S)"
    printf 'label=%s\n' "$label"
    printf 'backup_branch=%s\n' "$restore_point_backup_branch"
    printf 'reason=manual_restore_point\n'
  } >"$restore_point_dir/metadata.txt"

  save_script_managed_restore_state "$restore_point_dir"

  printf '%s\n' "$restore_point_dir"
}

ensure_no_noncherrypick_git_operation_in_progress() {
  local git_path
  for git_path in MERGE_HEAD REVERT_HEAD BISECT_LOG rebase-merge rebase-apply; do
    if [ -e "$(git rev-parse --git-path "$git_path")" ]; then
      die "A git operation is already in progress ($git_path). Finish it before running this script."
    fi
  done
}

ensure_no_git_operation_in_progress() {
  local git_path
  for git_path in CHERRY_PICK_HEAD MERGE_HEAD REVERT_HEAD BISECT_LOG rebase-merge rebase-apply; do
    if [ -e "$(git rev-parse --git-path "$git_path")" ]; then
      die "A git operation is already in progress ($git_path). Finish it before running this script."
    fi
  done

  if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
    die "There are unmerged files in the working tree. Resolve them first."
  fi
}

ensure_current_branch() {
  CURRENT_BRANCH="$(git symbolic-ref --quiet --short HEAD || true)"
  [ -n "$CURRENT_BRANCH" ] || die "Detached HEAD is not supported. Check out a branch first."
}

ensure_current_branch_with_state_fallback() {
  CURRENT_BRANCH="$(git symbolic-ref --quiet --short HEAD || true)"
  if [ -n "$CURRENT_BRANCH" ]; then
    return
  fi

  if load_state && [ -n "${STATE_BRANCH:-}" ]; then
    CURRENT_BRANCH="$STATE_BRANCH"
    return
  fi

  die "Detached HEAD is not supported here and no saved branch state was found."
}

ensure_upstream_remote() {
  local current_remote_url

  if current_remote_url="$(git remote get-url "$REMOTE_NAME" 2>/dev/null)"; then
    if [ "$current_remote_url" != "$REMOTE_URL" ]; then
      die "Remote '$REMOTE_NAME' points to '$current_remote_url', expected '$REMOTE_URL'."
    fi
    return
  fi

  say "Adding remote '$REMOTE_NAME'..."
  git remote add "$REMOTE_NAME" "$REMOTE_URL"
}

ensure_release_refs_exist() {
  git rev-parse --verify "$BASE_TAG" >/dev/null 2>&1 || die "Base tag '$BASE_TAG' does not exist locally. Fetch tags first."
  normalize_upstream_release_branch
  git rev-parse --verify "$CUSTOM_SOURCE_BRANCH" >/dev/null 2>&1 || die "Custom source branch '$CUSTOM_SOURCE_BRANCH' does not exist locally."
  git rev-parse --verify "refs/remotes/$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH" >/dev/null 2>&1 || die "Remote compare branch '$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH' was not found."
}

ensure_base_tag_exists() {
  git rev-parse --verify "$BASE_TAG" >/dev/null 2>&1 || die "Base tag '$BASE_TAG' does not exist locally. Fetch tags first."
}

ensure_upstream_compare_ref_exists() {
  git rev-parse --verify "refs/remotes/$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH" >/dev/null 2>&1 || die "Remote compare branch '$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH' was not found."
}

ensure_upstream_target_ref_exists() {
  local source_ref=""

  if [ -n "$UPSTREAM_RELEASE_TARGET_REF" ]; then
    source_ref="$(resolve_upstream_release_import_ref)"
    git rev-parse --verify "$source_ref" >/dev/null 2>&1 || die "Upstream release target ref '$source_ref' was not found locally."
    return
  fi

  normalize_upstream_release_branch
  source_ref="$(resolve_upstream_release_import_ref)"
  git rev-parse --verify "$source_ref" >/dev/null 2>&1 || die "Upstream release target ref '$source_ref' was not found locally."
}

capture_fetch_ref_states() {
  local branch ref oid seen_branches=""

  FETCH_REF_STATES=""
  for branch in "$UPSTREAM_RELEASE_BRANCH" "$UPSTREAM_COMPARE_BRANCH"; do
    case " $seen_branches " in
      *" $branch "*) continue ;;
    esac
    seen_branches="$seen_branches $branch"
    ref="refs/remotes/$REMOTE_NAME/$branch"
    if git show-ref --verify --quiet "$ref"; then
      oid="$(git rev-parse "$ref")"
      FETCH_REF_STATES="${FETCH_REF_STATES}${ref}|1|${oid}"$'\n'
    else
      FETCH_REF_STATES="${FETCH_REF_STATES}${ref}|0|"$'\n'
    fi
  done
}

restore_fetch_ref_states() {
  local ref existed oid

  [ -n "${STATE_FETCH_REF_STATES:-}" ] || return 0

  while IFS='|' read -r ref existed oid; do
    [ -n "$ref" ] || continue
    if [ "$existed" = "1" ] && [ -n "$oid" ]; then
      git update-ref "$ref" "$oid"
    else
      git update-ref -d "$ref" >/dev/null 2>&1 || true
    fi
  done <<< "${STATE_FETCH_REF_STATES}"
}

resolve_upstream_release_import_ref() {
  if [ -n "$UPSTREAM_RELEASE_TARGET_REF" ]; then
    git rev-parse --verify "$UPSTREAM_RELEASE_TARGET_REF" >/dev/null 2>&1 || die "Configured upstream release target ref '$UPSTREAM_RELEASE_TARGET_REF' does not exist locally."
    printf '%s\n' "$UPSTREAM_RELEASE_TARGET_REF"
    return
  fi

  printf '%s/%s\n' "$REMOTE_NAME" "$UPSTREAM_RELEASE_BRANCH"
}

maintenance_branch_exists() {
  git show-ref --verify --quiet "refs/heads/$MAINTENANCE_BRANCH"
}

ensure_on_maintenance_branch() {
  if ! maintenance_branch_exists; then
    die "Maintenance branch '$MAINTENANCE_BRANCH' does not exist yet. Run 'bootstrap' first."
  fi

  if [ "$CURRENT_BRANCH" = "$MAINTENANCE_BRANCH" ]; then
    return
  fi

  if worktree_has_local_changes; then
    die "Current branch is '$CURRENT_BRANCH'. Switch to '$MAINTENANCE_BRANCH' with a clean worktree first."
  fi

  git switch "$MAINTENANCE_BRANCH" >/dev/null
  CURRENT_BRANCH="$MAINTENANCE_BRANCH"
}

create_or_switch_to_maintenance_branch() {
  MAINTENANCE_BRANCH_WAS_CREATED="0"
  if maintenance_branch_exists; then
    ensure_on_maintenance_branch
    return
  fi

  if [ "$CURRENT_BRANCH" != "$MAINTENANCE_BRANCH" ] && worktree_has_local_changes; then
    die "Create the maintenance branch from a clean worktree."
  fi

  git switch -c "$MAINTENANCE_BRANCH" "$BASE_TAG" >/dev/null
  MAINTENANCE_BRANCH_WAS_CREATED="1"
  CURRENT_BRANCH="$MAINTENANCE_BRANCH"
  say "Created maintenance branch '$MAINTENANCE_BRANCH' from '$BASE_TAG'."
}

create_backup_branch_for_reason() {
  local reason="$1" safe_branch_name timestamp branch_name

  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  timestamp="$(date +%Y%m%d-%H%M%S)"
  branch_name="backup/maint-${safe_branch_name}-${reason}-${timestamp}"

  git branch "$branch_name" HEAD >/dev/null
  printf '%s\n' "$branch_name"
}

find_latest_backup_branch_for_current() {
  local safe_branch_name

  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  git for-each-ref --sort=-creatordate --format='%(refname:short)' "refs/heads/backup/maint-${safe_branch_name}-*" | head -n 1
}

list_backup_branches_for_current() {
  local safe_branch_name

  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  git for-each-ref --sort=-creatordate --format='%(refname:short)' "refs/heads/backup/maint-${safe_branch_name}-*"
}

list_snapshot_dirs_for_current() {
  local safe_branch_name snapshot_branch_dir

  safe_branch_name="$(sanitize_ref_name "$CURRENT_BRANCH")"
  snapshot_branch_dir="$SNAPSHOT_ROOT/$safe_branch_name"
  [ -d "$snapshot_branch_dir" ] || return 0
  find "$snapshot_branch_dir" -mindepth 1 -maxdepth 1 -type d | sort -r
}

associated_backup_branch_for_snapshot() {
  local target_snapshot="$1" relative_path="" snapshot_branch_name="" snapshot_name=""
  local snapshot_timestamp="" snapshot_reason=""

  case "$target_snapshot" in
    "$SNAPSHOT_ROOT"/*) ;;
    *) return 1 ;;
  esac

  relative_path="${target_snapshot#$SNAPSHOT_ROOT/}"
  snapshot_branch_name="${relative_path%%/*}"
  snapshot_name="${relative_path#*/}"

  [ -n "$snapshot_branch_name" ] || return 1
  [ -n "$snapshot_name" ] || return 1
  [ "$snapshot_branch_name" != "$relative_path" ] || return 1
  [ "$snapshot_name" != "$relative_path" ] || return 1

  if [[ "$snapshot_name" =~ ^([0-9]{8}-[0-9]{6})-(.+)$ ]]; then
    snapshot_timestamp="${BASH_REMATCH[1]}"
    snapshot_reason="${BASH_REMATCH[2]}"
    printf 'backup/maint-%s-%s-%s\n' "$snapshot_branch_name" "$snapshot_reason" "$snapshot_timestamp"
    return 0
  fi

  printf 'backup/maint-%s-%s\n' "$snapshot_branch_name" "$snapshot_name"
}

prepare_safety_before_real_action() {
  local backup_reason="$1"

  STATE_START_HEAD="$(git rev-parse HEAD)"
  BACKUP_BRANCH="$(create_backup_branch_for_reason "$backup_reason")"
  STATE_SNAPSHOT_PATH="$(create_worktree_snapshot_for_reason "$backup_reason")"
  say "Safety backup branch created: $BACKUP_BRANCH"
  say "Exact worktree snapshot created: $STATE_SNAPSHOT_PATH"
}

stash_current_changes() {
  local stash_prefix="$1" timestamp stash_name

  STASH_REF=""
  STASH_HASH=""
  if ! worktree_has_local_changes; then
    say "No local tracked/untracked changes to stash."
    return
  fi

  timestamp="$(date +%Y%m%d-%H%M%S)"
  stash_name="${stash_prefix}-$(sanitize_ref_name "$CURRENT_BRANCH")-${timestamp}"

  say "Stashing local tracked and untracked changes..."
  git stash push --include-untracked --message "$stash_name" >/dev/null
  STASH_REF="$(git stash list -1 --format='%gd')"
  [ -n "$STASH_REF" ] || die "Failed to locate the created stash entry."
  STASH_HASH="$(git rev-parse "$STASH_REF")"
  [ -n "$STASH_HASH" ] || die "Failed to resolve the created stash hash."
  say "Local changes saved in $STASH_REF"
}

fetch_upstream_compare_ref() {
  say "Fetching latest compare-branch changes from $REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH..."
  git fetch --prune --no-tags "$REMOTE_NAME" "+refs/heads/$UPSTREAM_COMPARE_BRANCH:refs/remotes/$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH"
}

fetch_upstream_target_ref() {
  local target_ref="${UPSTREAM_RELEASE_TARGET_REF:-}"

  if [ -z "$target_ref" ]; then
    say "Fetching latest release-branch changes from $REMOTE_NAME/$UPSTREAM_RELEASE_BRANCH..."
    git fetch --prune --no-tags "$REMOTE_NAME" "+refs/heads/$UPSTREAM_RELEASE_BRANCH:refs/remotes/$REMOTE_NAME/$UPSTREAM_RELEASE_BRANCH"
    return
  fi

  if git fetch --no-tags "$REMOTE_NAME" "+refs/tags/$target_ref:refs/tags/$target_ref" >/dev/null 2>&1; then
    say "Fetched upstream release target tag: $target_ref"
    return
  fi

  say "Fetching configured release target branch/ref from $REMOTE_NAME/$target_ref..."
  git fetch --prune --no-tags "$REMOTE_NAME" "+refs/heads/$target_ref:refs/remotes/$REMOTE_NAME/$target_ref"
}

fetch_upstream_refs() {
  fetch_upstream_compare_ref
  if [ "$UPSTREAM_COMPARE_BRANCH" != "$UPSTREAM_RELEASE_BRANCH" ] || [ -n "$UPSTREAM_RELEASE_TARGET_REF" ]; then
    fetch_upstream_target_ref
  fi
}

update_state() {
  STATE_BRANCH="$CURRENT_BRANCH"
  STATE_BACKUP_BRANCH="$BACKUP_BRANCH"
  STATE_STASH_HASH="$STASH_HASH"
  STATE_REMOTE_NAME="$REMOTE_NAME"
  STATE_REMOTE_URL="$REMOTE_URL"
  STATE_BASE_TAG="$BASE_TAG"
  STATE_UPSTREAM_RELEASE_BRANCH="$UPSTREAM_RELEASE_BRANCH"
  STATE_UPSTREAM_RELEASE_TARGET_REF="$UPSTREAM_RELEASE_TARGET_REF"
  STATE_UPSTREAM_COMPARE_BRANCH="$UPSTREAM_COMPARE_BRANCH"
  STATE_CUSTOM_SOURCE_BRANCH="$CUSTOM_SOURCE_BRANCH"
  STATE_MAINTENANCE_BRANCH="$MAINTENANCE_BRANCH"
  STATE_ENTRY_BRANCH="${STATE_ENTRY_BRANCH:-$CURRENT_BRANCH}"
  STATE_FETCH_REF_STATES="${STATE_FETCH_REF_STATES:-}"
  STATE_CREATED_MAINTENANCE_BRANCH="${STATE_CREATED_MAINTENANCE_BRANCH:-0}"
  write_state
}

find_stash_ref_by_hash() {
  local target_hash="$1" hash ref

  while read -r hash ref; do
    if [ "$hash" = "$target_hash" ]; then
      printf '%s\n' "$ref"
      return 0
    fi
  done < <(git stash list --format='%H %gd')
  return 1
}

drop_stash_by_hash_if_present() {
  local target_hash="$1" stash_ref

  [ -n "$target_hash" ] || return 0
  if stash_ref="$(find_stash_ref_by_hash "$target_hash")"; then
    git stash drop "$stash_ref" >/dev/null
  fi
}

restore_stash() {
  local keep_saved_copy="${1:-0}" restore_target

  if [ -z "$STASH_HASH" ] && [ -z "$STASH_REF" ]; then
    return
  fi

  restore_target="${STASH_HASH:-$STASH_REF}"
  say "Restoring stashed local changes from $restore_target..."
  if git stash apply --index "$restore_target"; then
    STASH_REF=""
    if [ "$keep_saved_copy" -eq 0 ]; then
      drop_stash_by_hash_if_present "$STASH_HASH"
      STASH_HASH=""
      STATE_STASH_HASH=""
    else
      STATE_STASH_HASH="${STASH_HASH:-$restore_target}"
    fi
    STATE_STATUS="completed"
    update_state
    if [ "$keep_saved_copy" -eq 0 ]; then
      say "Local changes restored successfully."
    else
      say "Local changes restored successfully. The original stash was kept for rollback safety."
    fi
    return
  fi

  STATE_STATUS="restore_conflict"
  update_state
  say "Conflicts occurred while restoring local changes."
  say "Backup branch kept at: $BACKUP_BRANCH"
  say "Stash kept at: $restore_target"
  say "Resolve the conflicts manually, or return safely with: ./.maintain-custom-release.sh rollback"
  exit 1
}

ordered_upstream_release_commits_for_ref() {
  local target_ref="$1" source_ref="" available_commit_shas="" commit

  source_ref="$(resolve_upstream_release_import_ref)"

  available_commit_shas="$(git cherry -v "$target_ref" "$source_ref" | awk '$1=="+"{print $2}')"
  [ -n "$available_commit_shas" ] || return 0

  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    if printf '%s\n' "$available_commit_shas" | grep -Fxq "$commit"; then
      printf '%s\n' "$commit"
    fi
  done < <(git rev-list --reverse "${target_ref}..$source_ref")
}

ordered_upstream_compare_commits_for_ref() {
  local target_ref="$1" source_ref="$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH" available_commit_shas="" commit

  available_commit_shas="$(git cherry -v "$target_ref" "$source_ref" | awk '$1=="+"{print $2}')"
  [ -n "$available_commit_shas" ] || return 0

  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    if printf '%s\n' "$available_commit_shas" | grep -Fxq "$commit"; then
      printf '%s\n' "$commit"
    fi
  done < <(git rev-list --reverse "${target_ref}..$source_ref")
}

ordered_custom_commits_not_in_ref() {
  local target_ref="$1" custom_commit_shas="" still_missing_shas="" commit

  custom_commit_shas="$(git cherry -v "$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH" "$CUSTOM_SOURCE_BRANCH" | awk '$1=="+"{print $2}')"
  [ -n "$custom_commit_shas" ] || return 0

  still_missing_shas="$(git cherry -v "$target_ref" "$CUSTOM_SOURCE_BRANCH" | awk '$1=="+"{print $2}')"
  [ -n "$still_missing_shas" ] || return 0

  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    if printf '%s\n' "$custom_commit_shas" | grep -Fxq "$commit" && printf '%s\n' "$still_missing_shas" | grep -Fxq "$commit"; then
      printf '%s\n' "$commit"
    fi
  done < <(git rev-list --reverse "$REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH..$CUSTOM_SOURCE_BRANCH")
}

show_commit_list() {
  local header="$1" found_any=0 commit
  shift

  say "$header"
  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    found_any=1
    git show --no-patch --date=short --format='  - %h | %ad | %s' "$commit"
  done

  if [ "$found_any" -eq 0 ]; then
    say "  none"
  fi
}

run_configure() {
  say "Interactive configuration"
  BASE_TAG="$(prompt_with_default "Base tag" "$BASE_TAG")"
  UPSTREAM_RELEASE_BRANCH="$(prompt_with_default "Upstream release branch (for example release/v1.26)" "$UPSTREAM_RELEASE_BRANCH")"
  UPSTREAM_RELEASE_TARGET_REF="$(prompt_with_default_allow_clear "Upstream release target ref (example v1.26.0, use - to clear)" "$UPSTREAM_RELEASE_TARGET_REF")"
  MAINTENANCE_BRANCH="$(prompt_with_default "Custom maintenance branch" "$MAINTENANCE_BRANCH")"
  CUSTOM_SOURCE_BRANCH="$(prompt_with_default "Custom source branch" "$CUSTOM_SOURCE_BRANCH")"
  UPSTREAM_COMPARE_BRANCH="$(prompt_with_default "Upstream compare branch" "$UPSTREAM_COMPARE_BRANCH")"
  CUSTOM_TAG_SUFFIX="$(prompt_with_default "Custom tag suffix" "$CUSTOM_TAG_SUFFIX")"
  save_runtime_settings
  say "Configuration updated for the current run."
}

show_plan() {
  local plan_ref

  ensure_git_repo
  ensure_current_branch_with_state_fallback
  ensure_base_tag_exists
  ensure_upstream_compare_ref_exists
  ensure_upstream_target_ref_exists

  if maintenance_branch_exists; then
    plan_ref="$MAINTENANCE_BRANCH"
  else
    plan_ref="$BASE_TAG"
  fi

  say "Plan target ref: $plan_ref"
  show_commit_list "Upstream compare branch commits to import next:" < <(ordered_upstream_compare_commits_for_ref "$plan_ref")
  show_commit_list "Upstream release target commits to import next:" < <(ordered_upstream_release_commits_for_ref "$plan_ref")
  show_commit_list "Custom commits to import next (oldest first):" < <(ordered_custom_commits_not_in_ref "$plan_ref")
}

set_pending_commits_from_array() {
  local pending=("$@")
  STATE_PENDING_COMMITS="${pending[*]}"
}

pending_commits_to_array() {
  read -r -a PENDING_COMMITS_ARRAY <<< "${STATE_PENDING_COMMITS:-}"
}

finish_import_sequence() {
  STASH_HASH="${STATE_STASH_HASH:-}"
  STASH_REF=""
  restore_stash 1
  STATE_PENDING_COMMITS=""
  STATE_ACTION_LABEL=""
  STATE_STATUS="completed"
  update_state
  say "Import sequence completed."
  say "Safety backup branch available at: $BACKUP_BRANCH"
  say "Safety snapshot available at: $STATE_SNAPSHOT_PATH"
  if [ -n "$STATE_STASH_HASH" ]; then
    say "Original pre-import stash retained for rollback at: $STATE_STASH_HASH"
  fi
}

continue_pending_sequence() {
  local pending=() commit

  pending_commits_to_array
  pending=("${PENDING_COMMITS_ARRAY[@]}")

  while [ "${#pending[@]}" -gt 0 ]; do
    commit="${pending[0]}"
    say "Cherry-picking: $(git show --no-patch --format='%h %s' "$commit")"
    if ! git cherry-pick -x "$commit"; then
      set_pending_commits_from_array "${pending[@]}"
      STATE_STATUS="cherry_pick_conflict"
      update_state
      say "Cherry-pick stopped because of conflicts."
      say "Conflicting commit: $(git show --no-patch --format='%h %s' CHERRY_PICK_HEAD)"
      say "Resolve conflicts and continue with: ./.maintain-custom-release.sh continue"
      say "Or return safely with: ./.maintain-custom-release.sh rollback"
      exit 1
    fi
    pending=("${pending[@]:1}")
    set_pending_commits_from_array "${pending[@]}"
    STATE_STATUS="import_in_progress"
    update_state
  done

  finish_import_sequence
}

start_import_sequence() {
  local action_label="$1"
  shift
  local selected_commits=("$@")

  [ "${#selected_commits[@]}" -gt 0 ] || {
    say "No commits need to be imported for '$action_label'."
    return 0
  }

  prepare_safety_before_real_action "before-${action_label}"
  stash_current_changes "pre-${action_label}"
  set_pending_commits_from_array "${selected_commits[@]}"
  STATE_ACTION_LABEL="$action_label"
  STATE_STATUS="prepared"
  update_state
  continue_pending_sequence
}

collect_upstream_compare_commits_for_current_branch() {
  ordered_upstream_compare_commits_for_ref "$CURRENT_BRANCH"
}

collect_upstream_target_commits_for_current_branch() {
  ordered_upstream_release_commits_for_ref "$CURRENT_BRANCH"
}

collect_custom_commits_for_current_branch() {
  ordered_custom_commits_not_in_ref "$CURRENT_BRANCH"
}

run_status() {
  local stash_count latest_backup latest_snapshot latest_restore_point

  ensure_git_repo
  ensure_current_branch_with_state_fallback
  ensure_upstream_remote

  stash_count="$(git stash list | wc -l | tr -d ' ')"
  latest_backup="$(find_latest_backup_branch_for_current || true)"
  latest_snapshot="$(find_latest_snapshot_for_current || true)"
  latest_restore_point="$(find_latest_restore_point_for_current || true)"

  say "Repository: $(git rev-parse --show-toplevel)"
  say "Current branch: $CURRENT_BRANCH"
  say "Maintenance branch: $MAINTENANCE_BRANCH"
  say "Base tag: $BASE_TAG"
  say "Upstream release branch: $REMOTE_NAME/$UPSTREAM_RELEASE_BRANCH"
  say "Upstream release target ref: ${UPSTREAM_RELEASE_TARGET_REF:-$REMOTE_NAME/$UPSTREAM_RELEASE_BRANCH}"
  say "Custom source branch: $CUSTOM_SOURCE_BRANCH"
  say "Upstream compare branch: $REMOTE_NAME/$UPSTREAM_COMPARE_BRANCH"
  say "Custom tag suffix: $CUSTOM_TAG_SUFFIX"
  say "Working tree:"
  if ! worktree_has_local_changes; then
    say "  clean"
  else
    git status --short
  fi
  say "Stash entries: $stash_count"
  say "Latest backup for current branch: ${latest_backup:-none}"
  say "Latest snapshot for current branch: ${latest_snapshot:-none}"
  say "Latest restore point for current branch: ${latest_restore_point:-none}"
  if load_state; then
    say "Saved state: $STATE_STATUS"
    say "Saved backup branch: ${STATE_BACKUP_BRANCH:-none}"
    say "Saved starting commit: ${STATE_START_HEAD:-none}"
    say "Saved exact snapshot: ${STATE_SNAPSHOT_PATH:-none}"
    say "Saved original stash: ${STATE_STASH_HASH:-none}"
    say "Saved action label: ${STATE_ACTION_LABEL:-none}"
    say "Saved pending commits: ${STATE_PENDING_COMMITS:-none}"
  else
    say "Saved state: none"
  fi
}

run_create_restore_point() {
  local label="${1:-manual}" restore_point_dir=""

  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch_with_state_fallback

  restore_point_dir="$(create_manual_restore_point "$label")"
  say "Manual restore point created: $restore_point_dir"
  say "Associated backup branch: $(snapshot_metadata_value "$restore_point_dir" backup_branch || true)"
}

collect_restore_point_paths() {
  local validation_mode="${1:-valid}" restore_point_dir

  if [ ! -d "$RESTORE_POINT_ROOT" ] && [ ! -d "$LEGACY_RESTORE_POINT_ROOT" ]; then
    return 0
  fi

  while IFS= read -r restore_point_dir; do
    [ -n "$restore_point_dir" ] || continue
    restore_point_matches_mode "$restore_point_dir" "$validation_mode" || continue
    printf '%s\n' "$restore_point_dir"
  done < <(list_all_restore_points)
}

show_restore_point_entry() {
  local entry_number="$1" restore_point_dir="$2" validation_mode="${3:-valid}"
  local source_branch head_value backup_branch created_at

  source_branch="$(snapshot_metadata_value "$restore_point_dir" source_branch || true)"
  head_value="$(snapshot_metadata_value "$restore_point_dir" head || true)"
  backup_branch="$(snapshot_metadata_value "$restore_point_dir" backup_branch || true)"
  created_at="$(snapshot_metadata_value "$restore_point_dir" created_at || true)"

  say "$entry_number) $restore_point_dir"
  say "   source branch: ${source_branch:-unknown}"
  say "   head: ${head_value:-unknown}"
  say "   created at: ${created_at:-unknown}"
  say "   backup branch: ${backup_branch:-none}"

  if [ "$validation_mode" = "candidate" ] && ! is_valid_restore_point_dir "$restore_point_dir"; then
    say "   status: orphaned"
  fi
}

run_list_restore_points() {
  local restore_point_dir found_any=0 entry_number=1

  ensure_git_repo

  while IFS= read -r restore_point_dir; do
    [ -n "$restore_point_dir" ] || continue
    found_any=1
    show_restore_point_entry "$entry_number" "$restore_point_dir" valid
    entry_number=$((entry_number + 1))
  done < <(collect_restore_point_paths valid)

  if [ "$found_any" -eq 0 ]; then
    say "No valid restore points found."
  fi
}

select_restore_point_interactively() {
  local validation_mode="$1" action_label="$2" selection="" restore_point_dir=""
  local -a restore_point_dirs=()

  SELECTED_RESTORE_POINT=""
  mapfile -t restore_point_dirs < <(collect_restore_point_paths "$validation_mode")
  if [ "${#restore_point_dirs[@]}" -eq 0 ]; then
    if [ "$validation_mode" = "valid" ]; then
      say "No valid restore points found."
    else
      say "No restore points found."
    fi
    return 1
  fi

  for i in "${!restore_point_dirs[@]}"; do
    show_restore_point_entry "$((i + 1))" "${restore_point_dirs[$i]}" "$validation_mode"
  done

  printf 'Choose backup number to %s [0 cancel]: ' "$action_label"
  read -r selection

  case "$selection" in
    0|"") return 1 ;;
    *[!0-9]*) say "Invalid selection: $selection"; return 1 ;;
  esac

  if [ "$selection" -lt 1 ] || [ "$selection" -gt "${#restore_point_dirs[@]}" ]; then
    say "Invalid selection: $selection"
    return 1
  fi

  restore_point_dir="${restore_point_dirs[$((selection - 1))]}"
  SELECTED_RESTORE_POINT="$restore_point_dir"
  return 0
}

run_fetch_all() {
  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  fetch_upstream_refs
  say "Latest upstream compare branch and release target refs fetched."
}

run_fetch_upstream_compare() {
  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  fetch_upstream_compare_ref
  say "Latest upstream compare branch ref fetched."
}

run_fetch_upstream_target() {
  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  fetch_upstream_target_ref
  say "Latest upstream release target ref fetched."
}

run_bootstrap() {
  local entry_branch=""

  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  entry_branch="$CURRENT_BRANCH"
  ensure_base_tag_exists
  prepare_safety_before_real_action "before-bootstrap"
  create_or_switch_to_maintenance_branch
  STATE_ENTRY_BRANCH="$entry_branch"
  STATE_FETCH_REF_STATES=""
  STATE_CREATED_MAINTENANCE_BRANCH="$MAINTENANCE_BRANCH_WAS_CREATED"
  STATE_PENDING_COMMITS=""
  STATE_ACTION_LABEL="bootstrap"
  STATE_STATUS="bootstrap_completed"
  update_state
  say "Maintenance branch ready: $MAINTENANCE_BRANCH"
  say "Next step: run sync-upstream-compare, sync-upstream-target, sync-custom, or sync-all."
}

run_sync_upstream_compare() {
  local -a selected_commits=()
  local commit

  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  STATE_ENTRY_BRANCH="${STATE_ENTRY_BRANCH:-$CURRENT_BRANCH}"
  if [ -z "${STATE_FETCH_REF_STATES:-}" ]; then
    capture_fetch_ref_states
    STATE_FETCH_REF_STATES="$FETCH_REF_STATES"
  fi
  STATE_CREATED_MAINTENANCE_BRANCH="${STATE_CREATED_MAINTENANCE_BRANCH:-0}"
  fetch_upstream_compare_ref
  ensure_upstream_compare_ref_exists
  ensure_on_maintenance_branch

  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    selected_commits+=("$commit")
  done < <(collect_upstream_compare_commits_for_current_branch)

  start_import_sequence "sync-upstream-compare" "${selected_commits[@]}"
}

run_sync_upstream_target() {
  local -a selected_commits=()
  local commit

  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  STATE_ENTRY_BRANCH="${STATE_ENTRY_BRANCH:-$CURRENT_BRANCH}"
  if [ -z "${STATE_FETCH_REF_STATES:-}" ]; then
    capture_fetch_ref_states
    STATE_FETCH_REF_STATES="$FETCH_REF_STATES"
  fi
  STATE_CREATED_MAINTENANCE_BRANCH="${STATE_CREATED_MAINTENANCE_BRANCH:-0}"
  fetch_upstream_target_ref
  ensure_upstream_target_ref_exists
  ensure_on_maintenance_branch

  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    selected_commits+=("$commit")
  done < <(collect_upstream_target_commits_for_current_branch)

  start_import_sequence "sync-upstream-target" "${selected_commits[@]}"
}

run_sync_custom() {
  local -a selected_commits=()
  local commit

  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  STATE_ENTRY_BRANCH="${STATE_ENTRY_BRANCH:-$CURRENT_BRANCH}"
  if [ -z "${STATE_FETCH_REF_STATES:-}" ]; then
    capture_fetch_ref_states
    STATE_FETCH_REF_STATES="$FETCH_REF_STATES"
  fi
  STATE_CREATED_MAINTENANCE_BRANCH="${STATE_CREATED_MAINTENANCE_BRANCH:-0}"
  fetch_upstream_compare_ref
  ensure_release_refs_exist
  ensure_on_maintenance_branch

  while IFS= read -r commit; do
    [ -n "$commit" ] || continue
    selected_commits+=("$commit")
  done < <(collect_custom_commits_for_current_branch)

  start_import_sequence "sync-custom" "${selected_commits[@]}"
}

run_sync_all() {
  STATE_ENTRY_BRANCH=""
  STATE_FETCH_REF_STATES=""
  STATE_CREATED_MAINTENANCE_BRANCH="0"
  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  run_sync_upstream_compare
  run_sync_upstream_target
  run_sync_custom
}

run_continue() {
  ensure_git_repo
  ensure_current_branch_with_state_fallback
  ensure_upstream_remote
  load_state || die "No saved import state was found."
  [ "$CURRENT_BRANCH" = "${STATE_BRANCH:-$CURRENT_BRANCH}" ] || die "Saved import state belongs to branch '$STATE_BRANCH'. Check out that branch first."
  has_cherry_pick_in_progress || die "There is no in-progress cherry-pick to continue."

  BACKUP_BRANCH="${STATE_BACKUP_BRANCH:-}"
  STASH_HASH="${STATE_STASH_HASH:-}"
  STATE_STATUS="import_in_progress"
  update_state

  say "Continuing cherry-pick..."
  GIT_EDITOR=: git cherry-pick --continue

  pending_commits_to_array
  if [ "${#PENDING_COMMITS_ARRAY[@]}" -gt 0 ]; then
    set_pending_commits_from_array "${PENDING_COMMITS_ARRAY[@]:1}"
    update_state
  fi

  continue_pending_sequence
}

run_restore_saved_stash() {
  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch_with_state_fallback
  load_state || die "No saved state was found."
  [ "$CURRENT_BRANCH" = "${STATE_BRANCH:-$CURRENT_BRANCH}" ] || die "Saved state belongs to branch '$STATE_BRANCH'. Check out that branch first."
  [ -n "${STATE_STASH_HASH:-}" ] || die "There is no saved pre-import stash to restore."
  if worktree_has_local_changes; then
    die "The working tree is not clean. Commit, stash, or discard current changes before restoring the saved stash."
  fi

  prepare_safety_before_real_action "before-restore-stash"
  STASH_HASH="$STATE_STASH_HASH"
  STASH_REF=""
  restore_stash 1
  say "Saved pre-import local changes restored."
}

list_stash_entries() {
  git stash list --format='%gd%x09%H%x09%gs'
}

select_stash_interactively() {
  local choice stash_ref stash_hash stash_subject
  local -a stash_rows=()

  SELECTED_STASH_TARGET=""
  ensure_git_repo
  load_state || true
  mapfile -t stash_rows < <(list_stash_entries)
  if [ "${#stash_rows[@]}" -eq 0 ]; then
    say "No stash entries found."
    return 1
  fi

  say "Stash entries:"
  for i in "${!stash_rows[@]}"; do
    IFS=$'\t' read -r stash_ref stash_hash stash_subject <<<"${stash_rows[$i]}"
    if [ -n "${STATE_STASH_HASH:-}" ] && [ "$stash_hash" = "$STATE_STASH_HASH" ]; then
      say "  $((i + 1))) ${stash_ref} [saved state] - ${stash_subject}"
    else
      say "  $((i + 1))) ${stash_ref} - ${stash_subject}"
    fi
  done
  say "  B) Back"
  say "  0) Exit"
  printf 'Choose stash [Enter=Back]: '
  read -r choice

  case "$choice" in
    0) exit 0 ;;
    ""|[bB]) return 1 ;;
    *[!0-9]*)
      say "Invalid menu selection: $choice"
      return 1
      ;;
  esac

  if [ "$choice" -lt 1 ] || [ "$choice" -gt "${#stash_rows[@]}" ]; then
    say "Invalid menu selection: $choice"
    return 1
  fi

  SELECTED_STASH_TARGET="${stash_rows[$((choice - 1))]}"
  return 0
}

run_delete_saved_stash() {
  local target_spec="${1:-}" stash_ref="" stash_hash="" stash_subject=""

  ensure_git_repo
  load_state || true

  if [ -n "$target_spec" ]; then
    if [[ "$target_spec" == *$'\t'* ]]; then
      IFS=$'\t' read -r stash_ref stash_hash stash_subject <<<"$target_spec"
    else
      stash_ref="$target_spec"
      stash_hash="$(git rev-parse "$stash_ref" 2>/dev/null || true)"
    fi
  else
    [ -n "${STATE_STASH_HASH:-}" ] || die "There is no saved pre-import stash to delete."
    stash_hash="$STATE_STASH_HASH"
    stash_ref="$(find_stash_ref_by_hash "$stash_hash" || true)"
  fi

  [ -n "$stash_ref" ] || [ -n "$stash_hash" ] || die "There is no saved pre-import stash to delete."

  if [ -n "$stash_hash" ]; then
    drop_stash_by_hash_if_present "$stash_hash"
  elif [ -n "$stash_ref" ]; then
    git stash drop "$stash_ref" >/dev/null
  fi

  if [ -n "${STATE_STASH_HASH:-}" ] && [ "$stash_hash" = "$STATE_STASH_HASH" ]; then
    STATE_STASH_HASH=""
    write_state
    say "Deleted the saved pre-import stash reference."
  else
    say "Deleted stash: ${stash_ref:-$stash_hash}"
  fi
}

run_rollback() {
  local explicit_target="${1:-}" reset_target="" reset_snapshot=""
  local original_restore_stash_hash="" original_restore_start_head=""
  local original_action_backup_branch="" original_action_snapshot=""
  local rollback_safety_snapshot="" rollback_safety_backup="" rollback_safety_start_head=""
  local preserve_stash_hash=""
  local restore_branch_after="" created_branch_name="" remove_created_branch="0"
  local needs_state_branch_switch="0" allow_entry_branch_bootstrap_rollback="0"

  ensure_git_repo
  ensure_no_noncherrypick_git_operation_in_progress
  load_state || true
  ensure_current_branch_with_state_fallback
  ensure_upstream_remote

  if [ -z "$explicit_target" ] && [ -n "${STATE_BRANCH:-}" ] && [ "$CURRENT_BRANCH" != "$STATE_BRANCH" ]; then
    needs_state_branch_switch="1"
  fi

  if [ -n "$explicit_target" ] && is_valid_snapshot_dir "$explicit_target"; then
    reset_snapshot="$explicit_target"
  elif [ -n "$explicit_target" ]; then
    git show-ref --verify --quiet "refs/heads/$explicit_target" || die "Backup branch '$explicit_target' does not exist."
    reset_target="$explicit_target"
  else
    if [ "$needs_state_branch_switch" = "1" ] &&
      [ "${STATE_ACTION_LABEL:-}" = "bootstrap" ] &&
      [ "${STATE_CREATED_MAINTENANCE_BRANCH:-0}" = "1" ] &&
      [ -n "${STATE_ENTRY_BRANCH:-}" ] &&
      [ "$CURRENT_BRANCH" = "$STATE_ENTRY_BRANCH" ]; then
      allow_entry_branch_bootstrap_rollback="1"
      needs_state_branch_switch="0"
    fi

    if [ "$needs_state_branch_switch" = "1" ]; then
      die "Saved state belongs to branch '$STATE_BRANCH'. Check out that branch or pass an explicit backup branch or snapshot."
    fi
    if [ -n "${STATE_SNAPSHOT_PATH:-}" ] && is_valid_snapshot_dir "$STATE_SNAPSHOT_PATH"; then
      reset_snapshot="$STATE_SNAPSHOT_PATH"
    fi
    if [ -n "${STATE_START_HEAD:-}" ]; then
      reset_target="$STATE_START_HEAD"
    elif [ -n "${STATE_BACKUP_BRANCH:-}" ]; then
      reset_target="$STATE_BACKUP_BRANCH"
    else
      reset_target="$(find_latest_backup_branch_for_current || true)"
    fi
  fi

  if [ -z "$reset_target" ] && [ -n "$reset_snapshot" ]; then
    reset_target="$(snapshot_metadata_value "$reset_snapshot" head || true)"
  fi

  [ -n "$reset_target" ] || [ -n "$reset_snapshot" ] || die "No saved rollback target was found."

  original_restore_stash_hash="${STATE_STASH_HASH:-}"
  original_restore_start_head="${STATE_START_HEAD:-}"
  original_action_backup_branch="${STATE_BACKUP_BRANCH:-}"
  original_action_snapshot="${STATE_SNAPSHOT_PATH:-}"
  restore_branch_after="${STATE_ENTRY_BRANCH:-}"
  created_branch_name="${STATE_BRANCH:-$MAINTENANCE_BRANCH}"
  remove_created_branch="${STATE_CREATED_MAINTENANCE_BRANCH:-0}"
  if [ -z "$original_restore_start_head" ] && [ -n "$reset_snapshot" ]; then
    original_restore_start_head="$(snapshot_metadata_value "$reset_snapshot" head || true)"
  fi

  if has_cherry_pick_in_progress; then
    say "Aborting in-progress cherry-pick before rollback..."
    git cherry-pick --abort || die "Failed to abort the in-progress cherry-pick."
  fi

  if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
    die "There are still unmerged files in the working tree. Resolve or discard them before rollback."
  fi

  prepare_safety_before_real_action "before-rollback"
  rollback_safety_backup="$BACKUP_BRANCH"
  rollback_safety_snapshot="$STATE_SNAPSHOT_PATH"
  rollback_safety_start_head="$STATE_START_HEAD"

  preserve_stash_hash=""
  if worktree_has_local_changes; then
    stash_current_changes "pre-rollback-preserve"
    preserve_stash_hash="$STASH_HASH"
  fi

  if [ "$needs_state_branch_switch" = "1" ]; then
    if git show-ref --verify --quiet "refs/heads/$STATE_BRANCH"; then
      git switch "$STATE_BRANCH" >/dev/null
      CURRENT_BRANCH="$STATE_BRANCH"
    else
      die "Saved state branch '$STATE_BRANCH' does not exist anymore."
    fi
  fi

  if [ -n "$reset_target" ]; then
    say "Resetting '$CURRENT_BRANCH' to '$reset_target'..."
    git reset --hard "$reset_target" >/dev/null
  fi

  if [ -n "$original_restore_stash_hash" ]; then
    STASH_HASH="$original_restore_stash_hash"
    STASH_REF=""
    BACKUP_BRANCH="$rollback_safety_backup"
    say "Restoring original pre-import local changes..."
    restore_stash 1
  fi

  if [ -n "$reset_snapshot" ]; then
    say "Restoring exact worktree snapshot from: $reset_snapshot"
    restore_worktree_snapshot "$reset_snapshot"
  fi

  if [ "$allow_entry_branch_bootstrap_rollback" = "1" ]; then
    restore_branch_after="${STATE_ENTRY_BRANCH:-$restore_branch_after}"
  fi

  restore_fetch_ref_states

  if [ -n "$restore_branch_after" ] && [ "$CURRENT_BRANCH" != "$restore_branch_after" ] && ! worktree_has_local_changes; then
    git switch "$restore_branch_after" >/dev/null
    CURRENT_BRANCH="$restore_branch_after"
  fi

  if [ "$remove_created_branch" = "1" ] && [ -n "$created_branch_name" ] && git show-ref --verify --quiet "refs/heads/$created_branch_name"; then
    git branch -D "$created_branch_name" >/dev/null
    say "Removed created maintenance branch: $created_branch_name"
  fi

  say "Rollback completed."
  say "Restored starting commit: ${original_restore_start_head:-$reset_target}"
  if [ -n "$reset_snapshot" ]; then
    say "Restored snapshot: $reset_snapshot"
  fi
  if [ -n "$preserve_stash_hash" ]; then
    STATE_BRANCH="$CURRENT_BRANCH"
    STATE_ENTRY_BRANCH="$CURRENT_BRANCH"
    STATE_BACKUP_BRANCH="$rollback_safety_backup"
    STATE_STASH_HASH="$preserve_stash_hash"
    STATE_REMOTE_NAME="$REMOTE_NAME"
    STATE_REMOTE_URL="$REMOTE_URL"
    STATE_BASE_TAG="$BASE_TAG"
    STATE_UPSTREAM_RELEASE_BRANCH="$UPSTREAM_RELEASE_BRANCH"
    STATE_UPSTREAM_RELEASE_TARGET_REF="$UPSTREAM_RELEASE_TARGET_REF"
    STATE_UPSTREAM_COMPARE_BRANCH="$UPSTREAM_COMPARE_BRANCH"
    STATE_CUSTOM_SOURCE_BRANCH="$CUSTOM_SOURCE_BRANCH"
    STATE_MAINTENANCE_BRANCH="$MAINTENANCE_BRANCH"
    STATE_START_HEAD="$rollback_safety_start_head"
    STATE_SNAPSHOT_PATH="$rollback_safety_snapshot"
    STATE_PENDING_COMMITS=""
    STATE_ACTION_LABEL=""
    STATE_STATUS="rollback_completed"
    STATE_FETCH_REF_STATES=""
    STATE_CREATED_MAINTENANCE_BRANCH="0"
    write_state
    say "Safety backup of the pre-rollback state kept at: $rollback_safety_backup"
    say "Safety snapshot of the pre-rollback state kept at: $rollback_safety_snapshot"
    say "Safety stash of the pre-rollback local changes kept at: $preserve_stash_hash"
  else
    if [ -z "$explicit_target" ]; then
      cleanup_temporary_restore_artifacts "$original_action_backup_branch" "$original_action_snapshot"
    fi
    cleanup_temporary_restore_artifacts "$rollback_safety_backup" "$rollback_safety_snapshot"
    rm -f "$STATE_FILE"
    say "Temporary rollback safety artifacts were cleaned up."
  fi
}

run_restore_snapshot() {
  local target_snapshot="${1:-}" restore_safety_backup="" restore_safety_snapshot=""
  local restore_safety_start_head="" restore_start_head="" preserve_stash_hash=""

  ensure_git_repo
  ensure_no_noncherrypick_git_operation_in_progress
  load_state || die "No saved state was found."
  ensure_current_branch_with_state_fallback
  ensure_upstream_remote

  if [ -z "$target_snapshot" ]; then
    target_snapshot="${STATE_SNAPSHOT_PATH:-}"
  fi
  is_valid_snapshot_dir "$target_snapshot" || die "No valid saved snapshot was found to restore."
  restore_start_head="${STATE_START_HEAD:-}"
  if [ -z "$restore_start_head" ]; then
    restore_start_head="$(snapshot_metadata_value "$target_snapshot" head || true)"
  fi
  [ -n "$restore_start_head" ] || die "No saved starting commit was found for the snapshot restore."

  if has_cherry_pick_in_progress; then
    say "Aborting in-progress cherry-pick before snapshot restore..."
    git cherry-pick --abort || die "Failed to abort the in-progress cherry-pick."
  fi

  if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
    die "There are still unmerged files in the working tree. Resolve or discard them before restoring the snapshot."
  fi

  prepare_safety_before_real_action "before-restore-snapshot"
  restore_safety_backup="$BACKUP_BRANCH"
  restore_safety_snapshot="$STATE_SNAPSHOT_PATH"
  restore_safety_start_head="$STATE_START_HEAD"

  if worktree_has_local_changes; then
    stash_current_changes "pre-restore-snapshot-preserve"
    preserve_stash_hash="$STASH_HASH"
  fi

  say "Resetting '$CURRENT_BRANCH' to '$restore_start_head' before snapshot restore..."
  git reset --hard "$restore_start_head" >/dev/null

  if [ -n "${STATE_STASH_HASH:-}" ]; then
    STASH_HASH="$STATE_STASH_HASH"
    STASH_REF=""
    BACKUP_BRANCH="$restore_safety_backup"
    say "Restoring saved pre-import local changes..."
    restore_stash 1
  fi

  say "Restoring exact worktree snapshot from: $target_snapshot"
  restore_worktree_snapshot "$target_snapshot"

  say "Snapshot restore completed."
  if [ -n "$preserve_stash_hash" ]; then
    STATE_BRANCH="$CURRENT_BRANCH"
    STATE_BACKUP_BRANCH="$restore_safety_backup"
    STATE_STASH_HASH="$preserve_stash_hash"
    STATE_REMOTE_NAME="$REMOTE_NAME"
    STATE_REMOTE_URL="$REMOTE_URL"
    STATE_BASE_TAG="$BASE_TAG"
    STATE_UPSTREAM_RELEASE_BRANCH="$UPSTREAM_RELEASE_BRANCH"
    STATE_UPSTREAM_RELEASE_TARGET_REF="$UPSTREAM_RELEASE_TARGET_REF"
    STATE_UPSTREAM_COMPARE_BRANCH="$UPSTREAM_COMPARE_BRANCH"
    STATE_CUSTOM_SOURCE_BRANCH="$CUSTOM_SOURCE_BRANCH"
    STATE_MAINTENANCE_BRANCH="$MAINTENANCE_BRANCH"
    STATE_START_HEAD="$restore_safety_start_head"
    STATE_SNAPSHOT_PATH="$restore_safety_snapshot"
    STATE_PENDING_COMMITS=""
    STATE_ACTION_LABEL=""
    STATE_STATUS="snapshot_restored"
    write_state
    say "Safety backup of the pre-restore state kept at: $restore_safety_backup"
    say "Safety snapshot of the pre-restore state kept at: $restore_safety_snapshot"
    say "Safety stash of the pre-restore local changes kept at: $preserve_stash_hash"
  else
    cleanup_temporary_restore_artifacts "$restore_safety_backup" "$restore_safety_snapshot"
    rm -f "$STATE_FILE"
    say "Temporary snapshot-restore safety artifacts were cleaned up."
  fi
}

run_delete_snapshot() {
  local target_snapshot="${1:-}"
  local associated_backup_branch=""

  ensure_git_repo
  load_state || true

  if [ -z "$target_snapshot" ]; then
    target_snapshot="${STATE_SNAPSHOT_PATH:-}"
  fi

  [ -n "$target_snapshot" ] || die "There is no saved snapshot to delete."
  is_valid_snapshot_dir "$target_snapshot" || die "Snapshot '$target_snapshot' is not valid."

  rm -rf "$target_snapshot"
  associated_backup_branch="$(associated_backup_branch_for_snapshot "$target_snapshot" || true)"
  if [ -n "$associated_backup_branch" ] && git show-ref --verify --quiet "refs/heads/$associated_backup_branch"; then
    git branch -D "$associated_backup_branch" >/dev/null
    say "Deleted associated backup branch: $associated_backup_branch"
  fi
  if [ "${STATE_SNAPSHOT_PATH:-}" = "$target_snapshot" ]; then
    STATE_SNAPSHOT_PATH=""
    write_state
  fi
  say "Deleted snapshot: $target_snapshot"
}

select_snapshot_interactively() {
  local choice target_snapshot
  local -a snapshot_dirs=()

  SELECTED_SNAPSHOT_TARGET=""
  ensure_git_repo
  load_state || true
  ensure_current_branch_with_state_fallback
  mapfile -t snapshot_dirs < <(list_snapshot_dirs_for_current)
  if [ "${#snapshot_dirs[@]}" -eq 0 ]; then
    say "No snapshots found."
    return 1
  fi

  say "Snapshots:"
  for i in "${!snapshot_dirs[@]}"; do
    target_snapshot="${snapshot_dirs[$i]}"
    if [ -n "${STATE_SNAPSHOT_PATH:-}" ] && [ "$target_snapshot" = "$STATE_SNAPSHOT_PATH" ]; then
      say "  $((i + 1))) $(basename "$target_snapshot") [saved state]"
    else
      say "  $((i + 1))) $(basename "$target_snapshot")"
    fi
  done
  say "  B) Back"
  say "  0) Exit"
  printf 'Choose snapshot [Enter=Back]: '
  read -r choice

  case "$choice" in
    0) exit 0 ;;
    ""|[bB]) return 1 ;;
    *[!0-9]*)
      say "Invalid menu selection: $choice"
      return 1
      ;;
  esac

  if [ "$choice" -lt 1 ] || [ "$choice" -gt "${#snapshot_dirs[@]}" ]; then
    say "Invalid menu selection: $choice"
    return 1
  fi

  SELECTED_SNAPSHOT_TARGET="${snapshot_dirs[$((choice - 1))]}"
  return 0
}

run_restore_restore_point() {
  local requested_target="${1:-}" restore_point_dir=""
  local restore_source_branch="" restore_head="" restore_backup_branch=""
  local restore_safety_backup="" restore_safety_snapshot="" restore_safety_start_head=""
  local preserve_stash_hash=""

  ensure_git_repo
  ensure_no_noncherrypick_git_operation_in_progress
  ensure_current_branch_with_state_fallback

  restore_point_dir="$(resolve_restore_point_dir "$requested_target")"
  [ -n "$restore_point_dir" ] || die "No restore point was found."
  restore_source_branch="$(snapshot_metadata_value "$restore_point_dir" source_branch || true)"
  restore_head="$(snapshot_metadata_value "$restore_point_dir" head || true)"
  restore_backup_branch="$(snapshot_metadata_value "$restore_point_dir" backup_branch || true)"
  [ -n "$restore_head" ] || die "Restore point '$restore_point_dir' does not include a saved HEAD."

  if has_cherry_pick_in_progress; then
    say "Aborting in-progress cherry-pick before restore point restore..."
    git cherry-pick --abort || die "Failed to abort the in-progress cherry-pick."
  fi

  if [ -n "$(git diff --name-only --diff-filter=U)" ]; then
    die "There are still unmerged files in the working tree. Resolve or discard them before restoring the restore point."
  fi

  prepare_safety_before_real_action "before-restore-point"
  restore_safety_backup="$BACKUP_BRANCH"
  restore_safety_snapshot="$STATE_SNAPSHOT_PATH"
  restore_safety_start_head="$STATE_START_HEAD"

  if worktree_has_local_changes; then
    stash_current_changes "pre-restore-point-preserve"
    preserve_stash_hash="$STASH_HASH"
  fi

  if [ -n "$restore_source_branch" ] && [ "$CURRENT_BRANCH" != "$restore_source_branch" ]; then
    if git show-ref --verify --quiet "refs/heads/$restore_source_branch"; then
      git switch "$restore_source_branch" >/dev/null
    else
      git switch -c "$restore_source_branch" "$restore_head" >/dev/null
    fi
    CURRENT_BRANCH="$restore_source_branch"
  fi

  say "Resetting '$CURRENT_BRANCH' to '$restore_head' before restore point restore..."
  git reset --hard "$restore_head" >/dev/null

  say "Restoring exact worktree from restore point: $restore_point_dir"
  restore_worktree_snapshot "$restore_point_dir"

  restore_script_managed_refs "$restore_point_dir"
  restore_script_managed_snapshots "$restore_point_dir"
  restore_script_managed_state_file "$restore_point_dir"

  say "Restore point restored: $restore_point_dir"
  say "Original restore-point backup branch: ${restore_backup_branch:-none}"
  if [ -n "$preserve_stash_hash" ]; then
    STATE_BRANCH="$CURRENT_BRANCH"
    STATE_BACKUP_BRANCH="$restore_safety_backup"
    STATE_STASH_HASH="$preserve_stash_hash"
    STATE_REMOTE_NAME="$REMOTE_NAME"
    STATE_REMOTE_URL="$REMOTE_URL"
    STATE_BASE_TAG="$BASE_TAG"
    STATE_UPSTREAM_RELEASE_BRANCH="$UPSTREAM_RELEASE_BRANCH"
    STATE_UPSTREAM_RELEASE_TARGET_REF="$UPSTREAM_RELEASE_TARGET_REF"
    STATE_UPSTREAM_COMPARE_BRANCH="$UPSTREAM_COMPARE_BRANCH"
    STATE_CUSTOM_SOURCE_BRANCH="$CUSTOM_SOURCE_BRANCH"
    STATE_MAINTENANCE_BRANCH="$MAINTENANCE_BRANCH"
    STATE_START_HEAD="$restore_safety_start_head"
    STATE_SNAPSHOT_PATH="$restore_safety_snapshot"
    STATE_PENDING_COMMITS=""
    STATE_ACTION_LABEL="restore-point"
    STATE_STATUS="restore_point_restored"
    write_state
    say "Safety backup of the pre-restore state kept at: $restore_safety_backup"
    say "Safety snapshot of the pre-restore state kept at: $restore_safety_snapshot"
    say "Safety stash of the pre-restore local changes kept at: $preserve_stash_hash"
  else
    cleanup_temporary_restore_artifacts "$restore_safety_backup" "$restore_safety_snapshot"
    say "Temporary restore-point safety artifacts were cleaned up."
  fi
}

run_delete_restore_point() {
  local requested_target="${1:-}" restore_point_dir="" restore_point_backup_branch="" restore_point_parent=""

  [ -n "$requested_target" ] || die "Provide the restore point path or name to delete."
  ensure_git_repo
  restore_point_dir="$(resolve_restore_point_dir "$requested_target" candidate)"
  restore_point_backup_branch="$(snapshot_metadata_value "$restore_point_dir" backup_branch || true)"
  restore_point_parent="$(dirname "$restore_point_dir")"

  rm -rf "$restore_point_dir"
  if [ -n "$restore_point_backup_branch" ] && git show-ref --verify --quiet "refs/heads/$restore_point_backup_branch"; then
    git branch -D "$restore_point_backup_branch" >/dev/null
  fi
  rmdir "$restore_point_parent" >/dev/null 2>&1 || true

  say "Deleted restore point: $restore_point_dir"
  if [ -n "$restore_point_backup_branch" ]; then
    say "Deleted associated backup branch: $restore_point_backup_branch"
  fi
}

run_tag_release() {
  local upstream_version_tag="${1:-}" custom_tag=""

  [ -n "$upstream_version_tag" ] || die "Provide the upstream release tag, for example: v1.26.0"
  ensure_git_repo
  ensure_no_git_operation_in_progress
  ensure_current_branch
  ensure_upstream_remote
  ensure_on_maintenance_branch

  custom_tag="${upstream_version_tag}${CUSTOM_TAG_SUFFIX}"
  git rev-parse --verify "$custom_tag" >/dev/null 2>&1 && die "Tag '$custom_tag' already exists."

  git tag -a "$custom_tag" -m "Custom release ${custom_tag} from ${MAINTENANCE_BRANCH}"
  say "Created custom tag: $custom_tag"
}

show_backups_menu() {
  local choice restore_point_label restore_point_target delete_restore_point_target

  while true; do
    cat <<EOF
Manual Backups:
  1) Create manual restore point
  2) List manual restore points
  3) Restore manual restore point
  4) Delete manual restore point
  B) Back
  0) Exit
EOF
    printf 'Choose an action [Enter=Back]: '
    read -r choice

    case "$choice" in
      1)
        printf 'Optional restore point label [manual]: '
        read -r restore_point_label
        run_create_restore_point "${restore_point_label:-manual}"
        ;;
      2) run_list_restore_points ;;
      3)
        select_restore_point_interactively valid restore || continue
        restore_point_target="$SELECTED_RESTORE_POINT"
        run_restore_restore_point "$restore_point_target"
        return
        ;;
      4)
        select_restore_point_interactively candidate delete || continue
        delete_restore_point_target="$SELECTED_RESTORE_POINT"
        run_delete_restore_point "$delete_restore_point_target"
        ;;
      ""|[bB]) return ;;
      0) exit 0 ;;
      *) say "Invalid menu selection: $choice" ;;
    esac
  done
}

show_fetch_upstreams_menu() {
  local choice current_target_label

  while true; do
    current_target_label="${UPSTREAM_RELEASE_TARGET_REF:-$UPSTREAM_RELEASE_BRANCH}"
    cat <<EOF
Fetch upstreams:
  1) Fetch upstream/main compare ref
  2) Fetch upstream release target ref [${current_target_label}]
  B) Back
  0) Exit
EOF
    printf 'Choose an action [Enter=Back]: '
    read -r choice

    case "$choice" in
      1) run_fetch_upstream_compare ;;
      2) run_fetch_upstream_target ;;
      ""|[bB]) return ;;
      0) exit 0 ;;
      *) say "Invalid menu selection: $choice" ;;
    esac
  done
}

show_sync_menu() {
  local choice current_target_label

  while true; do
    current_target_label="${UPSTREAM_RELEASE_TARGET_REF:-$UPSTREAM_RELEASE_BRANCH}"
    cat <<EOF
Sync:
  1) Sync upstream/main compare commits
  2) Sync upstream release target commits [${current_target_label}]
  3) Sync custom commits (oldest first)
  4) Sync all
  B) Back
  0) Exit
EOF
    printf 'Choose an action [Enter=Back]: '
    read -r choice

    case "$choice" in
      1) run_sync_upstream_compare; return ;;
      2) run_sync_upstream_target; return ;;
      3) run_sync_custom; return ;;
      4) run_sync_all; return ;;
      ""|[bB]) return ;;
      0) exit 0 ;;
      *) say "Invalid menu selection: $choice" ;;
    esac
  done
}

show_restore_menu() {
  local choice snapshot_target=""

  while true; do
    cat <<EOF
Restore:
  1) Restore saved stash
  2) Restore exact snapshot
  3) Delete Restore >
  B) Back
  0) Exit
EOF
    printf 'Choose an action [Enter=Back]: '
    read -r choice

    case "$choice" in
      1) run_restore_saved_stash; return ;;
      2)
        printf 'Optional snapshot path (leave empty for saved state): '
        read -r snapshot_target
        run_restore_snapshot "$snapshot_target"
        return
        ;;
      3) show_delete_restore_menu ;;
      ""|[bB]) return ;;
      0) exit 0 ;;
      *) say "Invalid menu selection: $choice" ;;
    esac
  done
}

show_delete_restore_menu() {
  local choice snapshot_target=""

  while true; do
    cat <<EOF
Delete Restore:
  1) Delete saved stash >
  2) Delete saved exact snapshot >
  3) Delete exact snapshot by path
  B) Back
  0) Exit
EOF
    printf 'Choose an action [Enter=Back]: '
    read -r choice

    case "$choice" in
      1)
        select_stash_interactively || continue
        run_delete_saved_stash "$SELECTED_STASH_TARGET"
        ;;
      2)
        select_snapshot_interactively || continue
        run_delete_snapshot "$SELECTED_SNAPSHOT_TARGET"
        ;;
      3)
        printf 'Snapshot path to delete: '
        read -r snapshot_target
        [ -n "$snapshot_target" ] || continue
        run_delete_snapshot "$snapshot_target"
        ;;
      ""|[bB]) return ;;
      0) exit 0 ;;
      *) say "Invalid menu selection: $choice" ;;
    esac
  done
}

show_rollback_menu() {
  local choice current_target target
  local -a rollback_targets=()
  local -a rollback_labels=()

  ensure_git_repo
  load_state || true
  ensure_current_branch_with_state_fallback

  if [ -n "${STATE_START_HEAD:-}" ] || [ -n "${STATE_BACKUP_BRANCH:-}" ] || { [ -n "${STATE_SNAPSHOT_PATH:-}" ] && is_valid_snapshot_dir "$STATE_SNAPSHOT_PATH"; }; then
    rollback_targets+=("__SAVED_STATE__")
    rollback_labels+=("Saved rollback state")
  fi

  if [ -n "${STATE_BACKUP_BRANCH:-}" ] && git show-ref --verify --quiet "refs/heads/$STATE_BACKUP_BRANCH"; then
    rollback_targets+=("$STATE_BACKUP_BRANCH")
    rollback_labels+=("Saved backup branch [$STATE_BACKUP_BRANCH]")
  fi

  if [ -n "${STATE_SNAPSHOT_PATH:-}" ] && is_valid_snapshot_dir "$STATE_SNAPSHOT_PATH"; then
    rollback_targets+=("$STATE_SNAPSHOT_PATH")
    rollback_labels+=("Saved snapshot [$(basename "$STATE_SNAPSHOT_PATH")]")
  fi

  while IFS= read -r target; do
    [ -n "$target" ] || continue
    case " ${rollback_targets[*]} " in
      *" $target "*) continue ;;
    esac
    rollback_targets+=("$target")
    rollback_labels+=("Backup branch [$target]")
  done < <(list_backup_branches_for_current)

  while IFS= read -r target; do
    [ -n "$target" ] || continue
    case " ${rollback_targets[*]} " in
      *" $target "*) continue ;;
    esac
    rollback_targets+=("$target")
    rollback_labels+=("Snapshot [$(basename "$target")]")
  done < <(list_snapshot_dirs_for_current)

  if [ "${#rollback_targets[@]}" -eq 0 ]; then
    say "No rollback targets found."
    return
  fi

  while true; do
    say "Rollback:"
    for i in "${!rollback_targets[@]}"; do
      say "  $((i + 1))) ${rollback_labels[$i]}"
    done
    say "  B) Back"
    say "  0) Exit"
    printf 'Choose an action [Enter=Back]: '
    read -r choice

    case "$choice" in
      0) exit 0 ;;
      ""|[bB]) return ;;
      *[!0-9]*)
        say "Invalid menu selection: $choice"
        continue
        ;;
    esac

    if [ "$choice" -ge 1 ] && [ "$choice" -le "${#rollback_targets[@]}" ]; then
      current_target="${rollback_targets[$((choice - 1))]}"
      if [ "$current_target" = "__SAVED_STATE__" ]; then
        run_rollback ""
      else
        run_rollback "$current_target"
      fi
      return
    fi

    say "Invalid menu selection: $choice"
  done
}

show_menu() {
  local choice tag_value

  while true; do
    cat <<EOF
Available actions:
  1) Edit configuration
  2) Manual Backups >
  3) Show status
  4) Bootstrap maintenance branch
  5) Fetch upstreams >
  6) Show import plan
  7) Sync >
  8) Continue interrupted import
  9) Rollback >
  10) Restore >
  11) Create custom release tag
  12) Help
  0) Exit
EOF
    printf 'Choose an action: '
    read -r choice

    case "$choice" in
      1) run_configure ;;
      2) show_backups_menu ;;
      3) run_status ;;
      4) run_bootstrap ;;
      5) show_fetch_upstreams_menu ;;
      6) show_plan ;;
      7) show_sync_menu ;;
      8) run_continue; return ;;
      9) show_rollback_menu ;;
      10) show_restore_menu ;;
      11)
        printf 'Enter the upstream version tag to mark, for example v1.26.0: '
        read -r tag_value
        run_tag_release "$tag_value"
        return
        ;;
      12) show_usage ;;
      0) exit 0 ;;
      *) say "Invalid menu selection: $choice" ;;
    esac
  done
}

main() {
  self_update_external_copy_if_needed "$@"
  load_runtime_settings

  case "${1:-menu}" in
    configure) run_configure ;;
    create-restore-point) run_create_restore_point "${2:-manual}" ;;
    list-restore-points) run_list_restore_points ;;
    restore-point|restore-restore-point) run_restore_restore_point "${2:-}" ;;
    delete-restore-point) run_delete_restore_point "${2:-}" ;;
    status) run_status ;;
    fetch) run_fetch_all ;;
    fetch-upstream-compare) run_fetch_upstream_compare ;;
    fetch-upstream-target) run_fetch_upstream_target ;;
    plan) show_plan ;;
    bootstrap) run_bootstrap ;;
    sync-upstream|sync-upstream-target) run_sync_upstream_target ;;
    sync-upstream-compare) run_sync_upstream_compare ;;
    sync-custom) run_sync_custom ;;
    sync-all) run_sync_all ;;
    continue) run_continue ;;
    rollback) run_rollback "${2:-}" ;;
    restore-stash) run_restore_saved_stash ;;
    restore-snapshot) run_restore_snapshot "${2:-}" ;;
    tag) run_tag_release "${2:-}" ;;
    help|-h|--help) show_usage ;;
    menu)
      if [ -t 0 ] && [ -t 1 ]; then
        show_menu
      else
        show_usage
      fi
      ;;
    *)
      die "Unknown command: $1. Run with 'help' to see available options."
      ;;
  esac
}

main "$@"
