#!/bin/bash

# Git Pre-commit Hook para evaluación de código con Claude CLI
# Archivo: .git/hooks/pre-commit

set -e

# Configuración
CLAUDE_CLI="claude"
TEMP_DIR="/tmp/code-review-$$"
MAX_FILE_SIZE=100000  # 100KB máximo por archivo

# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Función para logging
log() {
    echo -e "${GREEN}[PRE-COMMIT]${NC} $1"
}

error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

# Detectar qué archivo de pautas usar
# Prioridad: variable de entorno > archivo > pregunta interactiva
if [ -n "$CLAUDE_ANALYSIS_MODE" ]; then
    ANALYSIS_MODE="$CLAUDE_ANALYSIS_MODE"
elif [ -f ".claude-analysis-mode" ]; then
    ANALYSIS_MODE=$(cat .claude-analysis-mode)
else
    ANALYSIS_MODE=""
fi

# Verificar si el usuario quiere cambiar el modo (con --change-mode)
if [ "$1" = "--change-mode" ]; then
    ANALYSIS_MODE=""
fi

# Si no hay modo guardado o es inválido, preguntar
if [ "$ANALYSIS_MODE" != "standard" ] && [ "$ANALYSIS_MODE" != "sonar" ]; then
    echo
    echo "🔍 Selecciona el formato de análisis de código:"
    echo "1) Estándar - Formato clásico con recomendaciones"
    echo "2) SonarQube - Formato similar a SonarQube con métricas"
    echo
    
    # Intentar leer desde terminal
    if [ -t 0 ] && [ -c /dev/tty ]; then
        read -p "Opción (1 o 2): " -n 1 -r </dev/tty
        echo
    else
        # Si no hay terminal interactiva, usar modo estándar por defecto
        echo "No se puede leer input interactivo, usando modo estándar por defecto"
        REPLY="1"
    fi
    
    if [ "$REPLY" = "2" ]; then
        ANALYSIS_MODE="sonar"
        GUIDELINES_FILE="CLAUDE_PRE_COMMIT_SONAR.md"
    else
        ANALYSIS_MODE="standard"
        GUIDELINES_FILE="CLAUDE_PRE_COMMIT.md"
    fi
    
    # Guardar preferencia para futuros commits
    echo "$ANALYSIS_MODE" > .claude-analysis-mode
    echo -e "${GREEN}✓ Modo $ANALYSIS_MODE guardado para futuros commits${NC}"
    echo -e "${YELLOW}Tip: Para cambiar el modo, ejecuta: .git/hooks/pre-commit --change-mode${NC}"
    echo
else
    # Usar modo guardado
    if [ "$ANALYSIS_MODE" = "sonar" ]; then
        GUIDELINES_FILE="CLAUDE_PRE_COMMIT_SONAR.md"
        log "Usando modo de análisis: SonarQube"
    else
        GUIDELINES_FILE="CLAUDE_PRE_COMMIT.md"
        log "Usando modo de análisis: Estándar"
    fi
fi
# Función para limpiar archivos temporales
cleanup() {
    rm -rf "$TEMP_DIR"
}

# Configurar limpieza al salir
trap cleanup EXIT

# Crear directorio temporal
mkdir -p "$TEMP_DIR"

# Verificar si Claude CLI está instalado (solo para análisis de código)
if ! command -v "$CLAUDE_CLI" &> /dev/null; then
    error "Claude CLI no está instalado o no se encuentra en el PATH"
    error "Instala Claude CLI desde: https://github.com/anthropics/claude-cli"
    exit 1
fi

# Ahora verificar si hay archivos Java para analizar
JAVA_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(java|xml|properties|yml|yaml)$' || true)

if [ -z "$JAVA_FILES" ]; then
    log "No hay archivos Java/configuración para revisar"
    exit 0
fi

# Verificar si existe el archivo de pautas
if [ ! -f "$GUIDELINES_FILE" ]; then
    warning "No se encontró el archivo de pautas: $GUIDELINES_FILE"
    warning "Saltando análisis de código"
    exit 0
fi

log "Archivos Java/config a revisar: $(echo "$JAVA_FILES" | wc -l)"

# Construir el prompt para análisis de código
PROMPT_FILE="$TEMP_DIR/code_review_prompt.txt"

cat > "$PROMPT_FILE" << 'EOF'
Eres un revisor de código senior con experiencia en proyectos Spring Boot empresariales.

Tu tarea es analizar los siguientes cambios de código y responder exclusivamente con un JSON válido, **sin ningún texto fuera del JSON**, sin introducciones ni explicaciones adicionales.

⚠️ La respuesta debe ser un objeto JSON con esta estructura exacta:

{
  "approved": true,                // true si el commit puede aceptarse, false si debe bloquearse
  "score": 1-10,                   // calificación de calidad (entero)
  "blockingIssues": [             // lista de errores críticos (vacía si no hay)
    "texto descriptivo 1",
    "texto descriptivo 2"
  ],
  "recommendations": [            // sugerencias no bloqueantes
    "mejora 1",
    "mejora 2"
  ],
  "details": {
    "security": [                 // comentarios específicos por área
      "observación sobre seguridad"
    ],
    "architecture": [ "..." ],
    "performance": [ "..." ],
    "maintainability": [ "..." ]
  }
}

✅ Importante:
- Usa listas aunque estén vacías (por ejemplo `"blockingIssues": []`)
- No uses texto introductorio o explicaciones fuera del JSON
- No omitas claves aunque estén vacías
- Sé directo, claro y profesional en tus observaciones

A continuación se detallan las pautas y los cambios:
EOF

# Agregar las pautas
echo "=== PAUTAS DE EVALUACIÓN ===" >> "$PROMPT_FILE"
cat "$GUIDELINES_FILE" >> "$PROMPT_FILE"
echo -e "\n\n=== CAMBIOS A REVISAR ===\n" >> "$PROMPT_FILE"

# Procesar cada archivo Java
FILE_COUNT=0
for FILE in $JAVA_FILES; do
    if [ -f "$FILE" ]; then
        FILE_SIZE=$(stat -c%s "$FILE" 2>/dev/null || stat -f%z "$FILE" 2>/dev/null || echo "0")
        
        if [ "$FILE_SIZE" -gt "$MAX_FILE_SIZE" ]; then
            warning "Archivo $FILE demasiado grande ($FILE_SIZE bytes), saltando..."
            continue
        fi
        
        echo -e "\n--- Archivo: $FILE ---" >> "$PROMPT_FILE"
        
        # Mostrar el diff del archivo
        echo -e "\nDiff:" >> "$PROMPT_FILE"
        git diff --cached "$FILE" >> "$PROMPT_FILE" 2>/dev/null || echo "No se pudo obtener diff"
        
        # Si es un archivo nuevo, mostrar contenido completo
        if git diff --cached --name-status | grep "^A.*$FILE" > /dev/null; then
            echo -e "\nContenido completo (archivo nuevo):" >> "$PROMPT_FILE"
            git show ":$FILE" >> "$PROMPT_FILE" 2>/dev/null || cat "$FILE" >> "$PROMPT_FILE"
        fi
        
        FILE_COUNT=$((FILE_COUNT + 1))
    fi
done

if [ "$FILE_COUNT" -eq 0 ]; then
    log "No se encontraron archivos válidos para revisar"
    exit 0
fi

if [ "$FILE_COUNT" -gt 10 ]; then
    warning "Demasiados archivos para revisar ($FILE_COUNT)"
    warning "Considera dividir el commit en partes más pequeñas"
    exit 0
fi

log "Enviando $FILE_COUNT archivos para revisión con Claude..."

# Enviar a Claude y capturar respuesta
RESPONSE_FILE="$TEMP_DIR/code_review_response.txt"

# Ejecutar Claude CLI y capturar la respuesta
if $CLAUDE_CLI < "$PROMPT_FILE" > "$RESPONSE_FILE" 2>&1; then
    # Extraer el JSON de la respuesta
    JSON_RESPONSE=$(sed -n '/^{/,/^}/p' "$RESPONSE_FILE" | head -n 1000)
    
    if [ -z "$JSON_RESPONSE" ]; then
        error "No se recibió una respuesta JSON válida de Claude"
        error "Respuesta completa:"
        cat "$RESPONSE_FILE"
        exit 1
    fi
    
    # Guardar JSON para debug si está activado
    if [ -n "$DEBUG" ]; then
        echo "$JSON_RESPONSE" > ./debug-claude-response.json
        log "Respuesta guardada en debug-claude-response.json"
    fi
    
    # Parsear la respuesta usando jq
    APPROVED=$(echo "$JSON_RESPONSE" | jq -r '.approved // false')
    SCORE=$(echo "$JSON_RESPONSE" | jq -r '.score // 0')
    RECOMMENDATIONS=$(echo "$JSON_RESPONSE" | jq -r '.recommendations[]?' 2>/dev/null | sed '/^$/d')
    BLOCKING_ISSUES=$(echo "$JSON_RESPONSE" | jq -r '.blockingIssues[]?' 2>/dev/null | sed '/^$/d')
    
    # Verificar si estamos en modo SonarQube
    QUALITY_GATE=$(echo "$JSON_RESPONSE" | jq -r '.qualityGate // ""' 2>/dev/null)
    
    if [ "$ANALYSIS_MODE" = "sonar" ] && [ -n "$QUALITY_GATE" ] && [ "$QUALITY_GATE" != "null" ]; then
        # Mostrar resultados estilo SonarQube
        echo
        echo "╔════════════════════════════════════════════════════════════════════╗"
        echo "║                     CODE QUALITY ANALYSIS                           ║"
        echo "╚════════════════════════════════════════════════════════════════════╝"
        echo
        
        # Quality Gate Status
        if [ "$QUALITY_GATE" = "PASSED" ]; then
            echo -e "${GREEN}✓ Quality Gate: PASSED${NC}"
        else
            echo -e "${RED}✗ Quality Gate: FAILED${NC}"
        fi
        echo
        
        # Metrics
        METRICS=$(echo "$JSON_RESPONSE" | jq -r '.metrics // {}' 2>/dev/null)
        if [ "$METRICS" != "{}" ] && [ "$METRICS" != "null" ]; then
            echo "📊 METRICS"
            echo "├─ Reliability: $(echo "$METRICS" | jq -r '.reliability // "?"' 2>/dev/null)"
            echo "├─ Security: $(echo "$METRICS" | jq -r '.security // "?"' 2>/dev/null)"
            echo "├─ Maintainability: $(echo "$METRICS" | jq -r '.maintainability // "?"' 2>/dev/null)"
            echo "├─ Coverage: $(echo "$METRICS" | jq -r '.coverage // "?"' 2>/dev/null)%"
            echo "├─ Duplications: $(echo "$METRICS" | jq -r '.duplications // "?"' 2>/dev/null)%"
            echo "└─ Complexity: $(echo "$METRICS" | jq -r '.complexity // "?"' 2>/dev/null)"
            echo
        fi
        
        # Issues Summary
        SUMMARY=$(echo "$JSON_RESPONSE" | jq -r '.summary // {}' 2>/dev/null)
        if [ "$SUMMARY" != "{}" ] && [ "$SUMMARY" != "null" ]; then
            echo "📋 ISSUES SUMMARY"
            TOTAL=$(echo "$SUMMARY" | jq -r '.total // 0' 2>/dev/null)
            BLOCKER=$(echo "$SUMMARY" | jq -r '.blocker // 0' 2>/dev/null)
            CRITICAL=$(echo "$SUMMARY" | jq -r '.critical // 0' 2>/dev/null)
            MAJOR=$(echo "$SUMMARY" | jq -r '.major // 0' 2>/dev/null)
            MINOR=$(echo "$SUMMARY" | jq -r '.minor // 0' 2>/dev/null)
            INFO=$(echo "$SUMMARY" | jq -r '.info // 0' 2>/dev/null)
            
            echo "Total: $TOTAL issues found"
            [ "$BLOCKER" -gt 0 ] && echo -e "  ${RED}🔴 Blocker: $BLOCKER${NC}"
            [ "$CRITICAL" -gt 0 ] && echo -e "  ${RED}🟠 Critical: $CRITICAL${NC}"
            [ "$MAJOR" -gt 0 ] && echo -e "  ${YELLOW}🟡 Major: $MAJOR${NC}"
            [ "$MINOR" -gt 0 ] && echo "  🔵 Minor: $MINOR"
            [ "$INFO" -gt 0 ] && echo "  ⚪ Info: $INFO"
            echo
        fi
        
        # Detailed Issues
        ISSUES_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.issues | length' 2>/dev/null)
        if [ "$ISSUES_COUNT" -gt 0 ] 2>/dev/null; then
            echo "🔍 DETAILED ISSUES"
            echo "$JSON_RESPONSE" | jq -r '.issues[]? | 
                "[\(.severity)] \(.type) in \(.file):\(.line // "?")\n   \(.message)\n   Rule: \(.rule // "N/A") | Effort: \(.effort // "?")\n"' 2>/dev/null
        fi
        
        # Security Hotspots
        HOTSPOTS_COUNT=$(echo "$JSON_RESPONSE" | jq -r '.hotspots | length' 2>/dev/null)
        if [ "$HOTSPOTS_COUNT" -gt 0 ] 2>/dev/null; then
            echo "🔥 SECURITY HOTSPOTS"
            echo "$JSON_RESPONSE" | jq -r '.hotspots[]? | "  • \(.file): \(.message)"' 2>/dev/null
            echo
        fi
        
        # Check if commit should be blocked
        if [ "$QUALITY_GATE" = "FAILED" ] || [ "$APPROVED" = "false" ]; then
            echo
            error "❌ Commit blocked due to quality gate failure"
            exit 1
        fi
        
        echo
        log "✅ Code analysis completed. Quality gate passed."
    else
        # Mostrar resultados en formato clásico
        echo
        echo "=== RESULTADO DE LA REVISIÓN ==="
        echo "Score: $SCORE/10"
        
        if [ -n "$RECOMMENDATIONS" ] && [ "$RECOMMENDATIONS" != "null" ]; then
            echo
            echo "=== RECOMENDACIONES ==="
            echo "$RECOMMENDATIONS" | sed 's/^/- /'
        fi
        
        # Verificar si el commit debe ser bloqueado
        if [ "$APPROVED" = "false" ]; then
            error "❌ Commit rechazado por problemas críticos"
            if [ -n "$BLOCKING_ISSUES" ] && [ "$BLOCKING_ISSUES" != "null" ]; then
                echo
                echo "=== PROBLEMAS CRÍTICOS ==="
                echo "$BLOCKING_ISSUES" | sed 's/^/- /'
            fi
            exit 1
        fi

        DETAILS=$(echo "$JSON_RESPONSE" | jq -r '.details // {}')
        if [ -n "$DETAILS" ] && [ "$DETAILS" != "{}" ] && [ "$DETAILS" != "null" ]; then
            echo
            echo "=== DETALLES POR CATEGORÍA ==="
            echo "$DETAILS" | jq
        fi
        
        log "✅ Revisión completada. Commit aprobado (Score: $SCORE/10)"
    fi
    
else
    error "Error al ejecutar Claude CLI"
    error "Verifica que Claude CLI esté configurado correctamente"
    cat "$RESPONSE_FILE"
    exit 1
fi

exit 0