#!/usr/bin/env bash
# create-macos-usb.sh — Interactive bootable macOS USB creator
# Builds a bootable installer on a USB drive using Apple's `createinstallmedia`.
#
# Usage:  bash create-macos-usb.sh
# Requires: macOS, an "Install macOS *.app" in /Applications (or this script
# will offer to fetch the latest one), and a USB stick >= 16 GB.

set -euo pipefail

# ───── pretty output ──────────────────────────────────────────────────────────
RED=$'\033[1;31m'; GRN=$'\033[1;32m'; YLW=$'\033[1;33m'; BLU=$'\033[1;34m'; DIM=$'\033[2m'; RST=$'\033[0m'
info()  { printf "%s[i]%s %s\n" "$BLU" "$RST" "$*"; }
ok()    { printf "%s[✓]%s %s\n" "$GRN" "$RST" "$*"; }
warn()  { printf "%s[!]%s %s\n" "$YLW" "$RST" "$*"; }
err()   { printf "%s[x]%s %s\n" "$RED" "$RST" "$*" >&2; }
die()   { err "$*"; exit 1; }

confirm() {
  local prompt="${1:-Continue?}" default="${2:-N}" reply
  local hint
  if [[ "$default" =~ ^[Yy]$ ]]; then hint="[Y/n]"; else hint="[y/N]"; fi
  read -r -p "$prompt $hint " reply
  reply="${reply:-$default}"
  [[ "$reply" =~ ^[Yy]$ ]]
}

# ───── preflight ──────────────────────────────────────────────────────────────
[[ "$(uname -s)" == "Darwin" ]] || die "This script must be run on macOS."

# ───── 1. find or fetch a macOS installer ─────────────────────────────────────
info "Searching for macOS installer apps in /Applications…"

# bash 3.2 (stock macOS) has no `mapfile`; use a portable while-read loop instead.
INSTALLERS=()
while IFS= read -r line; do
  INSTALLERS+=("$line")
done < <(find /Applications -maxdepth 1 -type d -name "Install macOS*.app" 2>/dev/null | sort)

if (( ${#INSTALLERS[@]} == 0 )); then
  warn "No 'Install macOS *.app' found in /Applications."
  if confirm "Fetch the latest full installer now via softwareupdate? (≈ 13 GB download)" "Y"; then
    info "Running: softwareupdate --fetch-full-installer --full-installer-version <latest>"
    info "Listing available installer versions…"
    softwareupdate --list-full-installers || die "Could not list installers."
    read -r -p "Enter the macOS version to fetch (e.g. 15.4, 26.0): " VERSION
    [[ -n "$VERSION" ]] || die "No version provided."
    softwareupdate --fetch-full-installer --full-installer-version "$VERSION" \
      || die "Installer fetch failed."
    INSTALLERS=()
    while IFS= read -r line; do
      INSTALLERS+=("$line")
    done < <(find /Applications -maxdepth 1 -type d -name "Install macOS*.app" 2>/dev/null | sort)
  else
    die "Aborted — no installer available."
  fi
fi

(( ${#INSTALLERS[@]} > 0 )) || die "Still no installer found after fetch."

echo
info "Available macOS installers:"
for i in "${!INSTALLERS[@]}"; do
  name="$(basename "${INSTALLERS[$i]}" .app)"
  printf "  %s[%d]%s %s\n" "$YLW" "$((i+1))" "$RST" "$name"
done
echo
read -r -p "Pick an installer [1-${#INSTALLERS[@]}]: " CHOICE
[[ "$CHOICE" =~ ^[0-9]+$ ]] || die "Invalid choice."
(( CHOICE >= 1 && CHOICE <= ${#INSTALLERS[@]} )) || die "Choice out of range."
INSTALLER="${INSTALLERS[$((CHOICE-1))]}"
CIM="$INSTALLER/Contents/Resources/createinstallmedia"
[[ -x "$CIM" ]] || die "createinstallmedia not found / not executable in: $INSTALLER"
ok "Selected installer: $(basename "$INSTALLER")"

# ───── 2. detect USB keys only (strict Protocol: USB filter) ──────────────────
echo
info "Detecting USB drives only (Thunderbolt / internal disks are excluded)…"

USB_DISKS=()
USB_LABELS=()
while IFS= read -r DEV; do
  INFO_TXT="$(diskutil info "$DEV" 2>/dev/null)" || continue
  # Strict: must be USB protocol
  printf '%s\n' "$INFO_TXT" | grep -qE '^[[:space:]]*Protocol:[[:space:]]+USB[[:space:]]*$' || continue
  # Defensive: must not be reported as internal (belts + suspenders on top of `external physical`)
  printf '%s\n' "$INFO_TXT" | grep -qE '^[[:space:]]*Internal:[[:space:]]+Yes[[:space:]]*$' && continue

  SIZE="$(printf '%s\n' "$INFO_TXT" | awk -F': +' '/^[[:space:]]*Disk Size:/ {print $2; exit}')"
  MEDIA="$(printf '%s\n' "$INFO_TXT" | awk -F': +' '/^[[:space:]]*Device \/ Media Name:/ {print $2; exit}')"
  VOL="$(printf '%s\n' "$INFO_TXT" | awk -F': +' '/^[[:space:]]*Volume Name:/ {print $2; exit}')"

  USB_DISKS+=("$DEV")
  USB_LABELS+=("$DEV  —  ${MEDIA:-?}  —  ${SIZE:-?}${VOL:+  —  \"$VOL\"}")
done < <(diskutil list external physical 2>/dev/null | grep -oE '/dev/disk[0-9]+' | sort -u)

if (( ${#USB_DISKS[@]} == 0 )); then
  die "No USB drive detected. Plug a USB key in and re-run. (External SSDs over Thunderbolt are intentionally excluded — only Protocol: USB is accepted.)"
fi

echo
info "USB drives found:"
for i in "${!USB_DISKS[@]}"; do
  printf "  %s[%d]%s %s\n" "$YLW" "$((i+1))" "$RST" "${USB_LABELS[$i]}"
done
echo

read -r -p "Pick a USB drive [1-${#USB_DISKS[@]}]: " CHOICE
[[ "$CHOICE" =~ ^[0-9]+$ ]] || die "Invalid choice."
(( CHOICE >= 1 && CHOICE <= ${#USB_DISKS[@]} )) || die "Choice out of range."
DEVICE_PATH="${USB_DISKS[$((CHOICE-1))]}"
DISK="${DEVICE_PATH#/dev/}"

echo
info "About to ERASE this device:"
diskutil info "$DEVICE_PATH" | grep -E "(Device / Media Name|Disk Size|Volume Name|Protocol|Removable Media|Device Location)" || true
echo

warn "ALL DATA ON /dev/$DISK WILL BE DESTROYED."
confirm "Are you sure you want to continue?" "N" || die "Aborted by user."
read -r -p "Type the literal word ERASE in capitals to confirm: " CONF
[[ "$CONF" == "ERASE" ]] || die "Confirmation phrase mismatch — aborted."

# ───── 3. format the USB to Mac OS Extended (Journaled), GPT ──────────────────
VOLUME_NAME="MacOSInstaller"
info "Formatting /dev/$DISK as JHFS+ (GPT), volume name: $VOLUME_NAME …"
sudo diskutil eraseDisk JHFS+ "$VOLUME_NAME" GPT "/dev/$DISK" \
  || die "diskutil eraseDisk failed."
ok "Drive formatted."

# ───── 4. createinstallmedia ──────────────────────────────────────────────────
TARGET="/Volumes/$VOLUME_NAME"
[[ -d "$TARGET" ]] || die "Expected volume not mounted: $TARGET"

echo
info "Building bootable installer — this can take 20-40 minutes."
info "Command: sudo \"$CIM\" --volume \"$TARGET\" --nointeraction"
echo

sudo "$CIM" --volume "$TARGET" --nointeraction \
  || die "createinstallmedia failed."

echo
ok "Bootable installer created successfully on $TARGET."
echo
info "To boot from it:"
echo "  • Apple Silicon: shut down, then hold the power button until 'Loading startup options' appears, pick the USB."
echo "  • Intel Mac:     restart while holding the Option (⌥) key, pick the orange USB icon."
