#!/usr/bin/env bash
#
# A wizard walks a human through a manual procedure, step by step.
# Generated by the wizard skill (/skill:wizard).
#
# Everything above the "STAGES" marker is the wizard library: do not hand-edit
# it. Author the per-step stages below the marker.

set -euo pipefail

# ──────────────────────────────────────────────────────────────────────────
# Wizard library: delightful, consistent UX, identical across every wizard.
# ──────────────────────────────────────────────────────────────────────────

if [[ -t 1 ]] && command -v tput >/dev/null 2>&1 && [[ "$(tput colors 2>/dev/null || echo 0)" -ge 8 ]]; then
  BOLD=$(tput bold); DIM=$(tput dim); RESET=$(tput sgr0)
  BLUE=$(tput setaf 4); GREEN=$(tput setaf 2); YELLOW=$(tput setaf 3)
else
  BOLD=""; DIM=""; RESET=""; BLUE=""; GREEN=""; YELLOW=""
fi

# Author sets these at the top of the stages section. REPO is the GitHub
# repository (owner/name) the human confirmed while the wizard was scoped;
# every gh secret/variable write goes to it, and none happens without it.
TOTAL_STAGES=0
REPO=""

# The library's own state. The intro (banner) copies REPO into _WIZ_REPO once
# the human confirms it, then makes both, and ENV_FILE, read-only: every gh
# write goes to _WIZ_REPO, so no stage or captured value can redirect it.
_WIZ_REPO=""
_WIZ_STAGE_INDEX=0
ENV_FILE="${ENV_FILE:-.env}"
WRITTEN_ENV=()    # KEYs written to ENV_FILE this run
WRITTEN_SECRET=() # secret NAMEs set this run
SKIPPED=()        # things we couldn't do (e.g. gh missing)

# _clear wipes the terminal so only the current step is on screen. No-op when
# output isn't a terminal, so piped logs stay readable.
_clear() {
  [[ -t 1 ]] || return 0
  if command -v tput >/dev/null 2>&1 && tput clear 2>/dev/null; then return 0; fi
  printf '\033[2J\033[3J\033[H'
}

# banner "Title" shows the opening frame: what this wizard does.
banner() {
  _clear
  printf '\n%s%s  %s%s\n' "$BOLD" "$BLUE" "$1" "$RESET"
  printf '%s  %s stages%s\n\n' "$DIM" "$TOTAL_STAGES" "$RESET"
  printf '%s  You drive the browser; this wizard tells you exactly what to do and\n' "$DIM"
  printf '  captures the values you copy back. Stop any time with Ctrl-C and re-run\n'
  printf '  later, since it remembers values already saved.%s\n' "$RESET"
  if _repo_ok "$REPO"; then
    printf '\n  GitHub secrets and variables go to %s%s%s.\n' "$BOLD" "$REPO" "$RESET"
    confirm "Is $REPO the right repository?" || { warn "stopped: fix REPO in this script, then re-run"; exit 1; }
    _WIZ_REPO="$REPO"
  fi
  readonly _WIZ_REPO REPO ENV_FILE
  pause "Ready to start?"
}

# _repo_ok VALUE: VALUE names one GitHub repository (owner/name).
_repo_ok() { [[ "$1" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; }

# _wiz_name KEY refuses (exit 2) a KEY bash can't assign or the library keeps
# for itself, so a captured value never overwrites the confirmed repository,
# the .env path or the library's state, and never changes which `gh`, host or
# identity the writes use, or how the shell behaves.
_wiz_name() {
  case "$1" in
    '' | [!A-Za-z_]* | *[!A-Za-z0-9_]* | _wiz_* | _WIZ_* | REPO | ENV_FILE | \
    TOTAL_STAGES | WRITTEN_ENV | WRITTEN_SECRET | SKIPPED | \
    BOLD | DIM | RESET | BLUE | GREEN | YELLOW | \
    GH_* | GITHUB_* | GIT_* | PATH | HOME | IFS | ENV | BASH* | SHELLOPTS | \
    PS4 | LD_* | DYLD_*)
      printf 'wizard: %s is reserved by the wizard library or not a variable name; capture it under another name\n' "$1" >&2
      exit 2
      ;;
  esac
}

# stage "Name" clears the screen, then announces a stage and shows progress.
# Clearing keeps only the current step on screen.
stage() {
  _clear
  _WIZ_STAGE_INDEX=$((_WIZ_STAGE_INDEX + 1))
  printf '\n%s%s▸ Stage %s/%s · %s%s\n' \
    "$BOLD" "$BLUE" "$_WIZ_STAGE_INDEX" "$TOTAL_STAGES" "$1" "$RESET"
}

# say "..." prints a plain instruction line.
say()  { printf '  %s\n' "$1"; }
# step "..." is a numbered-feeling action the human takes in the browser.
step() { printf '  %s•%s %s\n' "$BLUE" "$RESET" "$1"; }
note() { printf '  %s%s%s\n' "$DIM" "$1" "$RESET"; }
warn() { printf '  %s⚠ %s%s\n' "$YELLOW" "$1" "$RESET"; }

# open_url URL opens it in the human's browser, cross-platform incl. WSL.
open_url() {
  local url="$1"
  printf '  %s↗ opening%s %s\n' "$GREEN" "$RESET" "$url"
  { if   command -v wslview     >/dev/null 2>&1; then wslview "$url"
    elif command -v explorer.exe >/dev/null 2>&1; then explorer.exe "$url"
    elif command -v xdg-open    >/dev/null 2>&1; then xdg-open "$url"
    elif command -v open        >/dev/null 2>&1; then open "$url"
    else false; fi
  } >/dev/null 2>&1 || warn "couldn't open a browser, so visit it manually: $url"
}

# pause "msg" waits for the human to confirm they've done the manual part.
pause() {
  printf '  %s%s%s ' "$DIM" "${1:-Press Enter to continue}" "$RESET"
  read -r _ || true
}

# confirm "question" is a y/N gate; returns success on yes.
confirm() {
  local reply=""
  printf '  %s? %s [y/N] ' "$YELLOW" "$1"
  read -r reply || true
  [[ "$reply" =~ ^[Yy] ]]
}

# _existing KEY: current value of KEY in ENV_FILE, if any, with write_env's single
# quotes or a plain dotenv double-quoted value undone.
_existing() {
  [[ -f "$ENV_FILE" ]] || return 1
  local line value sq="'\\''"; line=$(grep -E "^${1}=" "$ENV_FILE" | tail -n1) || return 1
  value="${line#*=}"
  if [[ "$value" == \'*\' ]]; then value="${value:1:${#value}-2}"; value="${value//"$sq"/\'}"
  elif [[ "$value" == \"*\" ]]; then
    value="${value:1:${#value}-2}"
    [[ "$value" == *[\\\$\"]* ]] && return 1   # escapes, $ or ": can't decode safely; ask again
  fi
  printf '%s' "$value"
}

# ask KEY "Prompt" reads a value into $KEY. Offers the existing .env value as
# a default on re-runs (Enter keeps it). Visible input (non-secret), edited
# with Readline. Fails at EOF with no input.
ask() {
  _wiz_name "$1"
  local _wiz_key="$1" _wiz_prompt="$2" _wiz_current _wiz_input _wiz_s=$'\001' _wiz_e=$'\002' _wiz_p _wiz_rc=0
  _wiz_current=$(_existing "$_wiz_key" || true)
  # Readline needs the colour codes wrapped in \001..\002 to place the cursor.
  _wiz_p="  $_wiz_s$BOLD$_wiz_e$_wiz_prompt$_wiz_s$RESET$_wiz_e "
  [[ -n "$_wiz_current" ]] && _wiz_p+="$_wiz_s$DIM${_wiz_e}[Enter keeps current]$_wiz_s$RESET$_wiz_e "
  read -e -r -p "$_wiz_p" _wiz_input || _wiz_rc=1
  if (( _wiz_rc )) && [[ -z "$_wiz_input" ]]; then return 1; fi
  [[ -z "$_wiz_input" && -n "$_wiz_current" ]] && _wiz_input="$_wiz_current"
  printf -v "$_wiz_key" '%s' "$_wiz_input"
}

# ask_secret KEY "Prompt" is like ask, but input is hidden.
ask_secret() {
  _wiz_name "$1"
  local _wiz_key="$1" _wiz_prompt="$2" _wiz_current _wiz_input _wiz_rc=0
  _wiz_current=$(_existing "$_wiz_key" || true)
  if [[ -n "$_wiz_current" ]]; then
    printf '  %s%s%s %s[Enter keeps current]%s ' "$BOLD" "$_wiz_prompt" "$RESET" "$DIM" "$RESET"
  else
    printf '  %s%s%s ' "$BOLD" "$_wiz_prompt" "$RESET"
  fi
  read -rs _wiz_input || _wiz_rc=1
  printf '\n'
  if (( _wiz_rc )) && [[ -z "$_wiz_input" ]]; then return 1; fi
  [[ -z "$_wiz_input" && -n "$_wiz_current" ]] && _wiz_input="$_wiz_current"
  printf -v "$_wiz_key" '%s' "$_wiz_input"
}

# write_env KEY VALUE upserts KEY='VALUE' into ENV_FILE (replaces any existing
# line) and sets $KEY. Idempotent. Creates ENV_FILE at mode 0600; writes through
# a symlink and keeps an existing file's mode.
write_env() {
  _wiz_name "$1"
  local _wiz_key="$1" _wiz_value="$2" _wiz_tmp _wiz_sq="'\\''"
  [[ -e "$ENV_FILE" ]] || (umask 077 && : > "$ENV_FILE")
  _wiz_tmp=$(mktemp)
  grep -vE "^${_wiz_key}=" "$ENV_FILE" > "$_wiz_tmp" || true
  printf "%s='%s'\n" "$_wiz_key" "${_wiz_value//\'/$_wiz_sq}" >> "$_wiz_tmp"
  cat "$_wiz_tmp" > "$ENV_FILE"
  rm -f "$_wiz_tmp"
  printf -v "$_wiz_key" '%s' "$_wiz_value"
  WRITTEN_ENV+=("$_wiz_key")
  printf '  %s✓ wrote%s %s → %s\n' "$GREEN" "$RESET" "$_wiz_key" "$ENV_FILE"
}

# set_secret NAME VALUE sets a GitHub Actions secret in the repository the
# human confirmed in the intro, via gh, never in gh's default repo. Falls back
# to a warning (and records it) if REPO is unset or unconfirmed or gh is
# unavailable or unauthenticated.
set_secret() {
  local name="$1" value="$2"
  if _repo_ok "$_WIZ_REPO" && command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
    if printf '%s' "$value" | gh secret set "$name" --repo "$_WIZ_REPO" >/dev/null 2>&1; then
      WRITTEN_SECRET+=("$name")
      printf '  %s✓ set%s GitHub secret %s\n' "$GREEN" "$RESET" "$name"
      return
    fi
  fi
  SKIPPED+=("GitHub secret $name (set it manually: gh secret set $name --repo ${_WIZ_REPO:-<owner>/<repo>})")
  warn "skipped GitHub secret $name: REPO unset or unconfirmed, or gh not ready; set it later"
}

# set_var NAME VALUE sets a GitHub Actions variable (non-secret) in the
# confirmed repository.
set_var() {
  local name="$1" value="$2"
  if _repo_ok "$_WIZ_REPO" && command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
    if gh variable set "$name" --body "$value" --repo "$_WIZ_REPO" >/dev/null 2>&1; then
      printf '  %s✓ set%s GitHub variable %s\n' "$GREEN" "$RESET" "$name"
      return
    fi
  fi
  SKIPPED+=("GitHub variable $name")
  warn "skipped GitHub variable $name, REPO unset or unconfirmed, or gh not ready; set it later"
}

# finish clears, then shows a closing summary of everything configured.
finish() {
  _clear
  printf '\n%s%s  ✓ Setup complete%s\n' "$BOLD" "$GREEN" "$RESET"
  (( ${#WRITTEN_ENV[@]} ))    && note "wrote ${#WRITTEN_ENV[@]} value(s) to $ENV_FILE: ${WRITTEN_ENV[*]}"
  (( ${#WRITTEN_SECRET[@]} )) && note "set ${#WRITTEN_SECRET[@]} GitHub secret(s): ${WRITTEN_SECRET[*]}"
  if (( ${#SKIPPED[@]} )); then
    printf '\n'; warn "still to do by hand:"
    for s in "${SKIPPED[@]}"; do note "  - $s"; done
  fi
  printf '\n'
}

# ──────────────────────────────────────────────────────────────────────────
# STAGES: author this section. One stage() per step the human takes.
# Replace the example below. Set TOTAL_STAGES to match the stages you write,
# and REPO to the owner/name the human confirmed (leave it "" if no stage
# writes a GitHub secret or variable). Capture each value under its own name:
# ask, ask_secret and write_env refuse the library's names (REPO, ENV_FILE,
# TOTAL_STAGES, ...) and any _wiz_ name.
# Keep every stage inside run_wizard and the last line as is: bash then parses
# the whole file before the first prompt, so an edit mid-run can't break it.
# ──────────────────────────────────────────────────────────────────────────

run_wizard() {

TOTAL_STAGES=1
REPO="<owner>/<repo>"

banner "Stripe setup"

# ── Example stage: replace with your real steps ───────────────────────────
stage "Stripe: API keys"
say "We'll grab your Stripe test keys and store them for local dev + CI."
open_url "https://dashboard.stripe.com/test/apikeys"
step "On the API keys page, copy the Publishable key (starts pk_test_)."
ask STRIPE_PUBLISHABLE_KEY "Paste the publishable key:"
step "Click 'Reveal test key' on the Secret key row, then copy it."
ask_secret STRIPE_SECRET_KEY "Paste the secret key:"
write_env STRIPE_PUBLISHABLE_KEY "$STRIPE_PUBLISHABLE_KEY"
write_env STRIPE_SECRET_KEY "$STRIPE_SECRET_KEY"
set_secret STRIPE_SECRET_KEY "$STRIPE_SECRET_KEY"   # CI needs this one
# ──────────────────────────────────────────────────────────────────────────

finish
}

run_wizard "$@"; exit
