#!/usr/bin/env bash
#
# A wizard — walks a human through a manual procedure step by step.
# Generated by the /wizard skill.
#
# 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); RED=$(tput setaf 1)
else
  BOLD=""; DIM=""; RESET=""; BLUE=""; GREEN=""; YELLOW=""; RED=""
fi

# Author sets these two at the top of the stages section.
TOTAL_STAGES=0
TOTAL_MINUTES=0

_STAGE_INDEX=0
_MINUTES_ELAPSED=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 — wipe 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; then tput clear; else printf '\033[2J\033[3J\033[H'; fi
}

# banner "Title" — opening frame: what this wizard does and how long it takes.
banner() {
  _clear
  printf '\n%s%s  %s%s\n' "$BOLD" "$BLUE" "$1" "$RESET"
  printf '%s  %s stages · about %s minutes%s\n\n' \
    "$DIM" "$TOTAL_STAGES" "$TOTAL_MINUTES" "$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 — it remembers values already saved.%s\n' "$RESET"
  pause "Ready to start?"
}

# stage "Name" <minutes> — clear the screen, then announce a stage and show
# progress + time remaining. Clearing keeps only the current step on screen.
stage() {
  _clear
  _STAGE_INDEX=$((_STAGE_INDEX + 1))
  local remaining=$((TOTAL_MINUTES - _MINUTES_ELAPSED))
  (( remaining < 0 )) && remaining=0
  _MINUTES_ELAPSED=$((_MINUTES_ELAPSED + ${2:-0}))
  printf '\n%s%s▸ Stage %s/%s · %s%s  %s(~%s min left)%s\n' \
    "$BOLD" "$BLUE" "$_STAGE_INDEX" "$TOTAL_STAGES" "$1" "$RESET" "$DIM" "$remaining" "$RESET"
}

# say "..." — a plain instruction line.
say()  { printf '  %s\n' "$1"; }
# step "..." — 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 — open 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 warn "couldn't open a browser — visit it manually: $url"; fi
  } >/dev/null 2>&1 || warn "couldn't open a browser — visit it manually: $url"
}

# pause "msg" — wait 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" — 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.
_existing() {
  [[ -f "$ENV_FILE" ]] || return 1
  local line; line=$(grep -E "^${1}=" "$ENV_FILE" | tail -n1) || return 1
  printf '%s' "${line#*=}"
}

# ask KEY "Prompt" — read a value into $KEY. Offers the existing .env value as
# a default on re-runs (Enter keeps it). Visible input (non-secret).
ask() {
  local key="$1" prompt="$2" current input
  current=$(_existing "$key" || true)
  if [[ -n "$current" ]]; then
    printf '  %s%s%s %s[Enter keeps current]%s ' "$BOLD" "$prompt" "$RESET" "$DIM" "$RESET"
  else
    printf '  %s%s%s ' "$BOLD" "$prompt" "$RESET"
  fi
  read -r input || true
  [[ -z "$input" && -n "$current" ]] && input="$current"
  printf -v "$key" '%s' "$input"
}

# ask_secret KEY "Prompt" — like ask, but input is hidden.
ask_secret() {
  local key="$1" prompt="$2" current input
  current=$(_existing "$key" || true)
  if [[ -n "$current" ]]; then
    printf '  %s%s%s %s[Enter keeps current]%s ' "$BOLD" "$prompt" "$RESET" "$DIM" "$RESET"
  else
    printf '  %s%s%s ' "$BOLD" "$prompt" "$RESET"
  fi
  read -rs input || true
  printf '\n'
  [[ -z "$input" && -n "$current" ]] && input="$current"
  printf -v "$key" '%s' "$input"
}

# write_env KEY VALUE — upsert KEY=VALUE into ENV_FILE (creates it; replaces
# any existing line). Idempotent.
write_env() {
  local key="$1" value="$2" tmp
  touch "$ENV_FILE"
  tmp=$(mktemp)
  grep -vE "^${key}=" "$ENV_FILE" > "$tmp" || true
  printf '%s=%s\n' "$key" "$value" >> "$tmp"
  mv "$tmp" "$ENV_FILE"
  WRITTEN_ENV+=("$key")
  printf '  %s✓ wrote%s %s → %s\n' "$GREEN" "$RESET" "$key" "$ENV_FILE"
}

# set_secret NAME VALUE — set a GitHub Actions repo secret via gh. Falls back
# to a warning (and records it) if gh is unavailable or unauthenticated.
set_secret() {
  local name="$1" value="$2"
  if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
    if printf '%s' "$value" | gh secret set "$name" >/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)")
  warn "skipped GitHub secret $name — gh not ready; set it later"
}

# set_var NAME VALUE — set a GitHub Actions repo variable (non-secret).
set_var() {
  local name="$1" value="$2"
  if command -v gh >/dev/null 2>&1 && gh auth status >/dev/null 2>&1; then
    if gh variable set "$name" --body "$value" >/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 — gh not ready; set it later"
}

# finish — clear, then 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 the two totals to match the stages you write.
# ──────────────────────────────────────────────────────────────────────────

TOTAL_STAGES=6
TOTAL_MINUTES=12

# The .env lives at the repo root, wherever this script is run from.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ENV_FILE="$SCRIPT_DIR/../.env"

banner "Shopify app: theme-agent (Dev Dashboard)"

# ── Stage 1: create the app in the Dev Dashboard ──────────────────────────
stage "Create the app" 3
say "Since Jan 2026 apps are created in the Dev Dashboard (dev.shopify.com),"
say "not the store admin. The app gives LLMs Admin API access to metaobjects,"
say "metafields, product properties, and translations on bigscreenvr.myshopify.com."
open_url "https://dev.shopify.com/dashboard"
step "Sign in with the account that owns the Bigscreen Shopify organization"
step "(the org that contains the bigscreenvr store — client credentials only"
step "work when app and store share an organization)."
step "Create a new app named: theme-agent. Choose the manual/dashboard path if"
step "it offers a CLI vs. dashboard choice — we are not building a hosted app."
pause "App created? Press Enter."

# ── Stage 2: grant Admin API scopes ───────────────────────────────────────
stage "Grant Admin API scopes" 3
say "Scopes are configured on the app's version/configuration in the dashboard."
step "Find the Admin API access scopes section for the app and grant EXACTLY:"
say "    read_products            write_products"
say "    read_metaobjects         write_metaobjects"
say "    read_metaobject_definitions   write_metaobject_definitions"
say "    read_translations        write_translations"
warn "Nothing else — no orders, no customers, no themes. Narrow on purpose."
step "Save — and if the dashboard requires releasing a version for changes to"
step "take effect, release it."
pause "Scopes granted (and version released, if asked)? Press Enter."

# ── Stage 3: install the app on the store ─────────────────────────────────
stage "Install on the bigscreenvr store" 2
step "From the app's page, install it on the store (look for an Install /"
step "'Test on store' / distribution control and pick bigscreenvr)."
step "Approve the scope list in the store admin if it prompts."
pause "Installed on bigscreenvr? Press Enter."

# ── Stage 4: capture Client ID + Client Secret ────────────────────────────
stage "Capture Client ID and Client Secret" 2
say "Dev Dashboard apps have no static admin token. The runner exchanges the"
say "app's Client ID + Client Secret for a ~24h token automatically (cached in"
say ".shopify/, refreshed as needed) — so these two credentials are all we store."
step "Open the app's settings/credentials section and copy the Client ID."
ask SHOPIFY_CLIENT_ID "Paste the Client ID:"
step "Reveal and copy the Client Secret."
ask_secret SHOPIFY_CLIENT_SECRET "Paste the Client Secret:"
write_env SHOPIFY_CLIENT_ID "$SHOPIFY_CLIENT_ID"
write_env SHOPIFY_CLIENT_SECRET "$SHOPIFY_CLIENT_SECRET"
write_env SHOPIFY_STORE "bigscreenvr"
write_env SHOPIFY_API_VERSION "2026-07"
note "The .env is gitignored — it never leaves this machine."

# ── Stage 5: record in Server_Keys ────────────────────────────────────────
stage "Record credentials in Server_Keys" 1
say "Server_Keys is the source of truth; this .env is just a machine-local copy."
step "Add an entry: 'Shopify app theme-agent (Dev Dashboard) — Client ID +"
step "Client Secret, store bigscreenvr, 8 scopes: products/metaobjects/"
step "metaobject definitions/translations, read+write'."
pause "Recorded? Press Enter."

# ── Stage 6: smoke test ───────────────────────────────────────────────────
stage "Smoke test" 1
say "Minting a token and running a read-only query through the runner:"
if node "$SCRIPT_DIR/shopify-api.mjs" --query '{ shop { name currencyCode } }'; then
  say ""
  say "If you can see the shop name above, the pipe works end to end."
else
  warn "Smoke test failed — likely causes: app not installed on the store, app"
  warn "and store in different organizations, or a mistyped credential. Re-run"
  warn "this wizard (it keeps saved values) or debug with:"
  warn "  node scripts/shopify-api.mjs --query '{ shop { name } }'"
  SKIPPED+=("smoke test — runner query failed")
fi
# ──────────────────────────────────────────────────────────────────────────

finish
