#!/usr/bin/env bash
# ─────────────────────────────────────────────────────────────────────────────
# Agent Recon — WSL Setup
# Run this script INSIDE WSL to wire the Agent Recon hooks into your WSL Claude.
#
#   bash setup-wsl.sh
#
# What it does:
#   1. Creates ~/.claude/hooks/
#   2. Copies (or updates) send-event.js there
#   3. Removes any legacy send-event*.py hook script
#   4. Writes (or merges) ~/.claude/settings.json with all 24 hook registrations
#   5. Tests connectivity to the Agent Recon server
# ─────────────────────────────────────────────────────────────────────────────
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
HOOK_SRC="$SCRIPT_DIR/.claude/hooks/send-event.js"
HOOK_DST="$HOME/.claude/hooks/send-event.js"
PROCMON_SRC="$SCRIPT_DIR/process-monitor-wsl.py"
PROCMON_DST="$HOME/.claude/hooks/process-monitor-wsl.py"
SETTINGS="$HOME/.claude/settings.json"
HOOK_CMD="node $HOOK_DST"

# ── Validate ─────────────────────────────────────────────────────────────────
if [[ ! -f "$HOOK_SRC" ]]; then
  echo "ERROR: Cannot find hook source at $HOOK_SRC"
  echo "  Run this script from the agent-recon project root directory"
  exit 1
fi

if ! command -v node &>/dev/null; then
  echo "ERROR: node not found in WSL. Install Node.js 22+:"
  echo "  Debian/Ubuntu: curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash - && sudo apt install -y nodejs"
  exit 1
fi

# ── Install / sync hook script ────────────────────────────────────────────────
mkdir -p "$HOME/.claude/hooks"

# Check if installed copy differs from repo source (drift detection)
if [[ -f "$HOOK_DST" ]]; then
  SRC_HASH=$(sha256sum "$HOOK_SRC" | cut -d' ' -f1)
  DST_HASH=$(sha256sum "$HOOK_DST" | cut -d' ' -f1)
  if [[ "$SRC_HASH" != "$DST_HASH" ]]; then
    echo "↻  Hook script updated — syncing to $HOOK_DST"
    cp "$HOOK_SRC" "$HOOK_DST"
    chmod +x "$HOOK_DST"
    echo "✓  Synced"
  else
    echo "✓  Hook script already up-to-date: $HOOK_DST"
  fi
else
  cp "$HOOK_SRC" "$HOOK_DST"
  chmod +x "$HOOK_DST"
  echo "✓  Installed hook forwarder → $HOOK_DST"
fi

# ── Remove legacy Python hook scripts (v1.0.x → v1.1.x migration) ────────────
for legacy in "$HOME/.claude/hooks/send-event.py" "$HOME/.claude/hooks/send-event-wsl.py"; do
  if [[ -f "$legacy" ]]; then
    rm -f "$legacy" && echo "✓  Removed legacy hook: $(basename "$legacy")"
  fi
done

# ── Install / sync process monitor daemon ────────────────────────────────────
if [[ -f "$PROCMON_SRC" ]]; then
  if [[ -f "$PROCMON_DST" ]]; then
    SRC_HASH=$(sha256sum "$PROCMON_SRC" | cut -d' ' -f1)
    DST_HASH=$(sha256sum "$PROCMON_DST" | cut -d' ' -f1)
    if [[ "$SRC_HASH" != "$DST_HASH" ]]; then
      echo "↻  Process monitor updated — syncing to $PROCMON_DST"
      cp "$PROCMON_SRC" "$PROCMON_DST"
      chmod +x "$PROCMON_DST"
    else
      echo "✓  Process monitor already up-to-date: $PROCMON_DST"
    fi
  else
    cp "$PROCMON_SRC" "$PROCMON_DST"
    chmod +x "$PROCMON_DST"
    echo "✓  Installed process monitor → $PROCMON_DST"
  fi
fi

# ── Test Agent Recon server connectivity ─────────────────────────────────────
echo ""
echo "── Connectivity check ──────────────────────────────────────────────────"

# Detect Windows host IP by parsing /proc/net/route (little-endian hex)
HOST_IP=$(node - <<'NODEEOF'
const fs = require('fs');
try {
  const raw = fs.readFileSync('/proc/net/route', 'utf8');
  const lines = raw.split('\n').slice(1);
  for (const line of lines) {
    const parts = line.trim().split(/\s+/);
    if (parts.length < 3) continue;
    if (parts[1] !== '00000000') continue;
    const gw = parts[2];
    if (!/^[0-9A-Fa-f]{8}$/.test(gw)) continue;
    const b4 = parseInt(gw.substring(0,2), 16);
    const b3 = parseInt(gw.substring(2,4), 16);
    const b2 = parseInt(gw.substring(4,6), 16);
    const b1 = parseInt(gw.substring(6,8), 16);
    const ip = `${b1}.${b2}.${b3}.${b4}`;
    if (ip !== '0.0.0.0') { console.log(ip); process.exit(0); }
  }
} catch {}
console.log('172.29.16.1');
NODEEOF
)

echo "  Detected Windows host IP : $HOST_IP"

REACHABLE_VIA=""

# Test 1: localhost (WSL2 localhost-forwarding — preferred method)
if curl -sf --max-time 2 "http://localhost:3131/health" > /dev/null 2>&1; then
  echo "  ✓ localhost:3131          REACHABLE  (WSL2 localhost-forwarding active)"
  REACHABLE_VIA="localhost"
else
  echo "  ✗ localhost:3131          not reachable"
fi

# Test 2: gateway IP (fallback for older WSL configs)
if curl -sf --max-time 2 "http://$HOST_IP:3131/health" > /dev/null 2>&1; then
  echo "  ✓ $HOST_IP:3131   REACHABLE  (gateway IP works)"
  [[ -z "$REACHABLE_VIA" ]] && REACHABLE_VIA="$HOST_IP"
else
  echo "  ✗ $HOST_IP:3131   not reachable"
fi

if [[ -z "$REACHABLE_VIA" ]]; then
  echo ""
  echo "  ⚠  Agent Recon server not reachable via any method."
  echo "     Start it on Windows first:"
  echo "       cd <agent-recon>\\server && node start.js"
  echo "     Then re-run this script to verify."
else
  echo ""
  echo "  ✓ Server reachable via: $REACHABLE_VIA"
  echo "  Hook forwarder will use localhost (preferred) with gateway fallback."
fi

# ── Write settings.json ───────────────────────────────────────────────────────
echo ""
echo "── Hook registration ───────────────────────────────────────────────────"

if [[ -f "$SETTINGS" ]]; then
  # Merge hooks into existing settings.json using Node so we don't clobber
  # other fields (e.g. skipDangerousModePermissionPrompt).
  node - "$SETTINGS" "$HOOK_CMD" <<'NODEEOF'
const fs = require('fs');
const settingsPath = process.argv[2];
const hookCmd      = process.argv[3];

let cfg = {};
try { cfg = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch {}
if (!cfg || typeof cfg !== 'object') cfg = {};
if (!cfg.hooks) cfg.hooks = {};
const hooks = cfg.hooks;

function hookEntry(matcher) {
  const entry = { type: 'command', command: hookCmd, async: true, timeout: 10 };
  return matcher ? { matcher: '', hooks: [entry] } : { hooks: [entry] };
}

// Keep in sync with installer/steps/hooks.js
const EVENTS_PLAIN = [
  'SessionStart','SessionEnd','UserPromptSubmit',
  'SubagentStart','SubagentStop','Stop','TeammateIdle','TaskCompleted',
  'StopFailure','PostCompact','InstructionsLoaded','ConfigChange',
  'CwdChanged','FileChanged',
  'TaskCreated','ElicitationResult',
];
const EVENTS_MATCHER = [
  'PreToolUse','PostToolUse','PostToolUseFailure','Notification','PreCompact',
  'PermissionRequest','Elicitation','PermissionDenied',
];

// Strip legacy Python hook registrations (preserve third-party hooks)
for (const ev of Object.keys(hooks)) {
  if (!Array.isArray(hooks[ev])) continue;
  hooks[ev] = hooks[ev].filter(group => {
    const hs = group.hooks || [];
    return !hs.some(h => h.command && /send-event(-wsl)?\.py/.test(h.command));
  });
  if (hooks[ev].length === 0) delete hooks[ev];
}

function alreadyRegistered(groups) {
  for (const g of (groups || [])) {
    for (const h of (g.hooks || [])) {
      if (h.command === hookCmd) return true;
    }
  }
  return false;
}

const added = [];
for (const ev of EVENTS_PLAIN) {
  if (!hooks[ev]) { hooks[ev] = [hookEntry(false)]; added.push(ev); }
  else if (!alreadyRegistered(hooks[ev])) { hooks[ev].push(hookEntry(false)); added.push(ev); }
}
for (const ev of EVENTS_MATCHER) {
  if (!hooks[ev]) { hooks[ev] = [hookEntry(true)]; added.push(ev); }
  else if (!alreadyRegistered(hooks[ev])) { hooks[ev].push(hookEntry(true)); added.push(ev); }
}

// Strip deprecated events — only remove AR hooks, preserve third-party hooks
const DEPRECATED = ['WorktreeCreate', 'WorktreeRemove'];
for (const ev of DEPRECATED) {
  if (!hooks[ev]) continue;
  hooks[ev] = hooks[ev].filter(g => !(g.hooks || []).some(h => h.command === hookCmd));
  if (hooks[ev].length === 0) delete hooks[ev];
}

fs.writeFileSync(settingsPath, JSON.stringify(cfg, null, 2) + '\n');

if (added.length) {
  console.log('✓  Merged hooks into', settingsPath);
  console.log('   Added:', added.join(', '));
} else {
  console.log('✓  All hooks already present in', settingsPath, '— nothing changed');
}
NODEEOF
else
  # Keep in sync with installer/steps/hooks.js
  cat > "$SETTINGS" <<SETTINGSEOF
{
  "hooks": {
    "SessionStart":        [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "SessionEnd":          [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "UserPromptSubmit":    [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PreToolUse":          [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PostToolUse":         [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PostToolUseFailure":  [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "SubagentStart":       [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "SubagentStop":        [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "Stop":                [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "Notification":        [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "TeammateIdle":        [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "TaskCompleted":       [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PreCompact":          [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "StopFailure":         [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PostCompact":         [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "InstructionsLoaded":  [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "ConfigChange":        [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "CwdChanged":          [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "FileChanged":         [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "TaskCreated":         [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "ElicitationResult":   [{"hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PermissionRequest":   [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "Elicitation":         [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}],
    "PermissionDenied":    [{"matcher": "","hooks": [{"type": "command","command": "$HOOK_CMD","async": true,"timeout": 10}]}]
  }
}
SETTINGSEOF
  # Validate JSON
  if ! node -e "JSON.parse(require('fs').readFileSync('$SETTINGS','utf8'))" > /dev/null 2>&1; then
    echo "⚠  Warning: generated settings.json may be malformed"
  fi
  echo "✓  Created $SETTINGS"
fi

echo ""
echo "────────────────────────────────────────────────────────────────────────"
echo "  WSL setup complete!"
echo ""
echo "  Hook script : $HOOK_DST"
echo "  Server URL  : http://localhost:3131 (via WSL2 localhost-forwarding)"
echo ""
echo "  Start server: cd $SCRIPT_DIR/server && node start.js"
echo "  (start.js auto-rebuilds the SQLite binary if you switched from Windows)"
echo ""
echo "  Start a Claude session in any WSL directory (including inside tmux)"
echo "  and events will stream to http://localhost:3131"
echo ""
echo "  Process monitor (tracks agent-spawned processes from inside WSL):"
echo "    # Use AGENT_RECON_URL if localhost forwarding is unavailable:"
echo "    AGENT_RECON_URL=http://$HOST_IP:3131 tmux new-window -n procmon 'AGENT_RECON_URL=http://$HOST_IP:3131 python3 $PROCMON_DST'"
echo "    # Or if localhost:3131 is reachable (WSL2 localhost-forwarding active):"
echo "    tmux new-window -n procmon 'python3 $PROCMON_DST'"
echo "    # Stop: kill \$(cat /tmp/agent-recon-procmon.pid)"
echo ""
echo "  Debug mode  : AGENT_RECON_DEBUG=1 claude  →  ~/.claude/agent-recon-debug.log"
echo "────────────────────────────────────────────────────────────────────────"
