#!/usr/bin/env bash
# SessionStart hook for sumo-qa plugin.
#
# Injects a compact bootstrap (hooks/compact-bootstrap.md: the first-hop rule
# plus a pointer to the `using_sumo_qa` router) into every conversation, so a
# QA-shaped request enters sumo-qa's workflow rather than free-styling generic
# testing advice, while a non-QA session does not carry the full router body.
#
# Capability fallback: the compact pointer needs a launchable MCP server (or a
# host Skill tool). When `uvx` is missing the plugin MCP server cannot start,
# so the full `using-sumo-qa` body is injected instead. SUMO_QA_BOOTSTRAP=full
# or =compact overrides the detection; =auto (or unset) detects. Any other
# value is reported in the injected context and treated as auto.

set -euo pipefail

# Determine plugin root directory
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PLUGIN_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"

uvx_present=0
if command -v uvx >/dev/null 2>&1; then
    uvx_present=1
fi

bootstrap_mode="${SUMO_QA_BOOTSTRAP:-auto}"
bootstrap_notice=""
case "$bootstrap_mode" in
    full|compact|auto) ;;
    *)
        # Sanitised so the echoed value cannot break the JSON envelope.
        bootstrap_notice="sumo-qa: SUMO_QA_BOOTSTRAP=${bootstrap_mode//[^[:alnum:]_.-]/?} is not one of auto, compact, full; using auto."
        bootstrap_mode="auto"
        ;;
esac
if [ "$bootstrap_mode" = "auto" ]; then
    if [ "$uvx_present" = 1 ]; then
        bootstrap_mode="compact"
    else
        bootstrap_mode="full"
    fi
fi

if [ "$bootstrap_mode" = "compact" ]; then
    bootstrap_content=$(cat "${PLUGIN_ROOT}/hooks/compact-bootstrap.md" 2>&1 || echo "Error reading sumo-qa compact bootstrap")
    # Literal placeholder in, absolute path out; escape_for_json escapes it
    # below. patsub_replacement (bash 5.2+) would expand `&` in the path.
    # Under Git Bash / MSYS on Windows the POSIX path (/c/Users/...) is not one
    # a Windows host can open, so cygpath converts it to C:/Users/... form.
    injected_root="$PLUGIN_ROOT"
    if command -v cygpath >/dev/null 2>&1; then
        injected_root="$(cygpath -m "$PLUGIN_ROOT" 2>/dev/null || printf '%s' "$PLUGIN_ROOT")"
    fi
    shopt -u patsub_replacement 2>/dev/null || true
    # shellcheck disable=SC2016 # the literal placeholder text, not an expansion
    placeholder='${PLUGIN_ROOT}'
    bootstrap_content=${bootstrap_content//"$placeholder"/$injected_root}
else
    using_sumo_qa_content=$(cat "${PLUGIN_ROOT}/skills/using-sumo-qa/SKILL.md" 2>&1 || echo "Error reading using-sumo-qa skill")
    bootstrap_content=$(printf '%s\n\n%s\n\n%s' \
        'You have sumo-qa: a senior-QA skills library + MCP server.' \
        "**Below is the full content of your 'sumo-qa:using-sumo-qa' skill - your entry router for every QA-shaped task. For all other sumo-qa skills, use the 'Skill' tool:**" \
        "$using_sumo_qa_content")
fi

# Escape string for JSON embedding using bash parameter substitution.
# Each ${s//old/new} is a single C-level pass - orders of magnitude
# faster than the character-by-character loop this replaces.
escape_for_json() {
    local s="$1"
    s="${s//\\/\\\\}"
    s="${s//\"/\\\"}"
    s="${s//$'\n'/\\n}"
    s="${s//$'\r'/\\r}"
    s="${s//$'\t'/\\t}"
    printf '%s' "$s"
}

bootstrap_escaped=$(escape_for_json "$bootstrap_content")

# Without uvx the plugin's MCP server can't launch (probe above). Surface
# a high-priority warning so Claude tells the user proactively instead of
# letting MCP tools fail opaquely on first invocation.
#
# Note: printf is used instead of a quoted heredoc (<<'EOF') because bash 3.2
# (macOS system bash) does not support quoted heredocs inside $() subshells.
if [ "$uvx_present" = 1 ]; then
    uvx_warning_escaped=""
    system_message_escaped=""
else
    uvx_warning=$(printf '%s\n%s\n\n%s\n    %s\n    %s\n    %s\n    %s\n    %s\n    %s\n\n%s\n%s\n' \
        '<UVX_WARNING>' \
        "The sumo-qa plugin's MCP server runs via uv's \`uvx\` package runner, but \`uvx\` is not on PATH in this session. sumo_qa_* MCP tools will fail to launch until uv is installed." \
        'Tell the user to install uv once:' \
        '# macOS / Linux' \
        'curl -LsSf https://astral.sh/uv/install.sh | sh' \
        '# Windows (PowerShell)' \
        'powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"' \
        '# Homebrew' \
        'brew install uv' \
        "Then restart this Claude Code session so the plugin's MCP server is re-spawned." \
        '</UVX_WARNING>')
    uvx_warning_escaped=$(escape_for_json "$uvx_warning")

    # The additionalContext above is silent — Claude reads it but the user
    # never sees it directly. Emit a separate user-visible systemMessage so
    # Claude Code surfaces the failure mode in the chat UI immediately at
    # session start, instead of relying on the LLM to remember to mention it.
    system_message=$(printf '%s\n\n%s\n  %s\n\nOr: %s\n\n%s' \
        'sumo-qa plugin: uvx is not on PATH. The plugin MCP server cannot launch and sumo_qa_* tools will fail.' \
        'Install uv (macOS / Linux):' \
        'curl -LsSf https://astral.sh/uv/install.sh | sh' \
        'brew install uv' \
        'Then restart Claude Code so the plugin MCP server is re-spawned.')
    system_message_escaped=$(escape_for_json "$system_message")
fi

# Note: the Sumo-sensei persona is OFF by default. To enable it the user must
# point the agent at docs/PERSONA.md explicitly mid-conversation (e.g. "read
# docs/PERSONA.md and adopt the Sumo-sensei voice"). No skill currently
# auto-recognises persona toggle phrases. See docs/PERSONA.md.

notice_escaped=""
if [ -n "$bootstrap_notice" ]; then
    notice_escaped="$(escape_for_json "$bootstrap_notice")\n"
fi

session_context="${notice_escaped}${uvx_warning_escaped}<EXTREMELY_IMPORTANT>\n${bootstrap_escaped}\n</EXTREMELY_IMPORTANT>"

# Output context injection as JSON.
# Cursor hooks expect additional_context (snake_case).
# Claude Code hooks expect hookSpecificOutput.additionalContext (nested).
# Copilot CLI (v1.0.11+) and others expect additionalContext (top-level, SDK standard).
# Claude Code reads BOTH additional_context and hookSpecificOutput without
# deduplication, so we must emit only the field the current platform consumes.
#
# Uses printf instead of heredoc to work around bash 5.3+ heredoc hang.
if [ -n "${CURSOR_PLUGIN_ROOT:-}" ]; then
  # Cursor sets CURSOR_PLUGIN_ROOT (may also set CLAUDE_PLUGIN_ROOT)
  if [ -n "$system_message_escaped" ]; then
    printf '{\n  "systemMessage": "%s",\n  "additional_context": "%s"\n}\n' \
      "$system_message_escaped" "$session_context"
  else
    printf '{\n  "additional_context": "%s"\n}\n' "$session_context"
  fi
elif [ -n "${CLAUDE_PLUGIN_ROOT:-}" ] && [ -z "${COPILOT_CLI:-}" ]; then
  # Claude Code sets CLAUDE_PLUGIN_ROOT without COPILOT_CLI
  if [ -n "$system_message_escaped" ]; then
    printf '{\n  "systemMessage": "%s",\n  "hookSpecificOutput": {\n    "hookEventName": "SessionStart",\n    "additionalContext": "%s"\n  }\n}\n' \
      "$system_message_escaped" "$session_context"
  else
    printf '{\n  "hookSpecificOutput": {\n    "hookEventName": "SessionStart",\n    "additionalContext": "%s"\n  }\n}\n' "$session_context"
  fi
else
  # Copilot CLI (sets COPILOT_CLI=1) or unknown platform — SDK standard format
  if [ -n "$system_message_escaped" ]; then
    printf '{\n  "systemMessage": "%s",\n  "additionalContext": "%s"\n}\n' \
      "$system_message_escaped" "$session_context"
  else
    printf '{\n  "additionalContext": "%s"\n}\n' "$session_context"
  fi
fi

exit 0
