#!/bin/bash
# =============================================================================
# officer-setup — shared foundation
# =============================================================================
#
# Sourced by officer-setup.sh before anything runs. DEFINITIONS ONLY, the same
# rule machine-setup/lib holds to: nothing here installs, writes or restarts.
#
# ── Why this is a separate script from machine-setup ──
#
# They answer different questions. machine-setup asks what a MACHINE should be —
# users, ssh, firewall, runtimes — and is worth running on a box that will never
# see Officer. This one puts Officer on a machine that is already ready, and
# assumes nothing about how it got that way.
#
# The split also means the failure modes stay apart: a broken firewall rule and a
# failed database migration are not the same kind of problem and should not be
# in the same run.

[[ -n "${OFFICER_SETUP_BASE_LOADED:-}" ]] && return 0
OFFICER_SETUP_BASE_LOADED=1

SUMMARY=()
ERRORS=()
CURRENT_STEP=""
SKIP_STEP=false

USERNAME="${SETUP_USERNAME:-}"
USER_HOME=""
OFFICER_ROOT="${OFFICER_ROOT:-}"
MACHINE_ROLE="${MACHINE_ROLE:-}"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m'

info() { echo -e "${CYAN}::${NC} $*"; }
ok() { echo -e "   ${GREEN}OK${NC}: $*"; }
warn() { echo -e "   ${YELLOW}WARN${NC}: $*"; }
fail() {
  echo -e "   ${RED}FAIL${NC}: $*"
  exit 1
}

ONLY_STEP="${ONLY_STEP:-}"

step() {
  CURRENT_STEP="$1"
  if [[ -n "$ONLY_STEP" ]]; then
    if [[ "${1,,}" == "${ONLY_STEP,,}" ]]; then
      SKIP_STEP=false
      echo ""
      echo -e "${BOLD}── $1 ──${NC}"
    else
      SKIP_STEP=true
    fi
    return
  fi
  if grep -qxF "$1" "$PROGRESS_FILE" 2>/dev/null; then
    echo -e "   ${GREEN}SKIP${NC}: $1 (already done)"
    SKIP_STEP=true
    return
  fi
  SKIP_STEP=false
  echo ""
  echo -e "${BOLD}── $1 ──${NC}"
}

skip() { [[ "$SKIP_STEP" == true ]]; }

step_ok() {
  [[ -n "$ONLY_STEP" ]] && return 0
  echo "$CURRENT_STEP" >>"$PROGRESS_FILE"
}

page() {
  if [[ -t 1 ]] && command -v more &>/dev/null; then more; else cat; fi
}

confirm() {
  local message="${1:-Proceed?}" default="${2:-y}" help_fn="${3:-}" answer prompt

  [[ "${ASSUME_YES:-}" == "1" ]] && { [[ "$default" == "y" ]] && return 0 || return 1; }

  if [[ "$default" == "y" ]]; then prompt="[Y/n]"; else prompt="[y/N]"; fi
  [[ -n "$help_fn" ]] && prompt="${prompt%]}/?]"

  while true; do
    if ! read -rp "  ${message} ${prompt}: " answer; then
      echo ""
      fail "No answer. Set ASSUME_YES=1 to run without prompts."
    fi
    [[ -z "$answer" ]] && answer="$default"
    case "$answer" in
      y | Y | yes | Yes) return 0 ;;
      n | N | no | No) return 1 ;;
      "?")
        if [[ -n "$help_fn" ]]; then
          echo ""
          "$help_fn" | page
          echo ""
        else
          warn "Answer y or n."
        fi
        ;;
      *) warn "Answer y or n${help_fn:+, or ? for what this is}." ;;
    esac
  done
}

ask_required() {
  local __var="$1" message="$2" default="$3" answer=""
  # Unattended takes the default where there IS one. Where there is not — the owning
  # account on a machine that machine-setup never ran on — it still asks, because
  # there is nothing to fall back to and a guess would install as the wrong user.
  if [[ "${UNATTENDED:-}" == "1" && -n "$default" ]]; then
    printf '  %s [%s] — unattended, taking the default\n' "$message" "$default"
    printf -v "$__var" '%s' "$default"
    return 0
  fi
  while [[ -z "$answer" ]]; do
    if ! read -rp "  ${message}${default:+ [$default]}: " answer; then
      echo ""
      fail "No answer."
    fi
    answer="${answer:-$default}"
    [[ -z "$answer" ]] && warn "This one cannot be left blank."
  done
  printf -v "$__var" '%s' "$answer"
}

user_group() { id -gn "${1:-$USERNAME}" 2>/dev/null || echo "${1:-$USERNAME}"; }

# Run something as the account that owns the install. Officer's files, its
# node_modules and its pm2 process list all belong to that account, not to root —
# a repository cloned as root is one the owner cannot pull.
as_owner() { (cd "${2:-/}" && sudo -H -u "$USERNAME" bash -c "$1"); }
