#!/usr/bin/env bash
#
# claude-mem-lite SessionStart pre-hook
# Data directory setup, migrations, and dependency resolution
#

set -euo pipefail

if [[ -z "${CLAUDE_PLUGIN_ROOT:-}" ]]; then
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  ROOT="$(dirname "$SCRIPT_DIR")"
else
  ROOT="$CLAUDE_PLUGIN_ROOT"
fi

DATA_DIR="$HOME/.claude-mem-lite"
OLD_UNHIDDEN_DIR="$HOME/claude-mem-lite"

# Colors
if [[ -t 2 ]]; then
  GREEN='\033[0;32m'; YELLOW='\033[0;33m'; BLUE='\033[0;34m'; RED='\033[0;31m'; NC='\033[0m'
else
  GREEN='' YELLOW='' BLUE='' RED='' NC=''
fi

log_ok()   { echo -e "${GREEN}✓${NC} $*" >&2; }
log_info() { echo -e "${BLUE}ℹ${NC} $*" >&2; }
log_warn() { echo -e "${YELLOW}⚠${NC} $*" >&2; }
# shellcheck disable=SC2317  # kept for API symmetry with log_ok/log_info/log_warn
log_err()  { echo -e "${RED}✗${NC} $*" >&2; }

# 1. Migrate unhidden dir (~/claude-mem-lite/ → ~/.claude-mem-lite/)
if [[ -d "$OLD_UNHIDDEN_DIR" && ! -d "$DATA_DIR" ]]; then
  mv "$OLD_UNHIDDEN_DIR" "$DATA_DIR"
  log_ok "Migrated ~/claude-mem-lite/ → ~/.claude-mem-lite/"
fi

# 2. Ensure data directory exists (runtime created after migration check)
mkdir -p "$DATA_DIR"
log_ok "Data directory: $DATA_DIR"

# 3. Migrate from old ~/.claude-mem/ if needed
OLD_DIR="$HOME/.claude-mem"
if [[ -f "$OLD_DIR/claude-mem.db" && ! -f "$DATA_DIR/claude-mem-lite.db" && ! -f "$DATA_DIR/claude-mem.db" ]]; then
  log_info "Migrating data from ~/.claude-mem/ → ~/.claude-mem-lite/..."
  if cp "$OLD_DIR/claude-mem.db" "$DATA_DIR/claude-mem-lite.db" 2>/dev/null; then
    # Main DB copied successfully, WAL/SHM are optional
    cp "$OLD_DIR/claude-mem.db-wal" "$DATA_DIR/claude-mem-lite.db-wal" 2>/dev/null || true
    cp "$OLD_DIR/claude-mem.db-shm" "$DATA_DIR/claude-mem-lite.db-shm" 2>/dev/null || true
    if [[ -d "$OLD_DIR/runtime" && ! -d "$DATA_DIR/runtime" ]]; then
      cp -r "$OLD_DIR/runtime" "$DATA_DIR/runtime" 2>/dev/null || true
    fi
    log_ok "Data migrated (old ~/.claude-mem/ preserved)"
  else
    log_warn "Migration failed — using fresh database"
  fi
fi

# 4. Rename claude-mem.db → claude-mem-lite.db in same directory
if [[ -f "$DATA_DIR/claude-mem.db" && ! -f "$DATA_DIR/claude-mem-lite.db" ]]; then
  mv "$DATA_DIR/claude-mem.db" "$DATA_DIR/claude-mem-lite.db"
  mv "$DATA_DIR/claude-mem.db-wal" "$DATA_DIR/claude-mem-lite.db-wal" 2>/dev/null || true
  mv "$DATA_DIR/claude-mem.db-shm" "$DATA_DIR/claude-mem-lite.db-shm" 2>/dev/null || true
  log_ok "Database renamed: claude-mem.db → claude-mem-lite.db"
fi

# 5. Ensure runtime directory exists (after migration to not mask migration check)
mkdir -p "$DATA_DIR/runtime"

# 6. Ensure native dependencies available for hooks (ESM import needs node_modules in resolution chain)
#    Plugin cache doesn't include node_modules — symlink from data dir or npm install on first run
if [[ ! -d "$ROOT/node_modules/better-sqlite3" ]]; then
  # Fast path: symlink from data dir (instant, no network needed)
  if [[ -d "$DATA_DIR/node_modules/better-sqlite3" ]]; then
    if ln -sfn "$DATA_DIR/node_modules" "$ROOT/node_modules" 2>/dev/null; then
      log_ok "Dependencies linked from $DATA_DIR"
    fi
  fi
  # Slow path: npm install (first-time only, ~10-20s for native addon)
  if [[ ! -d "$ROOT/node_modules/better-sqlite3" ]]; then
    log_info "Installing dependencies (first-time setup)..."
    if (cd "$ROOT" && npm install --omit=dev --no-audit --no-fund 2>&1) >&2; then
      log_ok "Dependencies installed"
    else
      log_warn "Dependency install failed — hooks may have limited functionality"
    fi
  fi
fi

# 7. MCP cleanup: idempotently clean stale registrations from pre-2.10 direct installs.
#    This runs on every plugin SessionStart because old global mem entries may still
#    exist even after an earlier migration marker was written.
#    Before 2.10: old direct installs left a global mem MCP alongside plugin MCP.
#    - Global mcpServers.mem in ~/.claude.json (from old install.mjs)
#    - Possibly stale marketplace root .mcp.json (from old git clone)
#    Root .mcp.json in the installed plugin cache is required for Claude Code to
#    register plugin MCP; only stale global/marketplace copies should be removed.
MCP_MIGRATION="$DATA_DIR/runtime/.mcp-dedup-v2.10.4"
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]]; then
  CLAUDE_JSON="$HOME/.claude.json" node -e '
    const fs = require("fs");
    let changed = false;
    // Remove stale global MCP registration (plugin .mcp.json handles it)
    try {
      const p = process.env.CLAUDE_JSON;
      const d = JSON.parse(fs.readFileSync(p, "utf8"));
      if (d.mcpServers?.mem) {
        delete d.mcpServers.mem;
        fs.writeFileSync(p, JSON.stringify(d, null, 2) + "\n");
        process.stderr.write("✓ Removed stale global MCP \"mem\" (plugin handles it)\n");
        changed = true;
      }
    } catch {}
    // NOTE: Do NOT touch marketplace .mcp.json — Claude Code copies it from
    // marketplace → plugin cache on updates. Clearing it causes the cache
    // .mcp.json to lose the MCP server definition, breaking plugin MCP.
    if (!changed) process.stderr.write("✓ MCP migration: already clean\n");
  ' || true
  touch "$MCP_MIGRATION"
fi

# 8. Prune old plugin cache versions (keep latest 3)
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" ]]; then
  CACHE_DIR="$HOME/.claude/plugins/cache/sdsrss/claude-mem-lite"
  if [[ -d "$CACHE_DIR" ]]; then
    # List version dirs sorted by semver descending, skip top 3
    # Use glob + while-read for bash 3.2 (macOS) compatibility (no mapfile, no `ls | grep`)
    OLD_VERS=()
    shopt -s nullglob
    _all_dirs=("$CACHE_DIR"/[0-9]*)
    shopt -u nullglob
    while IFS= read -r ver; do
      [[ -n "$ver" ]] && OLD_VERS+=("$ver")
    done < <(for _d in "${_all_dirs[@]}"; do [[ -d "$_d" ]] && echo "${_d##*/}"; done | sort -t. -k1,1nr -k2,2nr -k3,3nr | tail -n +4)
    unset _all_dirs _d
    if [[ ${#OLD_VERS[@]} -gt 0 ]]; then
      for ver in "${OLD_VERS[@]}"; do
        rm -rf "${CACHE_DIR:?}/$ver" 2>/dev/null || true
      done
      log_ok "Plugin cache pruned: removed ${#OLD_VERS[@]} old version(s)"
    fi
  fi
fi

# 9. Residue detection (plugin mode only): warn once if legacy direct-install
#    hooks remain in ~/.claude/settings.json. A user who installed via global
#    `claude-mem-lite install` and later switched to the marketplace plugin
#    will run every hook twice (direct settings.json hooks AND plugin hooks)
#    until they run `claude-mem-lite uninstall` to clear the settings.json
#    entries. /plugin uninstall does not touch settings.json.
RESIDUE_MARKER="$DATA_DIR/runtime/.residue-warned-v2.55"
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && ! -f "$RESIDUE_MARKER" ]]; then
  SETTINGS="$HOME/.claude/settings.json"
  if [[ -f "$SETTINGS" ]]; then
    SETTINGS_PATH="$SETTINGS" node -e '
      const fs = require("fs");
      try {
        const raw = fs.readFileSync(process.env.SETTINGS_PATH, "utf8");
        const data = JSON.parse(raw);
        const hooks = data.hooks || {};
        const events = Object.keys(hooks);
        const found = [];
        for (const ev of events) {
          const list = Array.isArray(hooks[ev]) ? hooks[ev] : [];
          for (const entry of list) {
            const inner = Array.isArray(entry?.hooks) ? entry.hooks : [];
            for (const h of inner) {
              const cmd = String(h?.command || "");
              if (cmd.includes(".claude-mem-lite/") || cmd.includes("claude-mem-lite/scripts") || cmd.includes("claude-mem-lite/hook.mjs")) {
                found.push(ev);
                break;
              }
            }
          }
        }
        if (found.length) {
          process.stderr.write("\n");
          process.stderr.write("\x1b[33m⚠\x1b[0m Legacy direct-install hooks detected in " + process.env.SETTINGS_PATH + "\n");
          process.stderr.write("  Events with stale entries: " + [...new Set(found)].join(", ") + "\n");
          process.stderr.write("  These will fire alongside plugin hooks (each tool call runs twice).\n");
          process.stderr.write("  Fix: run \x1b[1mclaude-mem-lite uninstall\x1b[0m to clear settings.json,\n");
          process.stderr.write("       then keep using the plugin install. (One-time warning.)\n\n");
          process.exit(2);
        }
      } catch {}
    ' || true
  fi
  # Mark the warning as shown regardless of result — silence is fine if no
  # residue, and the warning above is one-shot per data-dir.
  touch "$RESIDUE_MARKER"
fi

log_ok "claude-mem-lite ready"
exit 0
