#!/usr/bin/env bash
# ClaudeAll Smart Hooks Dispatcher (v3.6)
# Single entry point for all hook types. Reads JSON event from stdin, dispatches
# to the right handler based on $1 (hook type), and emits JSON back on stdout.
#
# Usage in hooks.json:
#   "command": "bash $HOME/.claude/hooks/smart-hooks.sh <hook-type>"
#
# Hook types:
#   intent-classifier      (UserPromptSubmit)
#   secret-scanner         (PreToolUse)
#   blast-radius-warner    (PreToolUse)
#   auto-test-runner       (PostToolUse)
#   auto-format            (PostToolUse)
#   commit-suggester       (Stop)
#   lessons-extractor      (Stop)
#   result-summarizer      (SubagentStop)

set -u

HOOK_TYPE="${1:-unknown}"
INPUT="$(cat)"

# Helper: print JSON output to stdout
emit() { printf '%s\n' "$1"; }

# Helper: extract a field from input JSON (jq if available, fallback to grep)
get_field() {
  local field="$1"
  if command -v jq &>/dev/null; then
    printf '%s' "$INPUT" | jq -r "$field // empty" 2>/dev/null
  else
    printf '%s' "$INPUT" | grep -oE "\"${field#.}\"\\s*:\\s*\"[^\"]*\"" | head -1 | sed 's/.*: *"\(.*\)".*/\1/'
  fi
}

# ────────────────────────────────────────────────────────────────────────────
# 1. intent-classifier (UserPromptSubmit)
# Reads the user prompt; if it matches known intents, suggests the right agent.
# ────────────────────────────────────────────────────────────────────────────
hook_intent_classifier() {
  local prompt
  prompt=$(get_field '.prompt' | tr '[:upper:]' '[:lower:]')
  [ -z "$prompt" ] && { emit '{}'; return; }

  local hint=""
  case "$prompt" in
    *"debug"*|*"bug"*|*"trace"*|*"why is "*|*"crash"*|*"fail"*)
      hint="Consider dispatching the **debugger** agent for systematic root-cause investigation." ;;
    *"design"*|*"architect"*|*"choose between"*|*"which framework"*|*"scaling"*|*"adr"*)
      hint="Consider dispatching the **architect** agent for system design + ADR." ;;
    *"down"*|*"outage"*|*"production"*|*"incident"*|*"on fire"*|*"sev"*)
      hint="Consider dispatching the **incident-commander** agent immediately." ;;
    *"slow query"*|*"n+1"*|*"index"*|*"explain analyze"*|*"schema"*|*"migration"*)
      hint="Consider dispatching the **db-doctor** agent." ;;
    *"refactor"*|*"tech debt"*|*"cleanup"*|*"smell"*)
      hint="Consider dispatching the **refactor-master** agent." ;;
    *"release"*|*"publish"*|*"changelog"*|*"version bump"*|*"tag"*)
      hint="Consider dispatching the **release-manager** agent." ;;
    *"cost"*|*"bill"*|*"aws spend"*|*"gcp spend"*|*"expensive"*)
      hint="Consider dispatching the **cost-watchdog** agent." ;;
  esac

  if [ -n "$hint" ]; then
    emit "{\"systemMessage\": \"💡 ${hint}\"}"
  else
    emit '{}'
  fi
}

# ────────────────────────────────────────────────────────────────────────────
# 2. secret-scanner (PreToolUse)
# Block tool calls that would commit/echo a likely secret.
# ────────────────────────────────────────────────────────────────────────────
hook_secret_scanner() {
  local tool_input
  tool_input=$(printf '%s' "$INPUT" | (command -v jq &>/dev/null && jq -c '.tool_input // {}' || cat))
  local payload="${tool_input}"

  # Patterns for common secret formats
  local patterns=(
    'gh[pousr]_[A-Za-z0-9]{30,}'                              # GitHub PAT
    'npm_[A-Za-z0-9]{30,}'                                     # npm token
    'sk-[a-zA-Z0-9]{32,}'                                      # OpenAI / Anthropic-style
    'AKIA[0-9A-Z]{16}'                                         # AWS access key
    'AIza[0-9A-Za-z_-]{35}'                                    # Google API key
    'xox[baprs]-[A-Za-z0-9-]{10,}'                             # Slack token
    '-----BEGIN (RSA |OPENSSH )?PRIVATE KEY-----'              # private key block
    'eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+'    # JWT
  )

  for pat in "${patterns[@]}"; do
    if printf '%s' "$payload" | grep -qE -- "$pat"; then
      emit '{"decision": "block", "reason": "🔒 secret-scanner blocked: tool input matches a known secret pattern. Reference the secret via env var (e.g., $TOKEN), or use ~/.claude/.env."}'
      return
    fi
  done

  emit '{}'
}

# ────────────────────────────────────────────────────────────────────────────
# 3. blast-radius-warner (PreToolUse, Bash tool)
# Warn loudly on dangerous shell commands.
# ────────────────────────────────────────────────────────────────────────────
hook_blast_radius_warner() {
  local tool_name
  tool_name=$(get_field '.tool_name')
  [ "$tool_name" != "Bash" ] && { emit '{}'; return; }

  local cmd
  if command -v jq &>/dev/null; then
    cmd=$(printf '%s' "$INPUT" | jq -r '.tool_input.command // ""')
  else
    cmd=$(get_field '.command')
  fi

  # Dangerous patterns (case-sensitive enough)
  local dangerous=(
    'rm -rf /'
    'rm -rf \$HOME'
    'rm -rf ~'
    'rm -rf \*'
    'mkfs\.'
    'dd if=.*of=/dev/'
    ':\(\)\{ :|:& \};:'                # fork bomb
    'chmod -R 777 /'
    'chown -R .* /'
    'DROP DATABASE'
    'DROP TABLE'
    'TRUNCATE TABLE'
    'git push.*--force'
    'git push.*-f'
    'git reset --hard'
    'git clean -fd[xX]?'
    'kubectl delete ns'
    'aws s3 rb .* --force'
    'terraform destroy'
  )

  for pat in "${dangerous[@]}"; do
    if printf '%s' "$cmd" | grep -qE "$pat"; then
      emit "{\"systemMessage\": \"⚠️ blast-radius-warner: command matched destructive pattern '${pat}'. Confirm intent + ensure backup before proceeding.\"}"
      return
    fi
  done

  emit '{}'
}

# ────────────────────────────────────────────────────────────────────────────
# 4. auto-test-runner (PostToolUse, Edit/Write/MultiEdit on src files)
# Trigger appropriate test command for the language.
# ────────────────────────────────────────────────────────────────────────────
hook_auto_test_runner() {
  local tool_name
  tool_name=$(get_field '.tool_name')
  case "$tool_name" in
    Edit|Write|MultiEdit) ;;
    *) emit '{}'; return ;;
  esac

  local file
  if command -v jq &>/dev/null; then
    file=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
  else
    file=$(get_field '.file_path')
  fi
  [ -z "$file" ] && { emit '{}'; return; }

  local hint=""
  case "$file" in
    *.js|*.jsx|*.ts|*.tsx)
      [ -f package.json ] && grep -q '"test"' package.json && hint="Run: npm test  (file: $file)" ;;
    *.py)
      [ -f pytest.ini ] || [ -f pyproject.toml ] && hint="Run: pytest  (file: $file)" ;;
    *.go)
      hint="Run: go test ./...  (file: $file)" ;;
    *.rs)
      [ -f Cargo.toml ] && hint="Run: cargo test  (file: $file)" ;;
    *.rb)
      [ -f Gemfile ] && hint="Run: bundle exec rspec  (file: $file)" ;;
  esac

  [ -n "$hint" ] && emit "{\"systemMessage\": \"🧪 auto-test-runner suggests: ${hint}\"}" || emit '{}'
}

# ────────────────────────────────────────────────────────────────────────────
# 5. auto-format (PostToolUse, Edit/Write/MultiEdit)
# Suggest the right formatter for the file type.
# ────────────────────────────────────────────────────────────────────────────
hook_auto_format() {
  local tool_name
  tool_name=$(get_field '.tool_name')
  case "$tool_name" in
    Edit|Write|MultiEdit) ;;
    *) emit '{}'; return ;;
  esac

  local file
  if command -v jq &>/dev/null; then
    file=$(printf '%s' "$INPUT" | jq -r '.tool_input.file_path // .tool_input.path // ""')
  else
    file=$(get_field '.file_path')
  fi
  [ -z "$file" ] && { emit '{}'; return; }

  local fmt=""
  case "$file" in
    *.js|*.jsx|*.ts|*.tsx|*.json|*.css|*.scss|*.html|*.md)
      command -v prettier &>/dev/null && fmt="prettier --write \"$file\"" ;;
    *.py)
      command -v black &>/dev/null && fmt="black \"$file\""
      command -v ruff &>/dev/null && fmt="ruff format \"$file\"" ;;
    *.go)
      fmt="gofmt -w \"$file\"" ;;
    *.rs)
      command -v rustfmt &>/dev/null && fmt="rustfmt \"$file\"" ;;
    *.sh)
      command -v shfmt &>/dev/null && fmt="shfmt -w \"$file\"" ;;
  esac

  [ -n "$fmt" ] && emit "{\"systemMessage\": \"✨ auto-format ready: ${fmt}\"}" || emit '{}'
}

# ────────────────────────────────────────────────────────────────────────────
# 6. commit-suggester (Stop)
# If repo has uncommitted changes, suggest a conventional-commit message.
# ────────────────────────────────────────────────────────────────────────────
hook_commit_suggester() {
  command -v git &>/dev/null || { emit '{}'; return; }
  git rev-parse --is-inside-work-tree &>/dev/null || { emit '{}'; return; }

  local changes
  changes=$(git status --porcelain 2>/dev/null | wc -l)
  [ "$changes" -eq 0 ] && { emit '{}'; return; }

  local files
  files=$(git status --porcelain 2>/dev/null | head -3 | awk '{print $2}' | tr '\n' ' ')

  emit "{\"systemMessage\": \"📝 commit-suggester: ${changes} uncommitted file(s) (${files}...). Consider: git add -A && git commit -m 'chore: <describe>'\"}"
}

# ────────────────────────────────────────────────────────────────────────────
# 7. lessons-extractor (Stop)
# Suggest invoking learning-loop agent to persist session lessons.
# ────────────────────────────────────────────────────────────────────────────
hook_lessons_extractor() {
  emit '{"systemMessage": "🧠 lessons-extractor: if anything novel/painful/reusable happened this session, dispatch the learning-loop agent to persist lessons to memory MCP."}'
}

# ────────────────────────────────────────────────────────────────────────────
# 8. result-summarizer (SubagentStop)
# Reminder to condense subagent output into key takeaways.
# ────────────────────────────────────────────────────────────────────────────
hook_result_summarizer() {
  emit '{"systemMessage": "📋 result-summarizer: summarize subagent findings as: (1) what was done, (2) key findings, (3) recommended next step. Drop verbose tool traces."}'
}

# Dispatch
case "$HOOK_TYPE" in
  intent-classifier)     hook_intent_classifier ;;
  secret-scanner)        hook_secret_scanner ;;
  blast-radius-warner)   hook_blast_radius_warner ;;
  auto-test-runner)      hook_auto_test_runner ;;
  auto-format)           hook_auto_format ;;
  commit-suggester)      hook_commit_suggester ;;
  lessons-extractor)     hook_lessons_extractor ;;
  result-summarizer)     hook_result_summarizer ;;
  *)                     emit '{}' ;;
esac
