#!/bin/bash
################################################################################
#  NEXUS Service Desk — Auditoría Completa de Sistema
#  Cliente  : Fedef — fedef.evolucionamos.com
#  Versión  : 1.0
#
#  EJECUCIÓN:
#    bash auditoria_nexus.sh 2>&1 | tee audit_resultado_$(date +%Y%m%d_%H%M%S).txt
#
#  SECCIONES:
#    1.  Entorno y configuración Laravel
#    2.  Seguridad
#    3.  Base de datos — integridad y estructura
#    4.  Usuarios, roles y permisos
#    5.  Tickets — estado operativo
#    6.  Notificaciones SMS
#    7.  SLA — configuración y cumplimiento
#    8.  Base de conocimiento
#    9.  Componentes Livewire
#    10. Rutas y controladores
#    11. Assets y vistas
#    12. API REST (Sanctum)
#    13. IA — clasificación y plantillas
#    14. Inventario
#    15. Logs y errores recientes
#    16. Rendimiento y optimización
#    17. Resumen ejecutivo + Backlog priorizado
################################################################################

set -uo pipefail

# ─── Colores ──────────────────────────────────────────────────────────────────
GRN="\033[0;32m"; RED="\033[0;31m"; YLW="\033[0;33m"
BLU="\033[0;34m"; CYN="\033[0;36m"; MAG="\033[0;35m"
RST="\033[0m";    BLD="\033[1m"

# ─── Contadores globales ───────────────────────────────────────────────────────
CRITICOS=0
ADVERTENCIAS=0
OKS=0
INFOS=0
declare -a BACKLOG_CRITICO=()
declare -a BACKLOG_MEDIO=()
declare -a BACKLOG_BAJO=()

# ─── Helpers ──────────────────────────────────────────────────────────────────
AUDIT_START=$(date +%s)

crit() {
    echo -e "${RED}${BLD}  [CRÍTICO]${RST}  $1"
    CRITICOS=$((CRITICOS+1))
    BACKLOG_CRITICO+=("$1")
}
warn() {
    echo -e "${YLW}${BLD}  [ADVERTENCIA]${RST} $1"
    ADVERTENCIAS=$((ADVERTENCIAS+1))
    BACKLOG_MEDIO+=("$1")
}
ok() {
    echo -e "${GRN}${BLD}  [OK]${RST}        $1"
    OKS=$((OKS+1))
}
info() {
    echo -e "${BLU}  [INFO]${RST}      $1"
    INFOS=$((INFOS+1))
}
low() {
    echo -e "${MAG}  [MEJORA]${RST}    $1"
    BACKLOG_BAJO+=("$1")
}
section() {
    echo ""
    echo -e "${CYN}${BLD}══════════════════════════════════════════════════════════════════${RST}"
    echo -e "${CYN}${BLD}  $1${RST}"
    echo -e "${CYN}${BLD}══════════════════════════════════════════════════════════════════${RST}"
}
subsection() {
    echo ""
    echo -e "${BLD}  ── $1 ──${RST}"
}

tinker() {
    php artisan tinker --execute="$1" 2>/dev/null | tr -d '\r'
}

################################################################################
echo ""
echo -e "${BLD}${CYN}"
echo "  ╔══════════════════════════════════════════════════════════════╗"
echo "  ║     NEXUS SERVICE DESK — AUDITORÍA COMPLETA DE SISTEMA      ║"
echo "  ║     Cliente: Fedef | $(date '+%Y-%m-%d %H:%M:%S')               ║"
echo "  ╚══════════════════════════════════════════════════════════════╝"
echo -e "${RST}"

[ ! -f "artisan" ] && { echo "ERROR: Ejecutar desde raíz de Laravel"; exit 1; }

################################################################################
section "1. ENTORNO Y CONFIGURACIÓN LARAVEL"
################################################################################

subsection "Versiones"
PHP_VER=$(php -r "echo PHP_VERSION;")
LARAVEL_VER=$(php artisan --version 2>/dev/null | grep -oP '\d+\.\d+\.\d+')
info "PHP versión        : $PHP_VER"
info "Laravel versión    : $LARAVEL_VER"
info "Directorio raíz    : $(pwd)"
info "Servidor           : $(hostname)"

subsection "Variables de entorno críticas"

check_env() {
    local KEY="$1" EXPECTED="$2" LABEL="$3"
    local VAL=$(grep "^${KEY}=" .env 2>/dev/null | cut -d'=' -f2-)
    if [ -z "$VAL" ]; then
        crit "$LABEL: no definido en .env"
    elif [ -n "$EXPECTED" ] && [ "$VAL" != "$EXPECTED" ]; then
        warn "$LABEL: valor='$VAL' (esperado='$EXPECTED')"
    else
        ok "$LABEL: $VAL"
    fi
}

check_env "APP_ENV"             "production"      "APP_ENV"
check_env "APP_DEBUG"           "false"           "APP_DEBUG"
check_env "APP_LOCALE"          "es"              "APP_LOCALE"
check_env "APP_TIMEZONE"        "America/Bogota"  "APP_TIMEZONE"
check_env "APP_KEY"             ""                "APP_KEY"

# Verificar que APP_KEY existe y tiene longitud correcta
APP_KEY=$(grep "^APP_KEY=" .env | cut -d'=' -f2-)
if [ ${#APP_KEY} -lt 40 ]; then
    crit "APP_KEY muy corta o vacía — regenerar con: php artisan key:generate"
else
    ok "APP_KEY tiene longitud correcta (${#APP_KEY} chars)"
fi

subsection "Archivos de configuración cacheados"
[ -f "bootstrap/cache/config.php" ] && ok "config.php cacheado" || warn "Config no cacheada — ejecutar: php artisan config:cache"
[ -f "bootstrap/cache/routes-v7.php" ] || [ -f "bootstrap/cache/routes.php" ] && ok "Routes cacheadas" || warn "Routes no cacheadas"

subsection "Extensiones PHP requeridas"
for EXT in pdo pdo_mysql mbstring openssl tokenizer xml ctype json bcmath; do
    php -r "echo extension_loaded('$EXT') ? 'OK' : 'MISSING';" 2>/dev/null | grep -q "OK" \
        && ok "ext-$EXT cargada" \
        || crit "ext-$EXT NO está cargada"
done

################################################################################
section "2. SEGURIDAD"
################################################################################

subsection "Configuración de seguridad"

# APP_DEBUG en producción
DEBUG=$(grep "^APP_DEBUG=" .env | cut -d'=' -f2)
[ "$DEBUG" = "false" ] && ok "APP_DEBUG=false (producción segura)" || crit "APP_DEBUG=true en producción — expone stack traces a usuarios"

# .env accesible vía web
subsection "Archivos sensibles"
[ -f "public/.env" ] && crit "public/.env accesible — eliminar inmediatamente" || ok "public/.env no existe"
[ -f "public/phpinfo.php" ] && crit "public/phpinfo.php expuesto — eliminar" || ok "phpinfo.php no expuesto"
[ -f ".env.backup" ] && warn ".env.backup en raíz — considerar eliminar" || ok "Sin backups de .env expuestos"

subsection "Permisos de archivos"
STORAGE_PERM=$(stat -c "%a" storage/ 2>/dev/null)
BOOTSTRAP_PERM=$(stat -c "%a" bootstrap/cache/ 2>/dev/null)
[ "$STORAGE_PERM" = "775" ] || [ "$STORAGE_PERM" = "755" ] && ok "storage/ permisos: $STORAGE_PERM" || warn "storage/ permisos: $STORAGE_PERM (recomendado: 775)"
[ "$BOOTSTRAP_PERM" = "775" ] || [ "$BOOTSTRAP_PERM" = "755" ] && ok "bootstrap/cache/ permisos: $BOOTSTRAP_PERM" || warn "bootstrap/cache/ permisos: $BOOTSTRAP_PERM"

subsection "CSRF y autenticación"
grep -r "VerifyCsrfToken\|csrf" app/Http/Middleware/ &>/dev/null && ok "Middleware CSRF presente" || warn "No se encontró middleware CSRF"
grep -r "Sanctum\|sanctum" config/ &>/dev/null && ok "Laravel Sanctum configurado (API)" || info "Sanctum no detectado en config"

subsection "Contraseñas de usuarios"
DEFAULT_PASS=$(tinker "echo App\Models\User::all()->filter(fn(\$u) => Hash::check(\$u->document_number ?? '123456', \$u->password))->count();")
info "Usuarios con contraseña = documento (estimado): verificar manualmente"

subsection "HTTPS"
APP_URL=$(grep "^APP_URL=" .env | cut -d'=' -f2-)
echo "$APP_URL" | grep -q "https://" && ok "APP_URL usa HTTPS: $APP_URL" || warn "APP_URL sin HTTPS: $APP_URL"

subsection "Rate limiting"
grep -r "throttle\|RateLimiter" routes/ app/Http/ &>/dev/null && ok "Rate limiting configurado en rutas" || warn "Sin rate limiting explícito en rutas de API/auth"

################################################################################
section "3. BASE DE DATOS — INTEGRIDAD Y ESTRUCTURA"
################################################################################

subsection "Conexión y configuración"
DB_CON=$(tinker "try { DB::connection()->getPdo(); echo 'OK'; } catch(\Exception \$e) { echo 'ERROR: '.\$e->getMessage(); }")
echo "$DB_CON" | grep -q "^OK" && ok "Conexión a BD: OK" || crit "Conexión a BD fallida: $DB_CON"

DB_NAME=$(grep "^DB_DATABASE=" .env | cut -d'=' -f2)
info "Base de datos: $DB_NAME"

subsection "Tablas principales"
EXPECTED_TABLES=("users" "tickets" "ticket_statuses" "ticket_priorities" "ticket_categories"
                 "departments" "roles" "model_has_roles" "reply_templates"
                 "automation_rules" "assets" "kb_articles" "sessions" "jobs")

for TABLE in "${EXPECTED_TABLES[@]}"; do
    EXISTS=$(tinker "echo Schema::hasTable('$TABLE') ? 'SI' : 'NO';")
    [ "$EXISTS" = "SI" ] && ok "Tabla '$TABLE': existe" || crit "Tabla '$TABLE': NO EXISTE"
done

subsection "Integridad referencial — tickets"
ORPHAN_STATUS=$(tinker "echo DB::select('SELECT COUNT(*) as c FROM tickets t LEFT JOIN ticket_statuses s ON t.status_id=s.id WHERE s.id IS NULL')[0]->c;")
ORPHAN_PRIORITY=$(tinker "echo DB::select('SELECT COUNT(*) as c FROM tickets t LEFT JOIN ticket_priorities p ON t.priority_id=p.id WHERE p.id IS NULL')[0]->c;")
[ "$ORPHAN_STATUS" = "0" ] && ok "Sin tickets con status_id huérfano" || crit "$ORPHAN_STATUS tickets con status_id sin referencia"
[ "$ORPHAN_PRIORITY" = "0" ] && ok "Sin tickets con priority_id huérfano" || crit "$ORPHAN_PRIORITY tickets con priority_id sin referencia"

subsection "Soft-deletes — tickets eliminados"
SOFT_DELETED=$(tinker "echo DB::table('tickets')->whereNotNull('deleted_at')->count();")
info "Tickets con soft-delete (eliminados): $SOFT_DELETED"

subsection "Migraciones pendientes"
PENDING=$(php artisan migrate:status 2>/dev/null | grep "Pending\| N " | wc -l)
[ "$PENDING" -eq 0 ] && ok "Sin migraciones pendientes" || warn "$PENDING migraciones pendientes — ejecutar: php artisan migrate"

subsection "Jobs fallidos"
FAILED_JOBS=$(tinker "echo Schema::hasTable('failed_jobs') ? DB::table('failed_jobs')->count() : 0;")
[ "$FAILED_JOBS" = "0" ] && ok "Sin jobs fallidos en cola" || warn "$FAILED_JOBS jobs fallidos — revisar: php artisan queue:failed"

################################################################################
section "4. USUARIOS, ROLES Y PERMISOS"
################################################################################

subsection "Conteo de usuarios"
TOTAL_USERS=$(tinker "echo App\Models\User::count();")
ACTIVE_USERS=$(tinker "echo App\Models\User::where('is_active',1)->count();")
INACTIVE_USERS=$(tinker "echo App\Models\User::where('is_active',0)->count();")
info "Total usuarios     : $TOTAL_USERS"
info "Activos            : $ACTIVE_USERS"
info "Inactivos          : $INACTIVE_USERS"

subsection "Distribución de roles"
ROLES=$(tinker "
\$roles = DB::table('roles')->get();
foreach(\$roles as \$r) {
    \$count = DB::table('model_has_roles')->where('role_id',\$r->id)->count();
    echo \$r->name . ': ' . \$count . PHP_EOL;
}
")
info "Roles y usuarios:"
echo "$ROLES" | while read line; do info "  $line"; done

subsection "Usuarios sin rol asignado"
NO_ROLE=$(tinker "echo App\Models\User::doesntHave('roles')->count();")
[ "$NO_ROLE" = "0" ] && ok "Todos los usuarios tienen rol asignado" || warn "$NO_ROLE usuarios sin rol — pueden tener acceso limitado"

subsection "Superadmins registrados"
SUPERADMINS=$(tinker "echo App\Models\User::role('superadmin')->count();")
info "Superadmins: $SUPERADMINS"
[ "$SUPERADMINS" -gt 3 ] && warn "Muchos superadmins ($SUPERADMINS) — revisar si todos son necesarios"

subsection "Usuarios con email duplicado"
DUP_EMAIL=$(tinker "echo DB::select('SELECT email, COUNT(*) as c FROM users GROUP BY email HAVING c > 1')[0]->c ?? 0;" 2>/dev/null || echo "0")
[ "$DUP_EMAIL" = "0" ] && ok "Sin emails duplicados" || crit "Emails duplicados detectados"

################################################################################
section "5. TICKETS — ESTADO OPERATIVO"
################################################################################

subsection "Volumen y estados"
TOTAL_TICKETS=$(tinker "echo App\Models\Ticket::withTrashed()->count();")
OPEN_TICKETS=$(tinker "echo App\Models\Ticket::count();")
info "Total tickets (incluye eliminados): $TOTAL_TICKETS"
info "Tickets activos (sin soft-delete) : $OPEN_TICKETS"

STATUSES=$(tinker "
\$statuses = App\Models\TicketStatus::withCount('tickets')->get();
foreach(\$statuses as \$s) {
    echo \$s->name . ': ' . \$s->tickets_count . PHP_EOL;
}
")
info "Distribución por estado:"
echo "$STATUSES" | while read line; do [ -n "$line" ] && info "  $line"; done

subsection "Tickets sin asignar"
UNASSIGNED=$(tinker "echo App\Models\Ticket::whereNull('assignee_id')->count();")
info "Tickets sin asignar: $UNASSIGNED"
[ "$UNASSIGNED" -gt 20 ] && warn "$UNASSIGNED tickets sin asignar — revisar asignación automática"

subsection "Tickets con SLA vencido"
SLA_BREACHED=$(tinker "echo App\Models\Ticket::where('sla_resolution_breached',1)->count();")
info "Tickets con SLA de resolución vencido: $SLA_BREACHED"
[ "$SLA_BREACHED" -gt 10 ] && warn "$SLA_BREACHED tickets con SLA vencido — requiere atención"

subsection "Scopes del modelo Ticket"
TICKET_SCOPES=$(grep -o "public function scope[A-Za-z]*" app/Models/Ticket.php 2>/dev/null | sed 's/public function scope//')
info "Scopes disponibles en Ticket: $TICKET_SCOPES"

subsection "Tickets críticos sin atender"
CRITICOS_TKT=$(tinker "
\$c = App\Models\Ticket::whereHas('priority', fn(\$q) => \$q->where('level',4))
    ->whereHas('status', fn(\$q) => \$q->where('name','Nuevo'))
    ->count();
echo \$c;
")
info "Tickets CRÍTICOS en estado Nuevo: $CRITICOS_TKT"
[ "$CRITICOS_TKT" -gt 0 ] && warn "$CRITICOS_TKT tickets críticos sin atender"

################################################################################
section "6. NOTIFICACIONES SMS (HÁBLAME)"
################################################################################

subsection "Configuración API Háblame"
HABLAME_USER=$(grep "HABLAME_USER\|SMS_USER\|HABLAME" .env | head -3)
[ -n "$HABLAME_USER" ] && ok "Variables Háblame presentes en .env" || warn "Variables de Háblame no encontradas en .env"

SMS_SERVICE=$(find app/Services -iname "*sms*" -o -iname "*hablame*" -o -iname "*Sms*" 2>/dev/null | head -3)
[ -n "$SMS_SERVICE" ] && ok "Servicio SMS encontrado: $SMS_SERVICE" || warn "No se encontró clase de servicio SMS"

subsection "Email — estado"
MAIL_MAILER=$(grep "^MAIL_MAILER=" .env | cut -d'=' -f2)
info "MAIL_MAILER: $MAIL_MAILER"
[ "$MAIL_MAILER" = "log" ] && warn "Email en modo 'log' — notificaciones por email NO se envían (pendiente migración de servidor)" \
                            || info "Email mailer: $MAIL_MAILER"

################################################################################
section "7. SLA — CONFIGURACIÓN Y CUMPLIMIENTO"
################################################################################

subsection "Prioridades y tiempos de SLA"
SLA_CONFIG=$(tinker "
\$priorities = App\Models\TicketPriority::orderBy('level')->get();
foreach(\$priorities as \$p) {
    echo \$p->name . ' (nivel '.\$p->level.'): respuesta='.\$p->response_time.'h, resolución='.\$p->resolution_time.'h' . PHP_EOL;
}
" 2>/dev/null)
if [ -n "$SLA_CONFIG" ]; then
    ok "Prioridades SLA configuradas:"
    echo "$SLA_CONFIG" | while read line; do [ -n "$line" ] && info "  $line"; done
else
    warn "No se pudo leer configuración de SLA — verificar modelo TicketPriority"
fi

subsection "Automatización SLA"
SLA_AUTO=$(tinker "echo App\Models\AutomationRule::where('trigger','sla_breached')->count();")
info "Reglas de automatización para SLA vencido: $SLA_AUTO"
[ "$SLA_AUTO" = "0" ] && warn "Sin automatización de escalado por SLA" || ok "Automatización SLA activa"

################################################################################
section "8. BASE DE CONOCIMIENTO"
################################################################################

KB_TABLE=$(tinker "echo Schema::hasTable('kb_articles') ? 'SI' : 'NO';")
if [ "$KB_TABLE" = "SI" ]; then
    KB_TOTAL=$(tinker "echo DB::table('kb_articles')->count();")
    KB_PUB=$(tinker "echo DB::table('kb_articles')->where('published',1)->count();" 2>/dev/null || \
             tinker "echo DB::table('kb_articles')->where('status','published')->count();" 2>/dev/null || echo "?")
    info "Artículos KB total     : $KB_TOTAL"
    info "Artículos publicados   : $KB_PUB"
    [ "$KB_TOTAL" = "0" ] && warn "Base de conocimiento vacía — poblar para mejorar autoservicio"
else
    warn "Tabla kb_articles no encontrada"
fi

################################################################################
section "9. COMPONENTES LIVEWIRE"
################################################################################

subsection "Inventario de componentes"
LW_COMPONENTS=$(find app/Livewire -name "*.php" 2>/dev/null)
LW_COUNT=$(echo "$LW_COMPONENTS" | wc -l)
info "Componentes Livewire encontrados: $LW_COUNT"
echo "$LW_COMPONENTS" | while read f; do [ -n "$f" ] && info "  $f"; done

subsection "Alpine.js — instancias duplicadas"
ALPINE_IN_LAYOUTS=$(grep -rn "alpinejs" resources/views/layouts/ 2>/dev/null | wc -l)
[ "$ALPINE_IN_LAYOUTS" = "0" ] && ok "Sin Alpine.js duplicado en layouts (fix aplicado)" \
                                 || crit "Alpine.js aún cargado $ALPINE_IN_LAYOUTS vez/veces en layouts — conflicto con Livewire v3"

subsection "wire:model en formularios críticos"
grep -r "wire:model\.blur\|wire:model\.live\|wire:model\.defer" resources/views/livewire/ &>/dev/null \
    && ok "wire:model con modificadores usados correctamente" \
    || warn "Revisar wire:model sin modificadores — puede causar problemas en móvil"

################################################################################
section "10. RUTAS Y CONTROLADORES"
################################################################################

subsection "Total de rutas registradas"
ROUTE_COUNT=$(php artisan route:list 2>/dev/null | wc -l)
info "Rutas registradas: $ROUTE_COUNT"

subsection "Rutas duplicadas"
DUP_ROUTES=$(php artisan route:list --json 2>/dev/null | python3 -c "
import json,sys
try:
    routes = json.load(sys.stdin)
    names = [r.get('name','') for r in routes if r.get('name')]
    from collections import Counter
    dups = [n for n,c in Counter(names).items() if c > 1 and n]
    print(len(dups))
    for d in dups[:5]: print('  DUP:', d)
except: print('0')
" 2>/dev/null)
DUP_COUNT=$(echo "$DUP_ROUTES" | head -1)
[ "$DUP_COUNT" = "0" ] && ok "Sin rutas con nombre duplicado" || crit "Rutas duplicadas detectadas: $DUP_ROUTES"

subsection "Controladores existentes"
CTRL_COUNT=$(find app/Http/Controllers -name "*.php" | wc -l)
info "Controladores: $CTRL_COUNT"

subsection "Middleware personalizado"
MW_CUSTOM=$(find app/Http/Middleware -name "*.php" 2>/dev/null)
echo "$MW_CUSTOM" | while read f; do [ -n "$f" ] && info "  Middleware: $(basename $f)"; done

################################################################################
section "11. ASSETS Y VISTAS"
################################################################################

subsection "Tailwind CSS"
TAILWIND_CDN=$(grep -rn "cdn.tailwindcss.com" resources/views/layouts/ 2>/dev/null | wc -l)
[ "$TAILWIND_CDN" -gt 0 ] && warn "Tailwind vía CDN en $TAILWIND_CDN layout(s) — usar build local en producción para mejor rendimiento" \
                            || ok "Sin Tailwind CDN en layouts"

subsection "Vistas de error personalizadas"
for CODE in 403 404 500 503; do
    [ -f "resources/views/errors/${CODE}.blade.php" ] \
        && ok "Vista de error $CODE personalizada" \
        || low "Vista de error $CODE sin personalizar (usa la de Laravel por defecto)"
done

subsection "Layouts principales"
for LAYOUT in app guest login-full portal; do
    [ -f "resources/views/layouts/${LAYOUT}.blade.php" ] \
        && ok "Layout '$LAYOUT' existe" \
        || warn "Layout '$LAYOUT' no encontrado"
done

subsection "Archivos de idioma"
for LANG_FILE in validation auth passwords; do
    [ -f "lang/es/${LANG_FILE}.php" ] \
        && ok "lang/es/${LANG_FILE}.php presente" \
        || crit "lang/es/${LANG_FILE}.php FALTANTE — mensajes en inglés"
done

################################################################################
section "12. API REST (SANCTUM)"
################################################################################

subsection "Configuración Sanctum"
[ -f "config/sanctum.php" ] && ok "config/sanctum.php presente" || warn "Sanctum no configurado"

subsection "Rutas API"
API_ROUTES=$(php artisan route:list 2>/dev/null | grep "api/" | wc -l)
info "Rutas bajo /api/: $API_ROUTES"

subsection "Documentación API"
[ -f "public/api-docs" ] || [ -d "public/api-docs" ] || \
php artisan route:list 2>/dev/null | grep -q "api/docs\|api-docs" \
    && ok "Documentación API accesible" \
    || low "Sin documentación API pública detectada — revisar /api/docs"

subsection "Rate limiting en API"
grep -r "throttle" routes/api.php &>/dev/null && ok "Rate limiting en routes/api.php" || warn "Sin throttle explícito en API"

################################################################################
section "13. IA — CLASIFICACIÓN Y PLANTILLAS"
################################################################################

subsection "Modelos y tablas IA"
AI_TABLES=("ai_response_templates")
for T in "${AI_TABLES[@]}"; do
    EXISTS=$(tinker "echo Schema::hasTable('$T') ? 'SI' : 'NO';")
    [ "$EXISTS" = "SI" ] && ok "Tabla '$T': existe" || info "Tabla '$T': no existe"
done

AI_TEMPLATE_COUNT=$(tinker "echo Schema::hasTable('ai_response_templates') ? DB::table('ai_response_templates')->count() : 0;")
info "Plantillas IA: $AI_TEMPLATE_COUNT"

subsection "Vistas IA"
AI_VIEWS=$(find resources/views/ai -name "*.blade.php" 2>/dev/null)
AI_VIEW_COUNT=$(echo "$AI_VIEWS" | grep -c "." || echo 0)
info "Vistas en /ai: $AI_VIEW_COUNT"

subsection "Bug constantes bare en vistas IA"
AI_CONSTANTS=$(grep -rn "{{[^{$]" resources/views/ai/ 2>/dev/null | grep -v "@{{\|'{{" | wc -l)
[ "$AI_CONSTANTS" = "0" ] && ok "Sin constantes PHP bare en vistas /ai" \
                           || warn "$AI_CONSTANTS posibles constantes bare en /ai — revisar"

################################################################################
section "14. INVENTARIO"
################################################################################

ASSET_TABLE=$(tinker "echo Schema::hasTable('assets') ? 'SI' : 'NO';")
if [ "$ASSET_TABLE" = "SI" ]; then
    ASSET_COUNT=$(tinker "echo DB::table('assets')->count();")
    info "Activos de inventario registrados: $ASSET_COUNT"
    [ "$ASSET_COUNT" = "0" ] && low "Inventario vacío — pendiente carga masiva de activos Fedef"

    LW_ASSET=$(find app/Livewire -iname "*asset*" 2>/dev/null | head -1)
    [ -n "$LW_ASSET" ] && ok "Componente Livewire de inventario: $LW_ASSET" \
                        || warn "No se encontró componente Livewire para inventario"
else
    crit "Tabla 'assets' no existe"
fi

################################################################################
section "15. LOGS Y ERRORES RECIENTES"
################################################################################

subsection "Tamaño del log"
if [ -f "storage/logs/laravel.log" ]; then
    LOG_SIZE=$(du -sh storage/logs/laravel.log | cut -f1)
    LOG_LINES=$(wc -l < storage/logs/laravel.log)
    info "laravel.log: $LOG_SIZE ($LOG_LINES líneas)"
    [ "$LOG_LINES" -gt 50000 ] && warn "Log muy grande ($LOG_LINES líneas) — considerar rotación"

    subsection "Errores críticos en las últimas 24h"
    RECENT_ERRORS=$(grep "production.ERROR" storage/logs/laravel.log | tail -100 | wc -l)
    info "Errores recientes en log (últimas 100 líneas del log): $RECENT_ERRORS"

    subsection "Tipos de errores más frecuentes"
    grep "production.ERROR" storage/logs/laravel.log | \
        grep -oP '(?<=ERROR: )[^\{]+' | \
        sort | uniq -c | sort -rn | head -5 | \
        while read line; do warn "  $line"; done

    subsection "Últimos 5 errores"
    grep "production.ERROR\|production.CRITICAL" storage/logs/laravel.log | \
        tail -5 | while read line; do
        SHORT=$(echo "$line" | cut -c1-120)
        info "  $SHORT"
    done
else
    info "No se encontró storage/logs/laravel.log"
fi

################################################################################
section "16. RENDIMIENTO Y OPTIMIZACIÓN"
################################################################################

subsection "Caché de configuración"
[ -f "bootstrap/cache/config.php" ] && ok "Config cacheada" || warn "Config no cacheada — php artisan config:cache"
[ -f "bootstrap/cache/routes-v7.php" ] || [ -f "bootstrap/cache/routes.php" ] \
    && ok "Routes cacheadas" || warn "Routes no cacheadas — php artisan route:cache"

subsection "Índices de base de datos — columnas de filtro frecuente"
python3 << 'PYEOF'
import subprocess

checks = [
    ("tickets", "status_id"),
    ("tickets", "priority_id"),
    ("tickets", "requester_id"),
    ("tickets", "assignee_id"),
    ("tickets", "created_at"),
    ("users",   "is_active"),
    ("users",   "email"),
]

for table, col in checks:
    result = subprocess.run(
        ['php', 'artisan', 'tinker', '--execute',
         f"$r=DB::select('SHOW INDEX FROM {table} WHERE Column_name = ?',['{col}']);echo count($r)>0?'SI':'NO';"],
        capture_output=True, text=True
    )
    has_index = result.stdout.strip() == 'SI'
    symbol = '  [OK]       ' if has_index else '  [MEJORA]   '
    status = 'índice presente' if has_index else 'SIN índice — considerar agregar para mejor rendimiento'
    print(f"{symbol}{table}.{col}: {status}")
PYEOF

subsection "Opcache"
php -r "echo opcache_get_status() ? 'ACTIVO' : 'INACTIVO';" 2>/dev/null | grep -q "ACTIVO" \
    && ok "OPcache activo" || warn "OPcache inactivo — activar en php.ini para mejor rendimiento"

subsection "Queue driver"
QUEUE_DRIVER=$(grep "^QUEUE_CONNECTION=" .env | cut -d'=' -f2)
info "Queue driver: $QUEUE_DRIVER"
[ "$QUEUE_DRIVER" = "sync" ] && warn "Queue en modo 'sync' — jobs pesados bloquean requests. Considerar 'database' o 'redis'" \
                              || ok "Queue driver: $QUEUE_DRIVER"

subsection "Session driver"
SESSION_DRIVER=$(grep "^SESSION_DRIVER=" .env | cut -d'=' -f2)
info "Session driver: $SESSION_DRIVER"

subsection "Tamaño del proyecto"
DU_VENDOR=$(du -sh vendor/ 2>/dev/null | cut -f1)
DU_STORAGE=$(du -sh storage/ 2>/dev/null | cut -f1)
DU_PUBLIC=$(du -sh public/ 2>/dev/null | cut -f1)
info "vendor/  : $DU_VENDOR"
info "storage/ : $DU_STORAGE"
info "public/  : $DU_PUBLIC"

################################################################################
section "17. RESUMEN EJECUTIVO"
################################################################################

AUDIT_END=$(date +%s)
DURATION=$((AUDIT_END - AUDIT_START))

echo ""
echo -e "${BLD}${CYN}╔══════════════════════════════════════════════════════════════════╗${RST}"
echo -e "${BLD}${CYN}║           NEXUS SERVICE DESK — DICTAMEN DE AUDITORÍA             ║${RST}"
echo -e "${BLD}${CYN}╠══════════════════════════════════════════════════════════════════╣${RST}"
echo -e "${BLD}${CYN}║${RST}  Fecha auditoría : $(date '+%Y-%m-%d %H:%M:%S')"
echo -e "${BLD}${CYN}║${RST}  Duración        : ${DURATION}s"
echo -e "${BLD}${CYN}║${RST}  Directorio      : $(pwd)"
echo -e "${BLD}${CYN}╠══════════════════════════════════════════════════════════════════╣${RST}"
echo -e "${BLD}${CYN}║  RESULTADO DE CONTROLES:${RST}"
echo -e "${BLD}${CYN}║${RST}  ${GRN}${BLD}✓ OK           : $OKS${RST}"
echo -e "${BLD}${CYN}║${RST}  ${RED}${BLD}✗ CRÍTICOS     : $CRITICOS${RST}"
echo -e "${BLD}${CYN}║${RST}  ${YLW}${BLD}! ADVERTENCIAS : $ADVERTENCIAS${RST}"
echo -e "${BLD}${CYN}║${RST}  ${MAG}  MEJORAS      : ${#BACKLOG_BAJO[@]}${RST}"
echo -e "${BLD}${CYN}╠══════════════════════════════════════════════════════════════════╣${RST}"

# Dictamen
if [ "$CRITICOS" -eq 0 ]; then
    echo -e "${BLD}${CYN}║${RST}  ${GRN}${BLD}DICTAMEN: APTO PARA PRODUCCIÓN ✓${RST}"
    echo -e "${BLD}${CYN}║${RST}  El sistema cumple los requisitos mínimos de MVP."
elif [ "$CRITICOS" -le 2 ]; then
    echo -e "${BLD}${CYN}║${RST}  ${YLW}${BLD}DICTAMEN: APTO CON OBSERVACIONES${RST}"
    echo -e "${BLD}${CYN}║${RST}  Resolver issues críticos antes del lanzamiento masivo."
else
    echo -e "${BLD}${CYN}║${RST}  ${RED}${BLD}DICTAMEN: REQUIERE ATENCIÓN ANTES DE PRODUCCIÓN${RST}"
    echo -e "${BLD}${CYN}║${RST}  Hay $CRITICOS issues críticos pendientes."
fi

echo -e "${BLD}${CYN}╠══════════════════════════════════════════════════════════════════╣${RST}"
echo -e "${BLD}${CYN}║  BACKLOG PRIORIZADO:${RST}"

if [ "${#BACKLOG_CRITICO[@]}" -gt 0 ]; then
    echo -e "${BLD}${CYN}║${RST}  ${RED}${BLD}── CRÍTICO (resolver antes de producción):${RST}"
    for item in "${BACKLOG_CRITICO[@]}"; do
        echo -e "${BLD}${CYN}║${RST}    ${RED}•${RST} $item"
    done
fi

if [ "${#BACKLOG_MEDIO[@]}" -gt 0 ]; then
    echo -e "${BLD}${CYN}║${RST}  ${YLW}${BLD}── SPRINT PRÓXIMO (advertencias):${RST}"
    for item in "${BACKLOG_MEDIO[@]}"; do
        echo -e "${BLD}${CYN}║${RST}    ${YLW}•${RST} $item"
    done
fi

if [ "${#BACKLOG_BAJO[@]}" -gt 0 ]; then
    echo -e "${BLD}${CYN}║${RST}  ${MAG}${BLD}── BACKLOG FUTURO (mejoras):${RST}"
    for item in "${BACKLOG_BAJO[@]}"; do
        echo -e "${BLD}${CYN}║${RST}    ${MAG}•${RST} $item"
    done
fi

echo -e "${BLD}${CYN}╚══════════════════════════════════════════════════════════════════╝${RST}"
echo ""
echo -e "${BLU}  Este informe ha sido guardado en el archivo .txt especificado.${RST}"
echo -e "${BLU}  Compartir con el equipo para revisión del backlog.${RST}"
echo ""
