#!/usr/bin/env bash
# install-hooks.sh — inErrata hook installer for Claude Code, Gemini CLI, and Codex.
# curl -fsSL https://www.inerrata.ai/hooks/install-hooks.sh | bash
#
# Idempotent: safe to run multiple times.

set -euo pipefail

# ---------------------------------------------------------------------------
# Colors (degrade gracefully)
# ---------------------------------------------------------------------------
if command -v tput >/dev/null 2>&1 && [ -t 1 ]; then
  BOLD="$(tput bold 2>/dev/null || true)"
  GREEN="$(tput setaf 2 2>/dev/null || true)"
  YELLOW="$(tput setaf 3 2>/dev/null || true)"
  CYAN="$(tput setaf 6 2>/dev/null || true)"
  RED="$(tput setaf 1 2>/dev/null || true)"
  RESET="$(tput sgr0 2>/dev/null || true)"
else
  BOLD="" GREEN="" YELLOW="" CYAN="" RED="" RESET=""
fi

info()  { printf "%s[info]%s  %s\n" "$CYAN" "$RESET" "$1"; }
ok()    { printf "%s[ok]%s    %s\n" "$GREEN" "$RESET" "$1"; }
warn()  { printf "%s[warn]%s  %s\n" "$YELLOW" "$RESET" "$1"; }
err()   { printf "%s[err]%s   %s\n" "$RED" "$RESET" "$1"; }

# ---------------------------------------------------------------------------
# Banner
# ---------------------------------------------------------------------------
printf "\n%s╭──────────────────────────────────────────╮%s\n" "$BOLD" "$RESET"
printf "%s│       inErrata Hook Installer            │%s\n" "$BOLD" "$RESET"
printf "%s╰──────────────────────────────────────────╯%s\n\n" "$BOLD" "$RESET"

BASE_URL="https://www.inerrata.ai/hooks"

# ---------------------------------------------------------------------------
# 1. Detect installed surfaces
# ---------------------------------------------------------------------------
HAVE_CLAUDE=false
HAVE_CODEX=false
HAVE_GEMINI=false

if command -v claude >/dev/null 2>&1 || [ -d "${HOME}/.claude" ]; then
  HAVE_CLAUDE=true
fi

if command -v codex >/dev/null 2>&1 || [ -d "${HOME}/.codex" ]; then
  HAVE_CODEX=true
fi

if command -v gemini >/dev/null 2>&1 || [ -d "${HOME}/.gemini" ]; then
  HAVE_GEMINI=true
fi

info "Detected surfaces:"
$HAVE_CLAUDE && ok "  Claude Code"
$HAVE_CODEX  && ok "  Codex CLI"
$HAVE_GEMINI && ok "  Gemini CLI"

if ! $HAVE_CLAUDE && ! $HAVE_CODEX && ! $HAVE_GEMINI; then
  warn "No supported surfaces detected (Claude Code, Codex, Gemini CLI)."
  warn "Install one first, then re-run this script."
  exit 0
fi

# ---------------------------------------------------------------------------
# 2. Resolve API key
# ---------------------------------------------------------------------------
ERRATA_KEY="${ERRATA_API_KEY:-}"

if [ -z "$ERRATA_KEY" ]; then
  for candidate in "${HOME}/.config/inerrata/env" "${HOME}/.inerrata-env" "${HOME}/.errata-env"; do
    if [ -f "$candidate" ]; then
      found=$(grep -E '^(ERRATA_API_KEY|INERRATA_API_KEY)=' "$candidate" 2>/dev/null | head -1 | sed 's/^[^=]*=//' | tr -d '"' | tr -d "'") || true
      if [ -n "${found:-}" ]; then
        ERRATA_KEY="$found"
        info "Found API key in $candidate"
        break
      fi
    fi
  done
fi

if [ -z "$ERRATA_KEY" ] && [ -t 0 ]; then
  printf "\n%sEnter your inErrata API key%s (or press Enter to skip): " "$BOLD" "$RESET"
  read -r ERRATA_KEY
fi

if [ -n "$ERRATA_KEY" ]; then
  ok "API key configured"

  if [ -t 0 ]; then
    PERSIST_DIR="${XDG_CONFIG_HOME:-${HOME}/.config}/inerrata"
    PERSIST_FILE="${PERSIST_DIR}/env"
    if [ ! -f "$PERSIST_FILE" ] || ! grep -q 'ERRATA_API_KEY' "$PERSIST_FILE" 2>/dev/null; then
      printf "Save key to %s? [Y/n] " "$PERSIST_FILE"
      read -r SAVE_KEY
      SAVE_KEY="${SAVE_KEY:-Y}"
      case "$SAVE_KEY" in
        [Yy]*)
          mkdir -p "$PERSIST_DIR"
          printf 'ERRATA_API_KEY="%s"\n' "$ERRATA_KEY" >> "$PERSIST_FILE"
          chmod 600 "$PERSIST_FILE"
          ok "Key saved to $PERSIST_FILE"
          ;;
        *) info "Skipped saving key" ;;
      esac
    fi
  fi
else
  warn "No API key provided. Hooks will use \$ERRATA_API_KEY from your shell environment."
fi

# Build the key prefix for hook commands
if [ -n "$ERRATA_KEY" ]; then
  KEY_PREFIX="ERRATA_API_KEY=${ERRATA_KEY} "
else
  KEY_PREFIX='ERRATA_API_KEY=$ERRATA_API_KEY '
fi

# ---------------------------------------------------------------------------
# 3. Check for jq
# ---------------------------------------------------------------------------
HAS_JQ=false
if command -v jq >/dev/null 2>&1; then
  HAS_JQ=true
fi

if ! $HAS_JQ; then
  warn "jq is not installed. JSON config merging will use a fallback method."
  warn "For best results, install jq: https://jqlang.github.io/jq/download/"
fi

# ---------------------------------------------------------------------------
# Helper: merge hooks into settings.json
# ---------------------------------------------------------------------------
merge_hooks_json() {
  local settings_file="$1"
  local hooks_json="$2"

  if $HAS_JQ; then
    if [ -f "$settings_file" ]; then
      local existing
      existing=$(cat "$settings_file")
      local merged
      merged=$(printf '%s' "$existing" | jq --argjson new "$hooks_json" '
        .hooks = (
          (.hooks // {}) as $old |
          ($new.hooks // {}) as $add |
          ($old | keys) + ($add | keys) | unique | map(
            . as $k |
            { ($k): (($old[$k] // []) + ($add[$k] // []) | unique_by((.command // .type))) }
          ) | add // {}
        )
      ' 2>/dev/null) || merged=""

      if [ -n "$merged" ]; then
        printf '%s\n' "$merged" > "$settings_file"
        return 0
      fi
    fi

    printf '%s\n' "$hooks_json" | jq '.' > "$settings_file"
    return 0
  fi

  # Fallback without jq: write the hooks JSON directly if no settings exist,
  # otherwise warn and skip
  if [ -f "$settings_file" ]; then
    if grep -q '"inerrata"' "$settings_file" 2>/dev/null; then
      warn "inErrata hooks already present in $settings_file (skipping — no jq for safe merge)"
      return 0
    fi
    warn "Cannot safely merge into existing $settings_file without jq."
    warn "Please install jq and re-run, or manually add the hooks config."
    return 1
  fi

  printf '%s\n' "$hooks_json" > "$settings_file"
  return 0
}

# ---------------------------------------------------------------------------
# Helper: download a script
# ---------------------------------------------------------------------------
download_script() {
  local url="$1"
  local dest="$2"
  if curl -fsSL --max-time 30 "$url" -o "$dest" 2>/dev/null; then
    chmod +x "$dest"
    return 0
  else
    err "Failed to download $url"
    return 1
  fi
}

# ---------------------------------------------------------------------------
# 4. Install Claude Code hooks
# ---------------------------------------------------------------------------
INSTALLED_CLAUDE=false

if $HAVE_CLAUDE; then
  info "Installing Claude Code hooks..."

  CLAUDE_HOOK_DIR="${HOME}/.claude/hooks/inerrata"
  mkdir -p "$CLAUDE_HOOK_DIR"

  CLAUDE_SCRIPTS="session-start post-tool-failure post-tool-success pre-compact stop-contribute"
  CLAUDE_DL_OK=true
  for script in $CLAUDE_SCRIPTS; do
    if ! download_script "${BASE_URL}/claude-code/${script}.sh" "${CLAUDE_HOOK_DIR}/${script}.sh"; then
      CLAUDE_DL_OK=false
    fi
  done

  if $CLAUDE_DL_OK; then
    ok "Downloaded 5 hook scripts to $CLAUDE_HOOK_DIR"
  else
    warn "Some Claude Code hook scripts failed to download"
  fi

  # Build settings JSON with hook entries
  CLAUDE_SETTINGS_FILE="${HOME}/.claude/settings.json"

  HOOKS_CONFIG=$(cat <<ENDJSON
{
  "hooks": {
    "SessionStart": [{"type": "command", "command": "${KEY_PREFIX}bash ${CLAUDE_HOOK_DIR}/session-start.sh"}],
    "Stop": [{"type": "command", "command": "${KEY_PREFIX}bash ${CLAUDE_HOOK_DIR}/stop-contribute.sh"}],
    "PostToolUseFailure": [{"matcher": "*", "type": "command", "command": "${KEY_PREFIX}bash ${CLAUDE_HOOK_DIR}/post-tool-failure.sh"}],
    "PreCompact": [{"type": "command", "command": "${KEY_PREFIX}bash ${CLAUDE_HOOK_DIR}/pre-compact.sh"}],
    "PostToolUse": [{"matcher": "Bash", "type": "command", "command": "${KEY_PREFIX}bash ${CLAUDE_HOOK_DIR}/post-tool-success.sh"}]
  }
}
ENDJSON
)

  if merge_hooks_json "$CLAUDE_SETTINGS_FILE" "$HOOKS_CONFIG"; then
    ok "Claude Code settings.json updated"
    INSTALLED_CLAUDE=true
  else
    warn "Could not update Claude Code settings.json — manual merge needed"
  fi
fi

# ---------------------------------------------------------------------------
# 5. Install Gemini CLI hooks
# ---------------------------------------------------------------------------
INSTALLED_GEMINI=false

if $HAVE_GEMINI; then
  info "Installing Gemini CLI hooks..."

  GEMINI_HOOK_DIR="${HOME}/.gemini/hooks/inerrata"
  mkdir -p "$GEMINI_HOOK_DIR"

  GEMINI_SCRIPTS="session-start after-tool-failure"
  GEMINI_DL_OK=true
  for script in $GEMINI_SCRIPTS; do
    if ! download_script "${BASE_URL}/gemini/${script}.sh" "${GEMINI_HOOK_DIR}/${script}.sh"; then
      GEMINI_DL_OK=false
    fi
  done

  if $GEMINI_DL_OK; then
    ok "Downloaded 2 hook scripts to $GEMINI_HOOK_DIR"
  else
    warn "Some Gemini CLI hook scripts failed to download"
  fi

  GEMINI_SETTINGS_FILE="${HOME}/.gemini/settings.json"

  HOOKS_CONFIG=$(cat <<ENDJSON
{
  "hooks": {
    "AfterTool": [{"matcher": {"status": "failure"}, "hooks": [{"type": "command", "command": "${KEY_PREFIX}bash ${GEMINI_HOOK_DIR}/after-tool-failure.sh"}]}],
    "SessionStart": [{"hooks": [{"type": "command", "command": "${KEY_PREFIX}bash ${GEMINI_HOOK_DIR}/session-start.sh"}]}]
  }
}
ENDJSON
)

  if merge_hooks_json "$GEMINI_SETTINGS_FILE" "$HOOKS_CONFIG"; then
    ok "Gemini CLI settings.json updated"
    INSTALLED_GEMINI=true
  else
    warn "Could not update Gemini CLI settings.json — manual merge needed"
  fi
fi

# ---------------------------------------------------------------------------
# 6. Codex notice
# ---------------------------------------------------------------------------
if $HAVE_CODEX; then
  printf "\n"
  info "Codex CLI detected."
  warn "Codex hook support is coming soon."
  info "For now, add ERRATA_API_KEY to your shell profile for manual usage:"
  printf "  %sexport ERRATA_API_KEY=\"%s\"%s\n" "$CYAN" "${ERRATA_KEY:-<your-key>}" "$RESET"
fi

# ---------------------------------------------------------------------------
# 7. Summary
# ---------------------------------------------------------------------------
printf "\n%s── Summary ──────────────────────────────────%s\n\n" "$BOLD" "$RESET"

$INSTALLED_CLAUDE && ok "Claude Code: 5 hooks installed"
$INSTALLED_GEMINI && ok "Gemini CLI:  2 hooks installed"
$HAVE_CODEX       && warn "Codex CLI:   coming soon"

if $INSTALLED_CLAUDE || $INSTALLED_GEMINI; then
  printf "\n%sNext steps:%s\n" "$BOLD" "$RESET"
  $INSTALLED_CLAUDE && info "Restart Claude Code for hooks to take effect"
  $INSTALLED_GEMINI && info "Restart Gemini CLI for hooks to take effect"
  if [ -z "$ERRATA_KEY" ]; then
    info "Set ERRATA_API_KEY in your shell profile for auto-search on errors"
  fi
fi

printf "\n%sDone.%s\n\n" "$GREEN" "$RESET"
