#!/bin/bash
# ============================================
# AI Code Review Hook for Claude Code
#
# Triggers when Claude completes work (Stop event) and sends
# the completed work to both Gemini MCP and Codex MCP for
# comprehensive AI code review using the ai-code-review skill.
#
# Hook Events Used:
#   - PostToolUse (Edit|Write): Tracks changed files
#   - Stop: Initiates AI code review on all changes
#
# MCP Servers Used:
#   - mcp__gemini-cli__ask-gemini (gemini-2.5-flash)
#   - mcp__codex-mcp__prompt_engine (CAGEERF methodology)
#   - mcp__codex__codex (comprehensive analysis)
#
# Created: 2024-12-10
# ============================================

set -uo pipefail
# Note: -e removed to allow graceful error handling

# Configuration
PROJECT_ROOT="/Users/Asim/Desktop/mawidi_codex"
REVIEW_QUEUE_DIR="/tmp/claude_code_review"
REVIEW_QUEUE_FILE="$REVIEW_QUEUE_DIR/queued_files.jsonl"
LOG_FILE="$REVIEW_QUEUE_DIR/review-hook.log"
MAX_FILE_SIZE=100000  # 100KB max per file for review

# Ensure directories exist
mkdir -p "$REVIEW_QUEUE_DIR"

# Function to log messages
log_message() {
    local timestamp
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] $1" >> "$LOG_FILE"
}

# Function to check if file should be reviewed
should_review_file() {
    local file_path="$1"

    # Skip non-code files
    if [[ ! "$file_path" =~ \.(ts|tsx|js|jsx|py|go|rs|java|sql|prisma)$ ]]; then
        return 1
    fi

    # Skip test files (they will be reviewed with their source)
    if [[ "$file_path" =~ \.(test|spec)\.(ts|tsx|js|jsx)$ ]]; then
        return 1
    fi

    # Skip directories that should not be reviewed
    local skip_dirs=("node_modules" ".next" ".git" "dist" "build" ".claude" "coverage" "__pycache__")
    for dir in "${skip_dirs[@]}"; do
        if [[ "$file_path" == *"/$dir/"* ]] || [[ "$file_path" == *"$dir/"* ]]; then
            return 1
        fi
    done

    # Skip very large files
    if [[ -f "$file_path" ]]; then
        local file_size
        file_size=$(stat -f%z "$file_path" 2>/dev/null || stat --printf="%s" "$file_path" 2>/dev/null || echo "0")
        if [[ "$file_size" -gt $MAX_FILE_SIZE ]]; then
            return 1
        fi
    fi

    return 0
}

# Function to handle PostToolUse event - queue files for review
handle_post_tool_use() {
    local input="$1"

    local tool_name
    tool_name=$(echo "$input" | jq -r '.tool_name // empty')

    # Only handle Edit and Write tools
    if [[ "$tool_name" != "Edit" ]] && [[ "$tool_name" != "Write" ]]; then
        echo '{"continue": true}'
        exit 0
    fi

    local file_path
    file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')

    if [[ -z "$file_path" ]]; then
        echo '{"continue": true}'
        exit 0
    fi

    # Check if file should be reviewed
    if ! should_review_file "$file_path"; then
        echo '{"continue": true}'
        exit 0
    fi

    log_message "PostToolUse: Queuing file for review: $file_path"

    # Add to review queue (compact single-line JSON for JSONL format)
    local queue_entry
    queue_entry=$(jq -cn \
        --arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
        --arg file_path "$file_path" \
        --arg tool_name "$tool_name" \
        '{timestamp: $timestamp, file_path: $file_path, tool_name: $tool_name}')

    echo "$queue_entry" >> "$REVIEW_QUEUE_FILE"

    echo '{"continue": true}'
}

# Function to handle Stop event - trigger AI code review
handle_stop() {
    local input="$1"

    log_message "Stop: Processing AI code review trigger"

    # Check if we have files to review
    if [[ ! -f "$REVIEW_QUEUE_FILE" ]] || [[ ! -s "$REVIEW_QUEUE_FILE" ]]; then
        log_message "Stop: No files queued for review"
        echo '{"continue": true}'
        exit 0
    fi

    # Get list of unique files (suppress jq errors for malformed lines)
    local -a unique_files
    unique_files=()
    while IFS= read -r line; do
        # Skip empty lines
        [[ -z "$line" ]] && continue
        local file_path
        file_path=$(echo "$line" | jq -r '.file_path // empty' 2>/dev/null || echo "")
        if [[ -n "$file_path" ]] && [[ -f "$file_path" ]]; then
            # Check if already in array (handle empty array case)
            local found=0
            for existing in "${unique_files[@]+"${unique_files[@]}"}"; do
                if [[ "$existing" == "$file_path" ]]; then
                    found=1
                    break
                fi
            done
            if [[ $found -eq 0 ]]; then
                unique_files+=("$file_path")
            fi
        fi
    done < "$REVIEW_QUEUE_FILE"

    local file_count=${#unique_files[@]}

    if [[ $file_count -lt 1 ]]; then
        log_message "Stop: No valid files to review"
        echo '{"continue": true}'
        exit 0
    fi

    log_message "Stop: Found $file_count files for potential AI code review"

    # Build file paths for the review prompt
    local file_list=""
    local gemini_file_refs=""
    for file in "${unique_files[@]}"; do
        if [[ -f "$file" ]]; then
            local relative_path="${file#$PROJECT_ROOT/}"
            file_list="${file_list}- ${relative_path}\\n"
            gemini_file_refs="${gemini_file_refs}@${relative_path} "
        fi
    done

    # Build the system message using printf for proper escaping
    local file_list_escaped
    file_list_escaped=$(printf '%s' "$file_list" | sed 's/\\n/\n/g')

    # ============================================
    # INTERACTIVE CONFIRMATION
    # Ask user if they want to run AI code review
    # (This sends data to Codex and Gemini MCP servers)
    # ============================================
    echo "" >&2
    echo "╔══════════════════════════════════════════════════════════════╗" >&2
    echo "║           AI CODE REVIEW - CONFIRMATION REQUIRED             ║" >&2
    echo "╠══════════════════════════════════════════════════════════════╣" >&2
    echo "║ ${file_count} file(s) modified and ready for AI review.             ║" >&2
    echo "║                                                              ║" >&2
    echo "║ ⚠️  This will send code to external AI services:             ║" >&2
    echo "║    • Gemini MCP (Google)                                     ║" >&2
    echo "║    • Codex MCP                                               ║" >&2
    echo "╠══════════════════════════════════════════════════════════════╣" >&2
    echo "║ Files to review:                                             ║" >&2
    printf '%s' "$file_list_escaped" | while IFS= read -r line; do
        printf "║   %s\n" "$line" >&2
    done
    echo "╚══════════════════════════════════════════════════════════════╝" >&2
    echo "" >&2

    # Read user confirmation from /dev/tty (interactive terminal)
    local response=""
    if [[ -t 0 ]] || [[ -e /dev/tty ]]; then
        printf "Run AI code review? [y/N]: " >&2
        read -r response < /dev/tty 2>/dev/null || response="n"
    else
        log_message "Stop: Non-interactive mode, skipping AI review"
        response="n"
    fi

    # Clean up queue file regardless of choice
    rm -f "$REVIEW_QUEUE_FILE"

    # Check user response
    if [[ "$response" =~ ^[Yy]$ ]] || [[ "$response" =~ ^[Yy][Ee][Ss]$ ]]; then
        log_message "Stop: User approved AI code review for $file_count files"

        local system_message
        system_message=$(printf '## AI Code Review Triggered\n\nWork completed with %d file(s) modified.\n\n### Files Modified:\n%s\n\n### Run AI Code Review:\n\n**Gemini CLI:** `mcp__gemini-cli__ask-gemini` with prompt: "%s Review for security, performance, errors, code style"\n\n**Codex MCP:** `mcp__codex-mcp__prompt_engine` with command: ">>code_review"\n\n**Codex Analysis:** `mcp__codex__codex` for logic verification and improvements\n\nRunning AI code review now...' "$file_count" "$file_list_escaped" "$gemini_file_refs")

        # Return the system message to prompt Claude using jq for proper JSON encoding
        jq -n --arg msg "$system_message" '{"continue": true, "systemMessage": $msg}'
    else
        log_message "Stop: User declined AI code review"
        echo "" >&2
        echo "AI code review skipped." >&2
        echo '{"continue": true}'
    fi
}

# Main handler
main() {
    # Read input from stdin
    local input
    input=$(cat)

    # Validate JSON input - if empty or invalid, exit gracefully
    if [[ -z "$input" ]] || ! echo "$input" | jq empty 2>/dev/null; then
        log_message "Invalid or empty JSON input received"
        echo '{"continue": true}'
        exit 0
    fi

    # Get hook event name
    local hook_event
    hook_event=$(echo "$input" | jq -r '.hook_event_name // empty' 2>/dev/null || echo "")

    log_message "Hook triggered: $hook_event"

    case "$hook_event" in
        "PostToolUse")
            handle_post_tool_use "$input"
            ;;
        "Stop")
            handle_stop "$input"
            ;;
        *)
            log_message "Unknown hook event: $hook_event"
            echo '{"continue": true}'
            ;;
    esac
}

# Run main
main "$@"

exit 0
