#!/bin/bash

# ============================================================================
# CONFIGURACIÓN - Editar estas constantes para personalizar el script
# ============================================================================

# Detectar la ubicación del script y la raíz del proyecto
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"

# Rutas del proyecto
DEFAULT_ANALYSIS_PATH="$PROJECT_ROOT/source"
INCLUDE_PATH="$PROJECT_ROOT/source"
SUPPRESSIONS_FILE="$SCRIPT_DIR/cppcheck_suppressions"
OUTPUT_DIR="$SCRIPT_DIR"
BUILD_DIR="$PROJECT_ROOT/build"
COMPILE_COMMANDS="$BUILD_DIR/compile_commands.json"

# Parámetros de compilación comunes (fallback para análisis de archivos específicos)
CPPCHECK_STD="--std=c++20"

# Calcular número de threads (cores - 1, mínimo 1)
THREADS=$(($(nproc) - 1))
[[ $THREADS -lt 1 ]] && THREADS=1

# ============================================================================

# Función para asegurar que compile_commands.json existe
ensure_compile_commands() {
    if [[ ! -f "$COMPILE_COMMANDS" ]]; then
        echo "⚠ compile_commands.json no encontrado en $BUILD_DIR"
        echo "Generando compile_commands.json con CMake..."

        # Crear directorio build si no existe
        mkdir -p "$BUILD_DIR"

        # Ejecutar CMake para generar compile_commands.json
        (cd "$BUILD_DIR" && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. > /dev/null 2>&1)

        if [[ ! -f "$COMPILE_COMMANDS" ]]; then
            echo "❌ Error: No se pudo generar compile_commands.json"
            echo "Por favor, ejecuta manualmente:"
            echo "  cd $BUILD_DIR && cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .."
            exit 1
        fi

        echo "✓ compile_commands.json generado exitosamente"
    else
        echo "✓ Usando compile_commands.json existente: $COMPILE_COMMANDS"
    fi
}

# Función para mostrar el uso del script
mostrar_uso() {
    echo "Uso: $0 [OPCIÓN] [RUTA]"
    echo ""
    echo "Opciones de análisis:"
    echo "  -w, --warning        Ejecutar cppcheck con warning, style, performance"
    echo "  -a, --all            Ejecutar cppcheck con todas las opciones habilitadas"
    echo "  -u, --unused         Ejecutar cppcheck para unusedFunction"
    echo ""
    echo "Opciones de ruta:"
    echo "  -p, --path <ruta>    Especificar ruta a analizar (default: PROJECT_ROOT/source)"
    echo "  [RUTA]               Ruta como último argumento posicional"
    echo ""
    echo "Ejemplos:"
    echo "  $0 --warning"
    echo "  $0 -w --path ../src/"
    echo "  $0 --all /path/to/code/"
    echo "  $0 -u ../source/"
}

# Inicializar las variables
opcion=""
ruta="$DEFAULT_ANALYSIS_PATH"

# Procesar las opciones
while [[ $# -gt 0 ]]; do
    case $1 in
        -w|--warning)
            opcion="warning"
            shift
            ;;
        -a|--all)
            opcion="all"
            shift
            ;;
        -u|--unused)
            opcion="unused"
            shift
            ;;
        -p|--path)
            if [[ -n "$2" && "$2" != -* ]]; then
                ruta="$2"
                shift 2
            else
                echo "Error: --path requiere un argumento"
                mostrar_uso
                exit 1
            fi
            ;;
        -h|--help)
            mostrar_uso
            exit 0
            ;;
        -*)
            echo "Error: Opción desconocida: $1"
            mostrar_uso
            exit 1
            ;;
        *)
            # Argumento posicional (asumimos que es la ruta)
            ruta="$1"
            shift
            ;;
    esac
done

# Verificar que se haya especificado una opción de análisis
if [[ -z "$opcion" ]]; then
    echo "Error: Debe especificar una opción de análisis (-w, -a, o -u)"
    mostrar_uso
    exit 1
fi

# Ejecutar según la opción seleccionada
case $opcion in
    warning)
        ensure_compile_commands
        if [[ "$ruta" == "$DEFAULT_ANALYSIS_PATH" ]]; then
            echo "Ejecutando cppcheck con warning, style, performance en proyecto completo (usando $THREADS threads)"
            cppcheck --force --enable=warning,style,performance \
            --check-level=exhaustive \
            -j$THREADS \
            --project="$COMPILE_COMMANDS" \
            --suppressions-list="$SUPPRESSIONS_FILE" \
            2>"$OUTPUT_DIR/cppcheck-result-warning-style-performance.txt"
        else
            echo "Ejecutando cppcheck con warning, style, performance en: $ruta (usando $THREADS threads)"
            cppcheck --force --enable=warning,style,performance $CPPCHECK_STD \
            --check-level=exhaustive \
            -j$THREADS \
            -I "$INCLUDE_PATH" \
            --suppressions-list="$SUPPRESSIONS_FILE" \
            "$ruta" \
            2>"$OUTPUT_DIR/cppcheck-result-warning-style-performance.txt"
        fi
        echo "Resultados guardados en: $OUTPUT_DIR/cppcheck-result-warning-style-performance.txt"
        ;;
    all)
        ensure_compile_commands
        if [[ "$ruta" == "$DEFAULT_ANALYSIS_PATH" ]]; then
            echo "Ejecutando cppcheck con todas las opciones en proyecto completo (usando $THREADS threads)"
            cppcheck --force --enable=all \
            -j$THREADS \
            --project="$COMPILE_COMMANDS" \
            --suppress=missingIncludeSystem \
            --suppressions-list="$SUPPRESSIONS_FILE" \
            2>"$OUTPUT_DIR/cppcheck-result-all.txt"
        else
            echo "Ejecutando cppcheck con todas las opciones en: $ruta (usando $THREADS threads)"
            cppcheck --force --enable=all -I /usr/include -I "$INCLUDE_PATH" $CPPCHECK_STD \
            -j$THREADS \
            --suppress=missingIncludeSystem \
            --suppressions-list="$SUPPRESSIONS_FILE" \
            "$ruta" \
            2>"$OUTPUT_DIR/cppcheck-result-all.txt"
        fi
        echo "Resultados guardados en: $OUTPUT_DIR/cppcheck-result-all.txt"
        ;;
    unused)
        ensure_compile_commands
        if [[ "$ruta" == "$DEFAULT_ANALYSIS_PATH" ]]; then
            echo "Ejecutando cppcheck para unusedFunction en proyecto completo (usando $THREADS threads)"
            cppcheck --enable=style \
            -j$THREADS \
            --project="$COMPILE_COMMANDS" \
            --suppressions-list="$SUPPRESSIONS_FILE" \
            2>"$OUTPUT_DIR/cppcheck-result-unusedFunction.txt"
        else
            echo "Ejecutando cppcheck para unusedFunction en: $ruta (usando $THREADS threads)"
            cppcheck --enable=style $CPPCHECK_STD \
            -j$THREADS \
            -I "$INCLUDE_PATH" \
            --suppressions-list="$SUPPRESSIONS_FILE" \
            "$ruta" \
            2>"$OUTPUT_DIR/cppcheck-result-unusedFunction.txt"
        fi
        echo "Resultados guardados en: $OUTPUT_DIR/cppcheck-result-unusedFunction.txt"
        ;;
    *)
        echo "Error: Opción inválida"
        mostrar_uso
        exit 1
        ;;
esac
