#!/usr/bin/env bash
# gstack-uninstall — remove gstack skills, state, and browse daemons
#
# Usage:
#   gstack-uninstall              — interactive uninstall (prompts before removing)
#   gstack-uninstall --force      — remove everything without prompting
#   gstack-uninstall --keep-state — remove skills but keep ~/.gstack/ data
#
# What gets REMOVED:
#   ~/.claude/skills/gstack       — global Claude skill install (git clone or vendored)
#   ~/.claude/skills/{skill}      — per-skill symlinks created by setup
#   ~/.codex/skills/gstack*       — Codex skill install + per-skill symlinks
#   ~/.factory/skills/gstack*     — Factory Droid skill install + per-skill symlinks
#   ~/.kiro/skills/gstack*        — Kiro skill install + per-skill symlinks
#   ~/.gstack/                    — global state (config, analytics, sessions, projects,
#                                   repos, installation-id, browse error logs)
#   .claude/skills/gstack*        — project-local skill install (--local installs)
#   .gstack/                      — per-project browse state (in current git repo)
#   .gstack-worktrees/            — per-project test worktrees (in current git repo)
#   .agents/skills/gstack*        — Codex/Gemini/Cursor sidecar (in current git repo)
#   Running browse daemons        — stopped via SIGTERM before cleanup
#
# What is NOT REMOVED:
#   ~/Library/Caches/ms-playwright/  — Playwright Chromium (shared, may be used by other tools)
#   ~/.gstack-dev/                   — developer eval artifacts (only present in gstack contributors)
#
# Env overrides (for testing):
#   GSTACK_DIR        — override auto-detected gstack root
#   GSTACK_STATE_DIR  — override ~/.gstack state directory
#
# NOTE: Uses set -uo pipefail (no -e) — uninstall must never abort partway.
set -uo pipefail

if [ -z "${HOME:-}" ]; then
  echo "ERROR: \$HOME is not set" >&2
  exit 1
fi

GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
STATE_DIR="${GSTACK_STATE_DIR:-$HOME/.gstack}"
_GIT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"

# ─── Parse flags ─────────────────────────────────────────────
FORCE=0
KEEP_STATE=0
while [ $# -gt 0 ]; do
  case "$1" in
    --force) FORCE=1; shift ;;
    --keep-state) KEEP_STATE=1; shift ;;
    -h|--help)
      sed -n '2,/^[^#]/{ /^#/s/^# \{0,1\}//p; }' "$0"
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      echo "Usage: gstack-uninstall [--force] [--keep-state]" >&2
      exit 1
      ;;
  esac
done

# ─── Confirmation ────────────────────────────────────────────
if [ "$FORCE" -eq 0 ]; then
  echo "This will remove gstack from your system:"
  { [ -d "$HOME/.claude/skills/gstack" ] || [ -L "$HOME/.claude/skills/gstack" ]; } && echo "  ~/.claude/skills/gstack (+ per-skill symlinks)"
  [ -d "$HOME/.codex/skills" ] && echo "  ~/.codex/skills/gstack*"
  [ -d "$HOME/.factory/skills" ] && echo "  ~/.factory/skills/gstack*"
  [ -d "$HOME/.kiro/skills" ] && echo "  ~/.kiro/skills/gstack*"
  [ "$KEEP_STATE" -eq 0 ] && [ -d "$STATE_DIR" ] && echo "  $STATE_DIR"

  if [ -n "$_GIT_ROOT" ]; then
    [ -d "$_GIT_ROOT/.claude/skills/gstack" ] && echo "  $_GIT_ROOT/.claude/skills/gstack (project-local)"
    [ -d "$_GIT_ROOT/.gstack" ] && echo "  $_GIT_ROOT/.gstack/ (browse state + reports)"
    [ -d "$_GIT_ROOT/.gstack-worktrees" ] && echo "  $_GIT_ROOT/.gstack-worktrees/"
    [ -d "$_GIT_ROOT/.agents/skills" ] && echo "  $_GIT_ROOT/.agents/skills/gstack*"
  fi

  # Preview running daemons
  if [ -n "$_GIT_ROOT" ] && [ -f "$_GIT_ROOT/.gstack/browse.json" ]; then
    _PREVIEW_PID="$(awk -F'[:,]' '/"pid"/ { for(i=1;i<=NF;i++) if($i ~ /"pid"/) { gsub(/[^0-9]/, "", $(i+1)); print $(i+1); exit } }' "$_GIT_ROOT/.gstack/browse.json" 2>/dev/null || true)"
    [ -n "$_PREVIEW_PID" ] && kill -0 "$_PREVIEW_PID" 2>/dev/null && echo "  browse daemon (PID $_PREVIEW_PID) will be stopped"
  fi

  printf "\nContinue? [y/N] "
  read -r REPLY
  case "$REPLY" in
    y|Y|yes|YES) ;;
    *) echo "Aborted."; exit 0 ;;
  esac
fi

REMOVED=()

# ─── Stop running browse daemons ─────────────────────────────
# Browse servers write PID to {project}/.gstack/browse.json.
# Stop any we can find before removing state directories.
stop_browse_daemon() {
  local state_file="$1"
  if [ ! -f "$state_file" ]; then
    return
  fi
  local pid
  pid="$(awk -F'[:,]' '/"pid"/ { for(i=1;i<=NF;i++) if($i ~ /"pid"/) { gsub(/[^0-9]/, "", $(i+1)); print $(i+1); exit } }' "$state_file" 2>/dev/null || true)"
  if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
    kill "$pid" 2>/dev/null || true
    # Wait up to 2s for graceful shutdown
    local waited=0
    while [ "$waited" -lt 4 ] && kill -0 "$pid" 2>/dev/null; do
      sleep 0.5
      waited=$(( waited + 1 ))
    done
    if kill -0 "$pid" 2>/dev/null; then
      kill -9 "$pid" 2>/dev/null || true
    fi
    REMOVED+=("browse daemon (PID $pid)")
  fi
}

# Stop daemon in current project
if [ -n "$_GIT_ROOT" ] && [ -f "$_GIT_ROOT/.gstack/browse.json" ]; then
  stop_browse_daemon "$_GIT_ROOT/.gstack/browse.json"
fi

# Stop daemons tracked in global projects directory
if [ -d "$STATE_DIR/projects" ]; then
  while IFS= read -r _BJ; do
    stop_browse_daemon "$_BJ"
  done < <(find "$STATE_DIR/projects" -name browse.json -path '*/.gstack/*' 2>/dev/null || true)
fi

# ─── Remove global Claude skills ────────────────────────────
CLAUDE_SKILLS="$HOME/.claude/skills"
if [ -d "$CLAUDE_SKILLS/gstack" ] || [ -L "$CLAUDE_SKILLS/gstack" ]; then
  # Remove per-skill symlinks that point into gstack/
  for _LINK in "$CLAUDE_SKILLS"/*; do
    [ -L "$_LINK" ] || continue
    _NAME="$(basename "$_LINK")"
    [ "$_NAME" = "gstack" ] && continue
    _TARGET="$(readlink "$_LINK" 2>/dev/null || true)"
    case "$_TARGET" in
      gstack/*|*/gstack/*) rm -f "$_LINK"; REMOVED+=("claude/$_NAME") ;;
    esac
  done

  rm -rf "$CLAUDE_SKILLS/gstack"
  REMOVED+=("~/.claude/skills/gstack")
fi

# ─── Remove project-local Claude skills (--local installs) ──
if [ -n "$_GIT_ROOT" ] && [ -d "$_GIT_ROOT/.claude/skills" ]; then
  for _LINK in "$_GIT_ROOT/.claude/skills"/*; do
    [ -L "$_LINK" ] || continue
    _TARGET="$(readlink "$_LINK" 2>/dev/null || true)"
    case "$_TARGET" in
      gstack/*|*/gstack/*) rm -f "$_LINK"; REMOVED+=("local claude/$(basename "$_LINK")") ;;
    esac
  done
  if [ -d "$_GIT_ROOT/.claude/skills/gstack" ] || [ -L "$_GIT_ROOT/.claude/skills/gstack" ]; then
    rm -rf "$_GIT_ROOT/.claude/skills/gstack"
    REMOVED+=("$_GIT_ROOT/.claude/skills/gstack")
  fi
fi

# ─── Remove Codex skills ────────────────────────────────────
CODEX_SKILLS="$HOME/.codex/skills"
if [ -d "$CODEX_SKILLS" ]; then
  for _ITEM in "$CODEX_SKILLS"/gstack*; do
    [ -e "$_ITEM" ] || [ -L "$_ITEM" ] || continue
    rm -rf "$_ITEM"
    REMOVED+=("codex/$(basename "$_ITEM")")
  done
fi

# ─── Remove Factory Droid skills ────────────────────────────
FACTORY_SKILLS="$HOME/.factory/skills"
if [ -d "$FACTORY_SKILLS" ]; then
  for _ITEM in "$FACTORY_SKILLS"/gstack*; do
    [ -e "$_ITEM" ] || [ -L "$_ITEM" ] || continue
    rm -rf "$_ITEM"
    REMOVED+=("factory/$(basename "$_ITEM")")
  done
fi

# ─── Remove Kiro skills ─────────────────────────────────────
KIRO_SKILLS="$HOME/.kiro/skills"
if [ -d "$KIRO_SKILLS" ]; then
  for _ITEM in "$KIRO_SKILLS"/gstack*; do
    [ -e "$_ITEM" ] || [ -L "$_ITEM" ] || continue
    rm -rf "$_ITEM"
    REMOVED+=("kiro/$(basename "$_ITEM")")
  done
fi

# ─── Remove per-project .agents/ sidecar ─────────────────────
if [ -n "$_GIT_ROOT" ] && [ -d "$_GIT_ROOT/.agents/skills" ]; then
  for _ITEM in "$_GIT_ROOT/.agents/skills"/gstack*; do
    [ -e "$_ITEM" ] || [ -L "$_ITEM" ] || continue
    rm -rf "$_ITEM"
    REMOVED+=("agents/$(basename "$_ITEM")")
  done

  rmdir "$_GIT_ROOT/.agents/skills" 2>/dev/null || true
  rmdir "$_GIT_ROOT/.agents" 2>/dev/null || true
fi

# ─── Remove per-project .factory/ sidecar ────────────────────
if [ -n "$_GIT_ROOT" ] && [ -d "$_GIT_ROOT/.factory/skills" ]; then
  for _ITEM in "$_GIT_ROOT/.factory/skills"/gstack*; do
    [ -e "$_ITEM" ] || [ -L "$_ITEM" ] || continue
    rm -rf "$_ITEM"
    REMOVED+=("factory/$(basename "$_ITEM")")
  done

  rmdir "$_GIT_ROOT/.factory/skills" 2>/dev/null || true
  rmdir "$_GIT_ROOT/.factory" 2>/dev/null || true
fi

# ─── Remove per-project state ───────────────────────────────
if [ -n "$_GIT_ROOT" ]; then
  if [ -d "$_GIT_ROOT/.gstack" ]; then
    rm -rf "$_GIT_ROOT/.gstack"
    REMOVED+=("$_GIT_ROOT/.gstack/")
  fi
  if [ -d "$_GIT_ROOT/.gstack-worktrees" ]; then
    rm -rf "$_GIT_ROOT/.gstack-worktrees"
    REMOVED+=("$_GIT_ROOT/.gstack-worktrees/")
  fi
fi

# ─── Remove SessionStart hook from Claude Code settings ─────
SETTINGS_HOOK="$(dirname "$0")/gstack-settings-hook"
SESSION_UPDATE="$(dirname "$0")/gstack-session-update"
if [ -x "$SETTINGS_HOOK" ]; then
  "$SETTINGS_HOOK" remove "$SESSION_UPDATE" 2>/dev/null && REMOVED+=("SessionStart hook") || true
  # Cathedral T8 cleanup: also remove plan-tune PreToolUse + PostToolUse hooks.
  if "$SETTINGS_HOOK" remove-source --source plan-tune-cathedral 2>/dev/null | grep -q "removed [1-9]"; then
    REMOVED+=("plan-tune cathedral hooks")
  fi
fi

# ─── Remove global state ────────────────────────────────────
if [ "$KEEP_STATE" -eq 0 ] && [ -d "$STATE_DIR" ]; then
  rm -rf "$STATE_DIR"
  REMOVED+=("$STATE_DIR")
fi

# ─── Clean up temp files ────────────────────────────────────
for _TMP in /tmp/gstack-latest-version /tmp/gstack-sketch-*.html /tmp/gstack-sketch.png /tmp/gstack-sync-*; do
  if [ -e "$_TMP" ]; then
    rm -f "$_TMP"
    REMOVED+=("$(basename "$_TMP")")
  fi
done

# ─── Summary ────────────────────────────────────────────────
if [ ${#REMOVED[@]} -gt 0 ]; then
  echo "Removed: ${REMOVED[*]}"
  echo "gstack uninstalled."
else
  echo "Nothing to remove — gstack is not installed."
fi

exit 0
