#!/bin/bash

# Common utilities for CodeVibe Gemini hooks
# This file provides shared functions for all hook scripts

# ─── Reviewer-subprocess short-circuit ───────────────────────────────
#
# When $QUORUM_REVIEWER_SUBPROCESS is set, the current `gemini`
# invocation is a reviewer subprocess spawned by Quorum 2.0's
# `GeminiReviewerProvider` (codevibe-core-rs/crates/codevibe-reviewer/
# src/providers/gemini.rs). Reviewer subprocesses have their own
# ephemeral session_id that MUST NOT interact with the user's primary
# Gemini session state.
#
# Without this guard, every reviewer spawn fires SessionStart →
# plugin's switchToResumedSession() evicts the user's primary session
# (marks it INACTIVE) → mobile app stops showing it. Worse, the
# plugin's in-memory session-key cache gets polluted and the primary
# session's subsequent events get encrypted with the wrong key →
# ciphertext on iOS. Both symptoms empirically observed on 2026-04-21
# when Quorum 2.0 local testing hit Hendry's primary Gemini plugin.
#
# Because `common.sh` is sourced by every hook script, `exit 0` here
# propagates to the hook script — Gemini CLI sees a clean hook
# success and continues normally. Zero-impact for normal user
# sessions (the env var is never set in the 1.0 code path).
#
# This change belongs on 1.0 main because it protects the 1.0
# primary-session-isolation invariant. The env var name is
# deliberately scoped `QUORUM_*` to avoid collision with other
# tooling and to signal its semantic origin.
if [ -n "$QUORUM_REVIEWER_SUBPROCESS" ]; then
    exit 0
fi

# Configuration
# Use TMPDIR if set (macOS sets this to user-specific temp), otherwise /tmp
CODEVIBE_TMPDIR="${TMPDIR:-/tmp}"
LOG_FILE="${LOG_FILE:-${CODEVIBE_TMPDIR}/codevibe-gemini-hooks.log}"
DEFAULT_PORT="${DEFAULT_PORT:-3457}"

# Timeout for interactive prompts (5 minutes = 300 seconds)
INTERACTIVE_PROMPT_TIMEOUT="${INTERACTIVE_PROMPT_TIMEOUT:-300}"
# Poll interval for checking prompt response (1 second)
POLL_INTERVAL="${POLL_INTERVAL:-1}"

# Log a message with timestamp
log() {
  local level="$1"
  shift
  local message="$*"
  echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] [$level] [gemini-hook] $message" >> "$LOG_FILE"
}

# Get the MCP server URL for a given session
# Priority: session-specific port file → default port file → DEFAULT_PORT
get_mcp_server_url() {
  local session_id="$1"
  local port="$DEFAULT_PORT"

  # Try session-specific port file first
  if [ -n "$session_id" ]; then
    local port_file="${CODEVIBE_TMPDIR}/codevibe-gemini-${session_id}.port"
    if [ -f "$port_file" ]; then
      port=$(cat "$port_file")
      log "DEBUG" "Using port from session file: $port"
      echo "http://localhost:${port}"
      return
    fi
  fi

  # Fallback: default port file (written at server startup before any session)
  local default_port_file="${CODEVIBE_TMPDIR}/codevibe-gemini-default.port"
  if [ -f "$default_port_file" ]; then
    port=$(cat "$default_port_file")
    log "DEBUG" "Using port from default file: $port"
  else
    log "DEBUG" "No port files found, using default port $port"
  fi

  echo "http://localhost:${port}"
}

# Read JSON input from stdin
read_json_input() {
  # Read all input from stdin
  cat
}

# Send event to MCP server via HTTP POST
# Usage: send_to_mcp <endpoint> <json_data> [session_id]
send_to_mcp() {
  local endpoint="$1"
  local json_data="$2"
  local session_id="$3"

  # Get the MCP server URL for this session
  local mcp_url=$(get_mcp_server_url "$session_id")

  log "INFO" "Sending to MCP server: POST $mcp_url/$endpoint"
  log "DEBUG" "Payload: $json_data"

  # Send HTTP POST request to MCP server
  local response
  local http_code

  response=$(curl -s -w "\n%{http_code}" \
    -X POST \
    -H "Content-Type: application/json" \
    -d "$json_data" \
    "$mcp_url/$endpoint" 2>&1)

  http_code=$(echo "$response" | tail -n 1)
  # Use sed instead of head -n -1 for macOS compatibility
  local body=$(echo "$response" | sed '$d')

  if [ "$http_code" = "200" ]; then
    log "INFO" "Successfully sent to MCP server (HTTP $http_code)"
    log "DEBUG" "Response: $body"
    echo "$body"
    return 0
  else
    log "ERROR" "Failed to send to MCP server (HTTP $http_code)"
    log "ERROR" "Response: $body"
    return 1
  fi
}

# Send interactive prompt and wait for response
# Usage: send_interactive_prompt <json_data> <session_id>
# Returns: JSON with decision field or exits with error
send_interactive_prompt() {
  local json_data="$1"
  local session_id="$2"

  local mcp_url=$(get_mcp_server_url "$session_id")

  log "INFO" "Sending interactive prompt to MCP server"

  # Send the interactive prompt request
  local response
  local http_code

  response=$(curl -s -w "\n%{http_code}" \
    -X POST \
    -H "Content-Type: application/json" \
    -d "$json_data" \
    "$mcp_url/interactive-prompt" 2>&1)

  http_code=$(echo "$response" | tail -n 1)
  local body=$(echo "$response" | sed '$d')

  if [ "$http_code" != "200" ]; then
    log "ERROR" "Failed to send interactive prompt (HTTP $http_code)"
    log "ERROR" "Response: $body"
    # Return default "ask" decision on error
    echo '{"decision":"ask","reason":"Failed to communicate with MCP server"}'
    return 1
  fi

  # Extract prompt ID from response
  local prompt_id=$(echo "$body" | grep -o '"promptId"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/')

  if [ -z "$prompt_id" ]; then
    log "ERROR" "No promptId in response: $body"
    echo '{"decision":"ask","reason":"No prompt ID received"}'
    return 1
  fi

  log "INFO" "Got prompt ID: $prompt_id, polling for response..."

  # Poll for response
  local elapsed=0
  while [ $elapsed -lt $INTERACTIVE_PROMPT_TIMEOUT ]; do
    sleep $POLL_INTERVAL
    elapsed=$((elapsed + POLL_INTERVAL))

    # Check for response
    response=$(curl -s -w "\n%{http_code}" \
      "$mcp_url/prompt-response/$prompt_id" 2>&1)

    http_code=$(echo "$response" | tail -n 1)
    body=$(echo "$response" | sed '$d')

    if [ "$http_code" = "200" ]; then
      # Check if we have a decision
      local decision=$(echo "$body" | grep -o '"decision"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*"\([^"]*\)"$/\1/')

      if [ -n "$decision" ] && [ "$decision" != "pending" ]; then
        log "INFO" "Got decision: $decision after ${elapsed}s"
        echo "$body"
        return 0
      fi
    elif [ "$http_code" = "404" ]; then
      # Prompt not found or expired
      log "WARN" "Prompt not found or expired"
      echo '{"decision":"ask","reason":"Prompt expired or not found"}'
      return 1
    fi

    log "DEBUG" "Still waiting for response... (${elapsed}s / ${INTERACTIVE_PROMPT_TIMEOUT}s)"
  done

  # Timeout reached
  log "WARN" "Timeout waiting for interactive prompt response after ${INTERACTIVE_PROMPT_TIMEOUT}s"
  echo '{"decision":"ask","reason":"Timeout waiting for mobile response"}'
  return 1
}

# Extract field from JSON using grep/sed (simple alternative to jq)
# This is a basic implementation - for complex JSON, consider using jq
extract_field() {
  local json="$1"
  local field="$2"

  # Simple regex-based extraction (works for simple string values)
  echo "$json" | grep -o "\"$field\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | sed "s/\"$field\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\"/\1/"
}

# Check if MCP server is running
# Usage: check_mcp_server [session_id]
check_mcp_server() {
  local session_id="$1"
  local mcp_url=$(get_mcp_server_url "$session_id")

  log "DEBUG" "Checking if MCP server is running at $mcp_url"

  local response
  response=$(curl -s "$mcp_url/health" 2>&1)

  if [ $? -eq 0 ]; then
    log "DEBUG" "MCP server is running"
    return 0
  else
    log "WARN" "MCP server is not responding at $mcp_url"
    return 1
  fi
}

# Export variables and functions for use in other scripts
export CODEVIBE_TMPDIR
export INTERACTIVE_PROMPT_TIMEOUT
export POLL_INTERVAL
export -f log
export -f get_mcp_server_url
export -f read_json_input
export -f send_to_mcp
export -f send_interactive_prompt
export -f extract_field
export -f check_mcp_server
