#!/usr/bin/env bash
# ask-choice.sh  -  portable single-choice picker for platforms WITHOUT a native
# AskUserQuestion primitive (Copilot CLI and other numbered-menu
# Agent mode). It renders a numbered menu, reads one selection, and echoes the
# chosen option label on stdout. This is the universal fallback in the pipeline's
# picker abstraction (see refs/picker-contract.md): Claude Code uses native
# AskUserQuestion; everything else degrades to this.
#
# Usage:
#   ask-choice.sh "<question>" "<option1>" "<option2>" [option3 ...]
#
# Output: the selected option's exact label on stdout (nothing else on stdout).
# Prompts/menu render on stderr so stdout stays a clean machine-readable value.
#
# Non-interactive / autopilot / CI:
#   - ASK_CHOICE_DEFAULT=<label-or-1based-index>  picks without prompting.
#   - If stdin is not a TTY and no default is set, the FIRST option is chosen
#     and a notice is written to stderr (never blocks an automated run).
#
# Exit codes: 0 selection made (label on stdout) · 64 usage error.

set -uo pipefail

if [ "$#" -lt 3 ]; then
  echo "usage: ask-choice.sh \"<question>\" \"<option1>\" \"<option2>\" [option3 ...]" >&2
  exit 64
fi

QUESTION="$1"; shift
OPTIONS=("$@")
COUNT="${#OPTIONS[@]}"

# Resolve a default (label or 1-based index) to the option label, or empty.
resolve_default() {
  local d="$1"
  [ -z "$d" ] && { echo ""; return; }
  # numeric index?
  case "$d" in
    ''|*[!0-9]*) ;; # not a pure number, fall through to label match
    *)
      if [ "$d" -ge 1 ] && [ "$d" -le "$COUNT" ]; then
        echo "${OPTIONS[$((d - 1))]}"; return
      fi
      ;;
  esac
  # label match (case-insensitive, trimmed)
  local lower_d
  lower_d=$(printf '%s' "$d" | tr '[:upper:]' '[:lower:]')
  for opt in "${OPTIONS[@]}"; do
    if [ "$(printf '%s' "$opt" | tr '[:upper:]' '[:lower:]')" = "$lower_d" ]; then
      echo "$opt"; return
    fi
  done
  echo ""
}

if [ -n "${ASK_CHOICE_DEFAULT:-}" ]; then
  resolved=$(resolve_default "$ASK_CHOICE_DEFAULT")
  if [ -n "$resolved" ]; then
    printf '%s\n' "$resolved"
    exit 0
  fi
  echo "ask-choice: ASK_CHOICE_DEFAULT='${ASK_CHOICE_DEFAULT}' matched no option; falling through" >&2
fi

# Non-interactive with no usable default: pick the first option, don't block.
if [ ! -t 0 ]; then
  echo "ask-choice: no TTY and no ASK_CHOICE_DEFAULT - selecting first option '${OPTIONS[0]}'" >&2
  printf '%s\n' "${OPTIONS[0]}"
  exit 0
fi

# Interactive: render menu on stderr, read on stdin, loop until valid.
while true; do
  printf '%s\n' "$QUESTION" >&2
  local_i=1
  for opt in "${OPTIONS[@]}"; do
    printf '  %d) %s\n' "$local_i" "$opt" >&2
    local_i=$((local_i + 1))
  done
  printf 'Select [1-%d]: ' "$COUNT" >&2
  read -r reply || { printf '%s\n' "${OPTIONS[0]}"; exit 0; }
  case "$reply" in
    ''|*[!0-9]*)
      # allow typing the label too
      resolved=$(resolve_default "$reply")
      if [ -n "$resolved" ]; then printf '%s\n' "$resolved"; exit 0; fi
      echo "  invalid selection, try again" >&2
      ;;
    *)
      if [ "$reply" -ge 1 ] && [ "$reply" -le "$COUNT" ]; then
        printf '%s\n' "${OPTIONS[$((reply - 1))]}"
        exit 0
      fi
      echo "  out of range, try again" >&2
      ;;
  esac
done
