#!/usr/bin/env bash
#
# PM33 Claude Code starter installer.
#
#   curl -fsSL https://pm-33.com/install | bash
#
# Installs the PM33 harness agents, harness/discipline/gauntlet skills,
# and the framework templates into your local Claude Code directories so
# any project on this machine picks them up.
#
# Locations written:
#   ~/.claude/agents/        — harness-coordinator, harness-planner
#   ~/.claude/skills/        — harness-*, gauntlet-review, feature-enhancements
#   ~/pm33-frameworks/       — HARNESS_PROJECT_TEMPLATE.md + framework docs
#
# Idempotent: re-running overwrites the PM33-managed files but leaves
# anything else under ~/.claude/ alone.
#
# Source: https://github.com/b33-steve/pm33-website-v3-1 →
#         scripts/install-bundle/ (bundle build script + content)
# Bundle: https://pm-33.com/install/pm33-bundle.tar.gz

set -euo pipefail

BUNDLE_URL="https://pm-33.com/install/pm33-bundle.tar.gz"
CLAUDE_DIR="${CLAUDE_DIR:-$HOME/.claude}"
FRAMEWORKS_DIR="${PM33_FRAMEWORKS_DIR:-$HOME/pm33-frameworks}"
STAGE_DIR="$(mktemp -d)"

# Cleanup the staging dir on exit regardless of outcome.
trap 'rm -rf "$STAGE_DIR"' EXIT

# --- pretty printing -------------------------------------------------------

bold() { printf '\033[1m%s\033[0m\n' "$*"; }
ok()   { printf '  \033[32m✓\033[0m %s\n' "$*"; }
note() { printf '  \033[2m· %s\033[0m\n' "$*"; }
warn() { printf '  \033[33m! %s\033[0m\n' "$*"; }
err()  { printf '  \033[31m✗ %s\033[0m\n' "$*" >&2; }

# --- preflight -------------------------------------------------------------

bold "PM33 → Claude Code starter installer"
echo

if ! command -v curl >/dev/null 2>&1; then
  err "curl not found. Install curl and re-run."
  exit 1
fi
if ! command -v tar >/dev/null 2>&1; then
  err "tar not found. Install tar and re-run."
  exit 1
fi

# --- download bundle -------------------------------------------------------

bold "1/4  Download bundle"
note "from $BUNDLE_URL"

if ! curl -fsSL --retry 3 --retry-delay 2 "$BUNDLE_URL" -o "$STAGE_DIR/pm33-bundle.tar.gz"; then
  err "Download failed."
  err "Check your connection or try later. If pm-33.com is reachable but the URL"
  err "returns 404, the bundle may be temporarily rebuilding — wait ~5 min and retry."
  exit 1
fi

ok "downloaded $(du -h "$STAGE_DIR/pm33-bundle.tar.gz" | awk '{print $1}')"

# --- extract ---------------------------------------------------------------

bold "2/4  Extract"
tar -xzf "$STAGE_DIR/pm33-bundle.tar.gz" -C "$STAGE_DIR"

if [ ! -d "$STAGE_DIR/pm33" ]; then
  err "Tarball didn't contain expected pm33/ layout. Aborting before touching ~/.claude/."
  exit 1
fi

ok "tarball layout verified"

# --- install agents + skills ----------------------------------------------

bold "3/4  Install agents + skills into $CLAUDE_DIR"

mkdir -p "$CLAUDE_DIR/agents" "$CLAUDE_DIR/skills"

# Agents (single files)
for src in "$STAGE_DIR/pm33/agents/"*.md; do
  [ -e "$src" ] || continue
  fname=$(basename "$src")
  cp "$src" "$CLAUDE_DIR/agents/$fname"
  ok "agents/$fname"
done

# Skills (directories — replace wholesale per skill so removed files are pruned)
for skill_dir in "$STAGE_DIR/pm33/skills/"*/; do
  [ -d "$skill_dir" ] || continue
  skill_name=$(basename "$skill_dir")
  dest="$CLAUDE_DIR/skills/$skill_name"
  rm -rf "$dest"
  cp -r "$skill_dir" "$dest"
  ok "skills/$skill_name/"
done

# --- install framework reference docs --------------------------------------

bold "4/5  Install framework reference docs into $FRAMEWORKS_DIR"

mkdir -p "$FRAMEWORKS_DIR"
for src in "$STAGE_DIR/pm33/frameworks/"*; do
  [ -e "$src" ] || continue
  fname=$(basename "$src")
  cp "$src" "$FRAMEWORKS_DIR/$fname"
  ok "$fname"
done

# Also drop the bundle README at the frameworks dir for easy first-read.
cp "$STAGE_DIR/pm33/README.md"  "$FRAMEWORKS_DIR/README.md"
cp "$STAGE_DIR/pm33/CLAUDE.md"  "$FRAMEWORKS_DIR/CLAUDE.md.starter"
ok "README.md (bundle docs)"
ok "CLAUDE.md.starter (copy into your project root + edit)"

# --- install Claude Code hooks --------------------------------------------

bold "5/5  Install Claude Code hooks into $CLAUDE_DIR/hooks"

HOOKS_DIR="$CLAUDE_DIR/hooks"
SETTINGS_FILE="$CLAUDE_DIR/settings.json"
BUNDLE_HOOKS="$STAGE_DIR/pm33/hooks"

# Copy hook scripts (+ tests). Only present in bundles built from
# pm-33-core PR #500 onwards. Older bundles skip this step silently.
if [ ! -d "$BUNDLE_HOOKS" ]; then
  note "Bundle has no hooks/ directory — skipping hook install"
  note "(Older bundle? Re-run \`curl -fsSL https://pm-33.com/install | bash\` to refresh.)"
else
  mkdir -p "$HOOKS_DIR/test"

  for hook in "$BUNDLE_HOOKS"/*.sh; do
    [ -e "$hook" ] || continue
    fname=$(basename "$hook")
    cp "$hook" "$HOOKS_DIR/$fname"
    chmod +x "$HOOKS_DIR/$fname"
    ok "hooks/$fname"
  done

  for t in "$BUNDLE_HOOKS"/test/*.sh; do
    [ -e "$t" ] || continue
    fname=$(basename "$t")
    cp "$t" "$HOOKS_DIR/test/$fname"
    chmod +x "$HOOKS_DIR/test/$fname"
  done
  ok "hooks/test/ (regression tests for the bundled hooks)"

  # --- merge settings.json fragment -----------------------------------

  FRAGMENT="$BUNDLE_HOOKS/settings-fragment.json"

  if [ ! -f "$FRAGMENT" ]; then
    note "No settings-fragment.json in bundle — skipping hook registration"
  elif ! command -v jq >/dev/null 2>&1; then
    warn "jq not installed — hooks copied but NOT registered in $SETTINGS_FILE"
    warn "Install jq (\`brew install jq\` / \`apt install jq\`) then re-run to register."
  else
    # Substitute @@PM33_HOOKS_DIR@@ → absolute path on this machine.
    # `|` instead of `/` in sed so the path's slashes don't conflict.
    RESOLVED_FRAGMENT=$(mktemp)
    sed "s|@@PM33_HOOKS_DIR@@|$HOOKS_DIR|g" "$FRAGMENT" > "$RESOLVED_FRAGMENT"

    # Read existing settings (default to empty object if missing).
    EXISTING=$(mktemp)
    if [ -f "$SETTINGS_FILE" ]; then
      cp "$SETTINGS_FILE" "$EXISTING"
    else
      echo '{}' > "$EXISTING"
    fi

    # Idempotent merge:
    #   1. STRIP any existing PM33-managed hook commands from
    #      PreToolUse + PostToolUse (identified by the script basename).
    #      Re-running the installer therefore REPLACES stale paths
    #      cleanly instead of accumulating duplicates.
    #   2. APPEND the fragment entries from the bundle.
    #
    # Preserves the user's OTHER hooks (different command paths)
    # untouched — only the two PM33 hooks are managed here.
    MERGED=$(mktemp)
    CLEANED=$(mktemp)
    PM33_HOOK_PATTERN='(pre-bash-branch-pin|post-edit-verify)\.sh$'

    jq --arg pat "$PM33_HOOK_PATTERN" '
      .hooks //= {} |
      .hooks.PreToolUse //= [] |
      .hooks.PostToolUse //= [] |

      def strip_pm33:
        map(
          .hooks //= [] |
          .hooks |= map(select(.command | test($pat) | not))
        ) | map(select((.hooks // []) | length > 0));

      .hooks.PreToolUse  |= strip_pm33 |
      .hooks.PostToolUse |= strip_pm33
    ' "$EXISTING" > "$CLEANED"

    jq -s '
      .[0] as $cleaned | .[1] as $fragment |
      $cleaned |
      .hooks //= {} |
      .hooks.PreToolUse  = ((.hooks.PreToolUse  // []) + ($fragment.hooks.PreToolUse  // [])) |
      .hooks.PostToolUse = ((.hooks.PostToolUse // []) + ($fragment.hooks.PostToolUse // []))
    ' "$CLEANED" "$RESOLVED_FRAGMENT" > "$MERGED"

    # Atomic replace — a Ctrl-C mid-write leaves the original intact.
    cp "$MERGED" "$SETTINGS_FILE.tmp"
    mv "$SETTINGS_FILE.tmp" "$SETTINGS_FILE"

    rm -f "$EXISTING" "$MERGED" "$CLEANED" "$RESOLVED_FRAGMENT"

    ok "settings.json registered (PreToolUse[Bash] + PostToolUse[Edit|Write])"
  fi
fi

# --- next steps ------------------------------------------------------------

echo
bold "Done."
echo
echo "  Read first:  $FRAMEWORKS_DIR/README.md"
echo "  Copy into your project root (and edit):"
echo "               $FRAMEWORKS_DIR/CLAUDE.md.starter → ./CLAUDE.md"
echo
echo "  Connect the PM33 MCP server:"
echo "    1. Restart Claude Code (so the new agents + skills load)"
echo "    2. Type  /mcp"
echo "    3. Pick  \"claude.ai PM33\"  and complete the OAuth flow"
echo
echo "  The branch-pin hook writes session state to .claude/session-state/"
echo "  in the project you're working in. If that project is a git repo,"
echo "  add this line to its .gitignore:"
echo "    .claude/session-state/"
echo
echo "  Re-run anytime to pull the latest bundle:"
echo "    curl -fsSL https://pm-33.com/install | bash"
echo
