#!/usr/bin/env bash
# PMOS one-line setup for macOS and Linux (initiative one-line-setup).
#
#   curl -fsSL https://unpkg.com/create-pmos/install.sh | bash
#
# Installs what is missing, makes a PMOS folder and opens the PMOS app:
#   1. Node.js (latest LTS from nodejs.org, into ~/.pmos/node; no Homebrew, no admin)
#   2. git (macOS: Apple's Command Line Tools, one system dialog; Linux: the package manager)
#   3. Claude Code (its own installer, claude.ai/install.sh)
#   4. the newest PMOS release that npm can download (a release a few minutes old may not download yet)
#   5. the PMOS kit in ~/PMOS (npx create-pmos)
#   6. the PMOS app (npx create-pmos workspace), which opens in the browser
# Every step checks first and skips what is already there, so running the line again is safe.
#
# Settings (environment variables):
#   PMOS_DIR=<folder>      the PMOS folder (default: ~/PMOS)
#   PMOS_NO_OPEN=1         do not open the browser at the end
#   PMOS_SKIP_CLAUDE=1     do not install Claude Code
#   PMOS_PKG=<spec>        the create-pmos package to run (default: create-pmos@latest)
set -euo pipefail

PMOS_HOME="${PMOS_HOME:-$HOME/.pmos}"
PMOS_DIR="${PMOS_DIR:-$HOME/PMOS}"
PMOS_PKG_GIVEN="${PMOS_PKG:-}"
PMOS_PKG="${PMOS_PKG:-create-pmos@latest}"
NODE_MIN=18
MARK="# added by PMOS setup"

say()  { printf '\033[1m==>\033[0m %s\n' "$*"; }
ok()   { printf '    \033[32m✓\033[0m %s\n' "$*"; }
fail() { printf '\n\033[31m✗ %s\033[0m\n' "$1" >&2; [ -n "${2:-}" ] && printf '  Try: %s\n' "$2" >&2; exit 1; }
have() { command -v "$1" >/dev/null 2>&1; }

OS="$(uname -s)"
case "$OS" in
  Darwin) PLAT=darwin ;;
  Linux)  PLAT=linux ;;
  *) fail "This setup is for macOS and Linux. On Windows, paste the PowerShell line instead." \
          "powershell -ExecutionPolicy Bypass -c \"iex ((New-Object Net.WebClient).DownloadString('https://unpkg.com/create-pmos/install.ps1'))\"" ;;
esac
case "$(uname -m)" in
  arm64|aarch64) ARCH=arm64 ;;
  x86_64|amd64)  ARCH=x64 ;;
  *) fail "This computer's processor ($(uname -m)) is not supported." ;;
esac

# The shell start-up files that new Terminal windows read, so PATH changes last. On Linux a new window
# reads ~/.bashrc and a login reads ~/.bash_profile or ~/.profile, so both get the line.
profile_files() {
  case "${SHELL:-}" in
    */zsh)  echo "$HOME/.zprofile" ;;
    */bash) if [ "$PLAT" = darwin ]; then echo "$HOME/.bash_profile"
            else
              echo "$HOME/.bashrc"
              # A login shell reads ~/.bash_profile instead of ~/.profile when it exists.
              if [ -f "$HOME/.bash_profile" ]; then echo "$HOME/.bash_profile"; else echo "$HOME/.profile"; fi
            fi ;;
    *)      echo "$HOME/.profile" ;;
  esac
}
# Put a folder on PATH now and in new Terminal windows. Adds the line once per file.
add_path() {
  local dir="$1" f
  case ":$PATH:" in *":$dir:"*) ;; *) export PATH="$dir:$PATH" ;; esac
  for f in $(profile_files); do
    touch "$f"
    grep -qsF "$dir" "$f" || printf '\nexport PATH="%s:$PATH" %s\n' "$dir" "$MARK" >> "$f"
  done
}

node_major() { node -p 'process.versions.node.split(".")[0]' 2>/dev/null || echo 0; }

echo
echo "PMOS setup — this installs what is missing and opens PMOS."
echo

# ── 1. Node.js ────────────────────────────────────────────────────────────────────────────────
say "Checking Node.js"
[ -x "$PMOS_HOME/node/bin/node" ] && add_path "$PMOS_HOME/node/bin"
if have node && [ "$(node_major)" -ge "$NODE_MIN" ]; then
  ok "Node.js $(node -v) is installed"
else
  say "Installing Node.js (latest LTS) into $PMOS_HOME/node"
  have curl || fail "curl is missing." "install curl, then paste the line again"
  # The list is newest first; the first entry whose "lts" is not false is the latest LTS. awk reads to the end
  # (no early exit), so nothing upstream is cut off mid-write under pipefail.
  ver="$(curl -fsSL https://nodejs.org/dist/index.json | tr '{' '\n' \
    | awk '!found && /"version":"v/ && !/"lts":false/ { sub(/.*"version":"/, ""); sub(/".*/, ""); print; found = 1 }')"
  [ -n "$ver" ] || fail "Could not read the Node.js version list from nodejs.org." "check the internet connection, then paste the line again"
  tmp="$(mktemp -d)"
  curl -fsSL "https://nodejs.org/dist/$ver/node-$ver-$PLAT-$ARCH.tar.gz" -o "$tmp/node.tar.gz" \
    || fail "Could not download Node.js $ver." "check the internet connection, then paste the line again"
  rm -rf "$PMOS_HOME/node" && mkdir -p "$PMOS_HOME/node"
  tar -xzf "$tmp/node.tar.gz" -C "$PMOS_HOME/node" --strip-components=1 --no-same-owner
  rm -rf "$tmp"
  add_path "$PMOS_HOME/node/bin"
  hash -r
  ok "Node.js $(node -v) installed"
fi
# A system Node whose global folder needs sudo: point npm's global folder at one the user owns.
npm_prefix="$(npm prefix -g 2>/dev/null || true)"
if [ -n "$npm_prefix" ] && [ ! -w "$npm_prefix/lib" ] && [ ! -w "$npm_prefix" ]; then
  mkdir -p "$PMOS_HOME/npm-global"
  npm config set prefix "$PMOS_HOME/npm-global"
  add_path "$PMOS_HOME/npm-global/bin"
  ok "npm global folder set to $PMOS_HOME/npm-global (no sudo needed)"
fi
# npm's global folder is where `pmos` lands: put its bin folder on PATH, wherever npm is set up to keep it.
npm_prefix="$(npm prefix -g 2>/dev/null || true)"
[ -n "$npm_prefix" ] && [ -d "$npm_prefix" ] && add_path "$npm_prefix/bin"

# ── 2. git ────────────────────────────────────────────────────────────────────────────────────
say "Checking git"
if [ "$PLAT" = darwin ]; then
  if xcode-select -p >/dev/null 2>&1 && git --version >/dev/null 2>&1; then
    ok "$(git --version)"
  else
    say "Installing Apple's Command Line Tools (they include git)"
    echo "    A window opens. Click Install and wait for it to finish. This step can take a few minutes."
    xcode-select --install >/dev/null 2>&1 || true
    waited=0
    until xcode-select -p >/dev/null 2>&1; do
      sleep 5; waited=$((waited + 5))
      [ "$waited" -ge 3600 ] && fail "The Command Line Tools did not finish installing." "run: xcode-select --install, then paste the line again"
    done
    ok "$(git --version)"
  fi
else
  if have git; then
    ok "$(git --version)"
  else
    say "Installing git (your password may be asked)"
    if have apt-get; then sudo apt-get update -qq && sudo apt-get install -y -qq git
    elif have dnf; then sudo dnf install -y -q git
    elif have pacman; then sudo pacman -S --noconfirm git
    else fail "Could not install git automatically." "install git with your package manager, then paste the line again"; fi
    ok "$(git --version)"
  fi
  # On Linux the terminal component (node-pty) is built from source: it needs a compiler and Python.
  if ! have make || ! have g++ || ! have python3; then
    say "Installing build tools for the PMOS app (your password may be asked)"
    if have apt-get; then sudo apt-get install -y -qq build-essential python3
    elif have dnf; then sudo dnf install -y -q gcc-c++ make python3
    elif have pacman; then sudo pacman -S --noconfirm base-devel python
    else fail "Could not install build tools automatically." "install a C++ compiler, make and python3, then paste the line again"; fi
    ok "build tools installed"
  fi
fi

# ── 3. Claude Code ───────────────────────────────────────────────────────────────────────────
say "Checking Claude Code"
[ -x "$HOME/.local/bin/claude" ] && add_path "$HOME/.local/bin"
if [ "${PMOS_SKIP_CLAUDE:-}" = 1 ]; then
  ok "skipped (PMOS_SKIP_CLAUDE=1)"
elif have claude; then
  ok "Claude Code is installed"
else
  say "Installing Claude Code"
  curl -fsSL https://claude.ai/install.sh | bash \
    || fail "Could not install Claude Code." "run: curl -fsSL https://claude.ai/install.sh | bash, then paste the line again"
  add_path "$HOME/.local/bin"
  hash -r
  have claude && ok "Claude Code installed" || fail "Claude Code installed, but the claude command is not found." "open a new Terminal window and paste the line again"
fi

# ── 4. The PMOS release ─────────────────────────────────────────────────────────────────────
# For a few minutes after a release, npm can name it as the newest while its download servers do not
# have it yet ("No matching version found"). Ask for the newest release first and step back to the ones
# before it until one downloads, then use that same release for the kit and for the app.
if [ -z "$PMOS_PKG_GIVEN" ]; then
  say "Finding the newest PMOS release"
  older="$(npm view create-pmos versions --json 2>/dev/null \
    | node -e 'let s="";process.stdin.on("data",(d)=>{s+=d}).on("end",()=>{try{console.log([].concat(JSON.parse(s)).slice(-3).reverse().join(" "))}catch{}})' || true)"
  picked=""
  for v in latest $older; do
    out="$(npx -y -p "create-pmos@$v" create-pmos --version 2>/dev/null || true)"
    rel="$(printf '%s\n' "$out" | sed -n '/^create-pmos [0-9]/{s/^create-pmos //p;q;}')"
    if [ -n "$rel" ]; then picked="$rel"; break; fi
    echo "    create-pmos@$v does not download yet; trying the release before it"
  done
  [ -n "$picked" ] || fail "Could not download PMOS from npm." "check the internet connection, then paste the line again"
  PMOS_PKG="create-pmos@$picked"
  ok "PMOS $picked"
fi

# ── 5. The PMOS folder and kit ──────────────────────────────────────────────────────────────
say "Setting up the PMOS folder: $PMOS_DIR"
mkdir -p "$PMOS_DIR"
if [ ! -d "$PMOS_DIR/.git" ] && ! git -C "$PMOS_DIR" rev-parse --git-dir >/dev/null 2>&1; then
  git -C "$PMOS_DIR" init -q
  ok "git folder created"
fi
if [ -f "$PMOS_DIR/pmos/AGENTS.md" ]; then
  ok "the PMOS kit is already in this folder"
else
  npx -y -p "$PMOS_PKG" create-pmos "$PMOS_DIR" || fail "Could not add the PMOS kit." "paste the line again; if it fails again, send the text above to your PMOS contact"
  ok "PMOS kit added"
fi

# ── 6. The PMOS app ─────────────────────────────────────────────────────────────────────────
say "Starting the PMOS app"
npx -y -p "$PMOS_PKG" create-pmos workspace "$PMOS_DIR" || fail "The PMOS app did not start." "run: pmos doctor, and send what it prints to your PMOS contact"

echo
if [ "$PLAT" = darwin ]; then
  ok "PMOS is ready. Next time, open PMOS from Applications or Spotlight."
  echo "    The workspace starts when you log in. No Terminal command is needed."
else
  ok "PMOS is ready. Next time, open Terminal and type: pmos"
fi
echo "    New Terminal windows find node, claude and pmos by themselves."
