<?php
/**
 * CORRECTOR DE ACL (PERMISOS) - SUBDOMINIOS SIE
 * ===============================================
 * Verifica y corrige conf/acl.auth.php de todos los subdominios DokuWiki.
 * Asegura que existan las 5 reglas minimas del sistema SIE.
 *
 * SIN las reglas minimas, DokuWiki muestra "No ACL setup yet! Denying access to everyone."
 * y los usuarios no pueden acceder a archivos ni paginas.
 *
 * REGLAS MINIMAS:
 *   *               @ALL            0       (denegar acceso anonimo)
 *   *               @sie            16      (grupo SIE - permisos totales)
 *   *               @lectura        8       (grupo lectura - upload)
 *   *               @editartareas   2       (grupo editartareas - edicion)
 *   @lidertareas    :task           coordinator
 *
 * MODOS:
 *   ?modo=escanear   (default) - Solo detectar, no modificar nada
 *   ?modo=corregir              - Agregar reglas faltantes a TODOS los afectados
 *   ?sub=nombre                 - Verificar/corregir uno solo
 *
 * SEGURIDAD:
 *   Crea backup acl.auth.php.bak_acl_* antes de modificar.
 *   Solo AGREGA reglas faltantes, NUNCA elimina reglas existentes.
 */

// =====================================================================
//  CONFIGURACION
// =====================================================================

$basePath = '/home/systeng3/public_html';

$excluir = ['.', '..', 'cgi-bin', '.well-known', '.trash', '.htaccess',
            'respaldo', 'diagnosticos', 'tmp', 'error_log'];

// Reglas minimas que DEBEN existir en todo sistema SIE
// Formato: [patron_regex_para_buscar, linea_completa_para_agregar, descripcion]
$reglasMinimas = [
    [
        'patron'      => '/^\*\s+@ALL\s+\d+/m',
        'linea'       => "*\t\t@ALL\t\t0",
        'descripcion' => '* @ALL 0 — Denegar acceso anonimo',
    ],
    [
        'patron'      => '/^\*\s+@sie\s+\d+/m',
        'linea'       => "*\t\t@sie\t\t16",
        'descripcion' => '* @sie 16 — Grupo SIE permisos totales',
    ],
    [
        'patron'      => '/^\*\s+@lectura\s+\d+/m',
        'linea'       => "*\t\t@lectura\t\t8",
        'descripcion' => '* @lectura 8 — Grupo lectura con upload',
    ],
    [
        'patron'      => '/^\*\s+@editartareas\s+\d+/m',
        'linea'       => "*\t\t@editartareas\t\t2",
        'descripcion' => '* @editartareas 2 — Grupo edicion de tareas',
    ],
    [
        'patron'      => '/@lidertareas\s+:task\s+coordinator/m',
        'linea'       => "@lidertareas\t\t:task\t\tcoordinator",
        'descripcion' => '@lidertareas :task coordinator — Coordinador de tareas',
    ],
];

// =====================================================================
//  PARAMETROS
// =====================================================================

$esCLI = (php_sapi_name() === 'cli');

if (!$esCLI) {
    header('Content-Type: text/html; charset=UTF-8');
}

$modo      = $esCLI ? ($argv[1] ?? 'escanear') : ($_GET['modo'] ?? 'escanear');
$targetSub = $esCLI ? ($argv[2] ?? '')          : ($_GET['sub'] ?? '');

if (!empty($targetSub)) {
    if (preg_match('#^https?://#i', $targetSub)) {
        $parsed = parse_url($targetSub);
        if (isset($parsed['host'])) {
            $parts = explode('.', $parsed['host']);
            $targetSub = $parts[0];
        }
    }
    $targetSub = basename(preg_replace('/[^a-zA-Z0-9._-]/', '', $targetSub));
}

// =====================================================================
//  FUNCIONES DE ANALISIS
// =====================================================================

/**
 * Analiza el archivo acl.auth.php de un subdominio
 * Retorna info de que reglas existen y cuales faltan
 */
function analizarACL($subPath, $carpeta)
{
    global $reglasMinimas;

    $r = [
        'carpeta'       => $carpeta,
        'tiene_doku'    => false,
        'tiene_acl'     => false,
        'reglas_ok'     => [],
        'reglas_faltan' => [],
        'total_lineas'  => 0,
        'estado'        => 'NO_DOKU',
        'problema'      => '',
    ];

    if (!file_exists($subPath . '/doku.php')) return $r;
    $r['tiene_doku'] = true;

    $aclFile = $subPath . '/conf/acl.auth.php';

    if (!file_exists($aclFile)) {
        $r['estado'] = 'SIN_ACL';
        $r['problema'] = 'No existe conf/acl.auth.php';
        $r['reglas_faltan'] = array_column($reglasMinimas, 'descripcion');
        return $r;
    }

    $content = @file_get_contents($aclFile);
    if ($content === false) {
        $r['estado'] = 'ERROR';
        $r['problema'] = 'No se puede leer conf/acl.auth.php';
        return $r;
    }

    $r['tiene_acl'] = true;

    // Contar lineas no vacias y no comentarios
    $lineas = explode("\n", $content);
    $r['total_lineas'] = count(array_filter($lineas, function($l) {
        $l = trim($l);
        return $l !== '' && $l[0] !== '#';
    }));

    // Verificar cada regla minima
    foreach ($reglasMinimas as $regla) {
        if (preg_match($regla['patron'], $content)) {
            $r['reglas_ok'][] = $regla['descripcion'];
        } else {
            $r['reglas_faltan'][] = $regla['descripcion'];
        }
    }

    if (empty($r['reglas_faltan'])) {
        $r['estado'] = 'OK';
    } elseif (count($r['reglas_faltan']) === count($reglasMinimas)) {
        $r['estado'] = 'SIN_REGLAS';
        $r['problema'] = 'Ninguna regla minima encontrada';
    } else {
        $r['estado'] = 'INCOMPLETO';
        $r['problema'] = count($r['reglas_faltan']) . ' regla(s) faltante(s)';
    }

    return $r;
}

/**
 * Corrige acl.auth.php agregando las reglas faltantes
 * SOLO agrega, NUNCA elimina reglas existentes
 */
function corregirACL($subPath, $carpeta, $reglasFaltan)
{
    global $reglasMinimas;

    $aclFile = $subPath . '/conf/acl.auth.php';
    $confDir = $subPath . '/conf';

    // Si no existe el directorio conf, no podemos hacer nada
    if (!is_dir($confDir)) {
        return ['ok' => false, 'msg' => 'No existe directorio conf/'];
    }

    // Si no existe el archivo, crearlo con header y todas las reglas
    if (!file_exists($aclFile)) {
        $content = "# acl.auth.php\n";
        $content .= "# Auto-generado por corregir_acl.php - " . date('Y-m-d H:i:s') . "\n";
        $content .= "#\n";
        foreach ($reglasMinimas as $regla) {
            $content .= $regla['linea'] . "\n";
        }

        if (@file_put_contents($aclFile, $content) === false) {
            return ['ok' => false, 'msg' => 'No se pudo crear acl.auth.php'];
        }
        return ['ok' => true, 'msg' => 'Archivo creado con ' . count($reglasMinimas) . ' reglas', 'creado' => true];
    }

    // Leer contenido actual
    $content = @file_get_contents($aclFile);
    if ($content === false) {
        return ['ok' => false, 'msg' => 'No se puede leer acl.auth.php'];
    }

    // Crear backup con timestamp
    $timestamp = date('Ymd_His');
    $backupName = "acl.auth.php.bak_acl_{$timestamp}";
    $backupPath = $confDir . '/' . $backupName;
    if (!@copy($aclFile, $backupPath)) {
        return ['ok' => false, 'msg' => 'No se pudo crear backup'];
    }

    // Determinar que lineas agregar
    $lineasAgregar = [];
    foreach ($reglasMinimas as $regla) {
        // Solo agregar si esta en la lista de faltantes
        $falta = false;
        foreach ($reglasFaltan as $desc) {
            if ($desc === $regla['descripcion']) {
                $falta = true;
                break;
            }
        }
        if ($falta) {
            $lineasAgregar[] = $regla['linea'];
        }
    }

    if (empty($lineasAgregar)) {
        @unlink($backupPath);
        return ['ok' => false, 'msg' => 'Sin cambios necesarios'];
    }

    // Asegurar que el contenido termina con newline
    if (substr($content, -1) !== "\n") {
        $content .= "\n";
    }

    // Agregar comentario y reglas al INICIO del archivo (despues de headers)
    // Buscar la posicion despues de los comentarios iniciales
    $lineas = explode("\n", $content);
    $insertPos = 0;

    // Encontrar donde terminan los comentarios del header
    for ($i = 0; $i < count($lineas); $i++) {
        $l = trim($lineas[$i]);
        if ($l === '' || $l[0] === '#') {
            $insertPos = $i + 1;
        } else {
            break;
        }
    }

    // Insertar las reglas faltantes despues de los comentarios
    $nuevasLineas = ["# Reglas minimas SIE (agregadas " . date('Y-m-d H:i:s') . ")"];
    foreach ($lineasAgregar as $linea) {
        $nuevasLineas[] = $linea;
    }

    array_splice($lineas, $insertPos, 0, $nuevasLineas);
    $nuevoContent = implode("\n", $lineas);

    if (@file_put_contents($aclFile, $nuevoContent) === false) {
        @copy($backupPath, $aclFile); // Restaurar si falla
        return ['ok' => false, 'msg' => 'No se pudo escribir acl.auth.php'];
    }

    return [
        'ok'       => true,
        'msg'      => count($lineasAgregar) . ' regla(s) agregada(s). Backup: ' . $backupName,
        'agregadas' => count($lineasAgregar),
    ];
}

// =====================================================================
//  EJECUCION
// =====================================================================

$tiempoInicio = microtime(true);
$resultados   = [];
$correcciones = [];

// Obtener lista de carpetas
if (!empty($targetSub)) {
    $carpetas = [$targetSub];
} else {
    $carpetas = [];
    $scan = @scandir($basePath);
    if (!$scan) {
        echo $esCLI ? "ERROR: No se puede leer {$basePath}\n" : "<p style='color:red'>ERROR: No se puede leer {$basePath}</p>";
        exit(1);
    }
    foreach ($scan as $c) {
        if (in_array($c, $excluir)) continue;
        if (!is_dir($basePath . '/' . $c)) continue;
        $carpetas[] = $c;
    }
    sort($carpetas);
}

// Escanear
foreach ($carpetas as $carpeta) {
    $subPath = $basePath . '/' . $carpeta;
    $r = analizarACL($subPath, $carpeta);
    if (!$r['tiene_doku']) continue;
    $resultados[] = $r;

    // Corregir si esta en modo corregir y NO esta OK
    if ($modo === 'corregir' && $r['estado'] !== 'OK') {
        $fix = corregirACL($subPath, $carpeta, $r['reglas_faltan']);
        $correcciones[$carpeta] = $fix;
    }
}

$tiempoFin = round(microtime(true) - $tiempoInicio, 2);

// Estadisticas
$totalOK        = count(array_filter($resultados, fn($r) => $r['estado'] === 'OK'));
$totalSinACL    = count(array_filter($resultados, fn($r) => $r['estado'] === 'SIN_ACL'));
$totalSinReglas = count(array_filter($resultados, fn($r) => $r['estado'] === 'SIN_REGLAS'));
$totalIncompleto = count(array_filter($resultados, fn($r) => $r['estado'] === 'INCOMPLETO'));
$totalError     = count(array_filter($resultados, fn($r) => $r['estado'] === 'ERROR'));
$totalCorregir  = $totalSinACL + $totalSinReglas + $totalIncompleto;

// =====================================================================
//  SALIDA CLI
// =====================================================================

if ($esCLI) {
    echo "================================================================\n";
    echo " CORRECTOR DE ACL - SUBDOMINIOS SIE\n";
    echo " " . date('Y-m-d H:i:s') . " | Modo: {$modo} | Tiempo: {$tiempoFin}s\n";
    echo "================================================================\n\n";

    echo "Total: " . count($resultados) . " | OK: {$totalOK} | Sin ACL: {$totalSinACL} | Incompleto: {$totalIncompleto} | Sin reglas: {$totalSinReglas}\n\n";

    $afectados = array_filter($resultados, fn($r) => $r['estado'] !== 'OK');
    if (!empty($afectados)) {
        echo "=== SISTEMAS A CORREGIR ===\n";
        foreach ($afectados as $r) {
            $fix = $correcciones[$r['carpeta']] ?? null;
            echo sprintf("  %-30s [%s] %s %s\n",
                $r['carpeta'],
                $r['estado'],
                $r['problema'],
                $fix ? ($fix['ok'] ? '-> ' . $fix['msg'] : '-> ERROR: ' . $fix['msg']) : ''
            );
        }
    }
    exit(0);
}

// =====================================================================
//  SALIDA HTML
// =====================================================================
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Corrector ACL - SIE</title>
<style>
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f1f5f9; color: #1e293b; padding: 20px; }
    .container { max-width: 1400px; margin: 0 auto; }
    h1 { font-size: 1.5em; color: #0f172a; margin-bottom: 4px; }
    .subtitle { color: #64748b; font-size: 0.88em; margin-bottom: 20px; }

    .summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
    .card { background: #fff; border-radius: 10px; padding: 14px; text-align: center; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
    .card .num { font-size: 1.8em; font-weight: 700; }
    .card .label { font-size: 0.8em; color: #64748b; }
    .green { color: #16a34a; } .red { color: #dc2626; } .yellow { color: #d97706; } .blue { color: #2563eb; }

    .section { background: #fff; border-radius: 10px; padding: 20px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.08); }
    .section h2 { font-size: 1.1em; margin-bottom: 12px; }

    .explain { background: #fef2f2; border: 1px solid #fecaca; border-radius: 10px; padding: 16px; margin-bottom: 20px; }
    .explain h2 { color: #991b1b; margin-bottom: 8px; font-size: 1em; }
    .explain p { font-size: 0.86em; color: #334155; margin-bottom: 4px; }
    .explain code { background: #fee2e2; color: #991b1b; padding: 1px 4px; border-radius: 3px; font-size: 0.9em; }

    .reglas-box { background: #f0fdf4; border: 1px solid #86efac; border-radius: 8px; padding: 14px; margin: 12px 0; }
    .reglas-box h3 { font-size: 0.92em; color: #166534; margin-bottom: 8px; }
    .reglas-box code { display: block; background: #dcfce7; color: #166534; padding: 4px 8px; margin: 3px 0; border-radius: 4px; font-size: 0.88em; }

    .actions { display: flex; gap: 12px; margin-bottom: 20px; flex-wrap: wrap; align-items: center; }
    .btn { padding: 10px 20px; border: none; border-radius: 8px; font-size: 0.9em; cursor: pointer; text-decoration: none; display: inline-block; font-weight: 600; }
    .btn-blue { background: #2563eb; color: #fff; } .btn-blue:hover { background: #1d4ed8; }
    .btn-red { background: #dc2626; color: #fff; } .btn-red:hover { background: #b91c1c; }
    .btn-green { background: #16a34a; color: #fff; } .btn-gray { background: #64748b; color: #fff; }

    .result-box { border-radius: 10px; padding: 16px; margin-bottom: 20px; }
    .result-ok { background: #f0fdf4; border: 1px solid #86efac; }
    .result-ok strong { color: #166534; }
    .result-err { background: #fef2f2; border: 1px solid #fecaca; }

    .problema-grupo { margin-bottom: 14px; padding: 12px 14px; border-radius: 8px; }
    .pg-sinacl { background: #fee2e2; border: 1px solid #fecaca; }
    .pg-incompleto { background: #fef3c7; border: 1px solid #fde68a; }
    .pg-sinreglas { background: #fce7f3; border: 1px solid #f9a8d4; }
    .pg-title { font-weight: 700; font-size: 0.92em; margin-bottom: 6px; }
    .pg-lista { font-size: 0.85em; line-height: 1.9; }
    .pg-lista span { display: inline-block; margin-right: 10px; }

    table { width: 100%; border-collapse: collapse; font-size: 0.83em; }
    th { text-align: left; padding: 8px 6px; border-bottom: 2px solid #e2e8f0; color: #475569; font-size: 0.85em; }
    td { padding: 7px 6px; border-bottom: 1px solid #f1f5f9; }
    tr:hover { background: #f8fafc; }
    tr.row-err { background: #fef2f2; }
    tr.row-err:hover { background: #fee2e2; }

    .badge { display: inline-block; padding: 2px 7px; border-radius: 4px; font-size: 0.76em; font-weight: 600; }
    .badge-ok { background: #dcfce7; color: #166534; }
    .badge-err { background: #fee2e2; color: #991b1b; }
    .badge-fix { background: #dbeafe; color: #1e40af; }
    .badge-warn { background: #fef3c7; color: #92400e; }

    code { background: #f1f5f9; padding: 1px 4px; border-radius: 3px; font-size: 0.86em; }

    .filter-bar { margin-bottom: 12px; display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
    .filter-bar input, .filter-bar select { padding: 6px 10px; border: 1px solid #cbd5e1; border-radius: 6px; font-size: 0.86em; }
    .filter-bar input { width: 200px; }

    .regla-detalle { font-size: 0.78em; color: #64748b; }
    .regla-si { color: #16a34a; } .regla-no { color: #dc2626; font-weight: 600; }
</style>
</head>
<body>
<div class="container">

<h1>&#128274; Corrector de ACL (Permisos) - Subdominios SIE</h1>
<p class="subtitle">
    <?= date('Y-m-d H:i:s') ?> |
    Modo: <strong><?= $modo === 'corregir' ? '&#9888;&#65039; CORREGIR' : '&#128269; ESCANEAR' ?></strong> |
    Tiempo: <?= $tiempoFin ?>s |
    Sistemas: <?= count($resultados) ?>
</p>

<div class="explain">
    <h2>&#128274; Que hace este script</h2>
    <p><strong>Problema:</strong> Sin las reglas minimas en <code>conf/acl.auth.php</code>, DokuWiki muestra <em>"No ACL setup yet! Denying access to everyone."</em> y bloquea el acceso.</p>
    <p><strong>Solucion:</strong> Verifica que las 5 reglas minimas del sistema SIE existan en cada subdominio. Si faltan, las agrega sin eliminar reglas existentes.</p>
    <p><strong>Escanear:</strong> Detecta sistemas donde faltan reglas ACL.</p>
    <p><strong>Corregir:</strong> Agrega las reglas faltantes con backup automatico.</p>
</div>

<div class="reglas-box">
    <h3>&#9989; Reglas minimas obligatorias</h3>
    <code>*&nbsp;&nbsp;&nbsp;&nbsp;@ALL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← Denegar acceso anonimo</code>
    <code>*&nbsp;&nbsp;&nbsp;&nbsp;@sie&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;16&nbsp;&nbsp;&nbsp;&nbsp;← Grupo SIE - permisos totales</code>
    <code>*&nbsp;&nbsp;&nbsp;&nbsp;@lectura&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← Grupo lectura - upload</code>
    <code>*&nbsp;&nbsp;&nbsp;&nbsp;@editartareas&nbsp;&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;← Grupo edicion de tareas</code>
    <code>@lidertareas&nbsp;&nbsp;:task&nbsp;&nbsp;coordinator&nbsp;&nbsp;← Coordinador de tareas</code>
</div>

<!-- Resumen -->
<div class="summary">
    <div class="card"><div class="num blue"><?= count($resultados) ?></div><div class="label">Total DokuWiki</div></div>
    <div class="card"><div class="num green"><?= $totalOK ?></div><div class="label">ACL Completo</div></div>
    <div class="card"><div class="num <?= $totalIncompleto > 0 ? 'yellow' : 'green' ?>"><?= $totalIncompleto ?></div><div class="label">Incompleto</div></div>
    <div class="card"><div class="num <?= $totalSinACL > 0 ? 'red' : 'green' ?>"><?= $totalSinACL ?></div><div class="label">Sin ACL</div></div>
    <div class="card"><div class="num <?= $totalSinReglas > 0 ? 'red' : 'green' ?>"><?= $totalSinReglas ?></div><div class="label">Sin reglas</div></div>
</div>

<!-- Botones -->
<div class="actions">
    <a href="?modo=escanear" class="btn btn-blue">&#128269; Escanear todos</a>
    <?php if ($totalCorregir > 0 && $modo !== 'corregir'): ?>
        <a href="?modo=corregir" class="btn btn-red"
           onclick="return confirm('ATENCION: Esto va a agregar reglas ACL faltantes en <?= $totalCorregir ?> sistemas.\n\nSe creara backup de conf/acl.auth.php antes de modificar cada uno.\n\nSolo AGREGA reglas, NO elimina las existentes.\n\nContinuar?')">
            &#128274; Corregir <?= $totalCorregir ?> sistemas
        </a>
    <?php endif; ?>
    <?php if (!empty($targetSub)): ?>
        <a href="?" class="btn btn-gray">Ver todos</a>
    <?php endif; ?>
</div>

<?php if ($modo === 'corregir' && !empty($correcciones)): ?>
<!-- Resultado de correcciones -->
<?php
$fixOK = count(array_filter($correcciones, fn($f) => $f['ok']));
$fixErr = count(array_filter($correcciones, fn($f) => !$f['ok']));
?>
<div class="result-box <?= $fixErr > 0 ? 'result-err' : 'result-ok' ?>">
    <strong>&#9989; Resultado: <?= $fixOK ?> corregidos, <?= $fixErr ?> errores</strong>
    <table style="margin-top:10px;">
        <thead><tr><th>Subdominio</th><th>Resultado</th><th>Detalle</th></tr></thead>
        <tbody>
        <?php foreach ($correcciones as $carpeta => $fix): ?>
            <tr>
                <td><strong><?= htmlspecialchars($carpeta) ?></strong></td>
                <td><span class="badge <?= $fix['ok'] ? 'badge-ok' : 'badge-err' ?>"><?= $fix['ok'] ? 'CORREGIDO' : 'ERROR' ?></span></td>
                <td><?= htmlspecialchars($fix['msg']) ?></td>
            </tr>
        <?php endforeach; ?>
        </tbody>
    </table>
</div>
<?php endif; ?>

<?php if ($totalCorregir > 0 && $modo !== 'corregir'): ?>
<!-- Problemas agrupados -->
<div class="section">
    <h2>&#9888;&#65039; Sistemas a corregir (<?= $totalCorregir ?>)</h2>

    <?php $afectadosSinACL = array_filter($resultados, fn($r) => $r['estado'] === 'SIN_ACL'); ?>
    <?php if (!empty($afectadosSinACL)): ?>
    <div class="problema-grupo pg-sinacl">
        <div class="pg-title">&#9940; Sin archivo acl.auth.php (<?= count($afectadosSinACL) ?>)</div>
        <div class="pg-lista">
            <?php foreach ($afectadosSinACL as $r): ?>
                <span>&#8226; <strong><?= htmlspecialchars($r['carpeta']) ?></strong></span>
            <?php endforeach; ?>
        </div>
    </div>
    <?php endif; ?>

    <?php $afectadosSinReglas = array_filter($resultados, fn($r) => $r['estado'] === 'SIN_REGLAS'); ?>
    <?php if (!empty($afectadosSinReglas)): ?>
    <div class="problema-grupo pg-sinreglas">
        <div class="pg-title">&#10060; ACL sin ninguna regla minima (<?= count($afectadosSinReglas) ?>)</div>
        <div class="pg-lista">
            <?php foreach ($afectadosSinReglas as $r): ?>
                <span>&#8226; <strong><?= htmlspecialchars($r['carpeta']) ?></strong></span>
            <?php endforeach; ?>
        </div>
    </div>
    <?php endif; ?>

    <?php $afectadosIncompleto = array_filter($resultados, fn($r) => $r['estado'] === 'INCOMPLETO'); ?>
    <?php if (!empty($afectadosIncompleto)): ?>
    <div class="problema-grupo pg-incompleto">
        <div class="pg-title">&#9888;&#65039; ACL incompleto — faltan reglas (<?= count($afectadosIncompleto) ?>)</div>
        <div class="pg-lista">
            <?php foreach ($afectadosIncompleto as $r): ?>
                <span>&#8226; <strong><?= htmlspecialchars($r['carpeta']) ?></strong> (<?= htmlspecialchars($r['problema']) ?>)</span>
            <?php endforeach; ?>
        </div>
    </div>
    <?php endif; ?>
</div>
<?php endif; ?>

<!-- Tabla completa -->
<div class="section">
    <h2>&#128203; Todos los sistemas (<?= count($resultados) ?>)</h2>
    <div class="filter-bar">
        <input type="text" id="filtro" placeholder="Buscar..." oninput="filtrar()">
        <select id="filtroEstado" onchange="filtrar()">
            <option value="">Todos</option>
            <option value="err">A corregir</option>
            <option value="OK">Solo OK</option>
        </select>
    </div>
    <table id="tabla">
        <thead>
            <tr>
                <th>#</th>
                <th>Subdominio</th>
                <th>Lineas ACL</th>
                <th>Reglas minimas</th>
                <th>Estado</th>
                <?php if ($modo === 'corregir'): ?><th>Fix</th><?php endif; ?>
            </tr>
        </thead>
        <tbody>
        <?php $i = 0; foreach ($resultados as $r): $i++; ?>
            <?php
                $rowClass = $r['estado'] !== 'OK' ? 'row-err' : '';
                $fix = $correcciones[$r['carpeta']] ?? null;
                $totalReglas = count($reglasMinimas);
                $reglasPresentes = count($r['reglas_ok']);
            ?>
            <tr class="<?= $rowClass ?>" data-name="<?= htmlspecialchars(strtolower($r['carpeta'])) ?>" data-estado="<?= $r['estado'] === 'OK' ? 'OK' : 'err' ?>">
                <td><?= $i ?></td>
                <td>
                    <strong><?= htmlspecialchars($r['carpeta']) ?></strong>
                    <?php if (!empty($r['reglas_faltan'])): ?>
                        <div class="regla-detalle">
                            <?php foreach ($r['reglas_faltan'] as $falta): ?>
                                <span class="regla-no">&#10007; <?= htmlspecialchars($falta) ?></span><br>
                            <?php endforeach; ?>
                        </div>
                    <?php endif; ?>
                </td>
                <td><?= $r['tiene_acl'] ? $r['total_lineas'] : '—' ?></td>
                <td>
                    <?php if ($r['estado'] === 'OK'): ?>
                        <span class="badge badge-ok"><?= $reglasPresentes ?>/<?= $totalReglas ?></span>
                    <?php elseif ($r['tiene_acl']): ?>
                        <span class="badge <?= $reglasPresentes > 0 ? 'badge-warn' : 'badge-err' ?>"><?= $reglasPresentes ?>/<?= $totalReglas ?></span>
                    <?php else: ?>
                        <span class="badge badge-err">0/<?= $totalReglas ?></span>
                    <?php endif; ?>
                </td>
                <td>
                    <?php if ($r['estado'] === 'OK'): ?>
                        <span class="badge badge-ok">OK</span>
                    <?php elseif ($r['estado'] === 'SIN_ACL'): ?>
                        <span class="badge badge-err">SIN ACL</span>
                    <?php elseif ($r['estado'] === 'SIN_REGLAS'): ?>
                        <span class="badge badge-err">SIN REGLAS</span>
                    <?php elseif ($r['estado'] === 'INCOMPLETO'): ?>
                        <span class="badge badge-warn">INCOMPLETO</span>
                    <?php else: ?>
                        <span class="badge badge-err"><?= htmlspecialchars($r['estado']) ?></span>
                    <?php endif; ?>
                </td>
                <?php if ($modo === 'corregir'): ?>
                <td>
                    <?php if ($fix): ?>
                        <span class="badge <?= $fix['ok'] ? 'badge-fix' : 'badge-err' ?>">
                            <?= $fix['ok'] ? 'CORREGIDO' : 'ERROR' ?>
                        </span>
                        <span style="font-size:0.8em;"><?= htmlspecialchars($fix['msg']) ?></span>
                    <?php elseif ($r['estado'] === 'OK'): ?>
                        <span style="color:#94a3b8;">—</span>
                    <?php endif; ?>
                </td>
                <?php endif; ?>
            </tr>
        <?php endforeach; ?>
        </tbody>
    </table>
</div>

</div><!-- /container -->

<script>
function filtrar() {
    var texto = document.getElementById('filtro').value.toLowerCase();
    var estado = document.getElementById('filtroEstado').value;
    var rows = document.querySelectorAll('#tabla tbody tr');
    rows.forEach(function(row) {
        var name = row.dataset.name || '';
        var est = row.dataset.estado || '';
        var showText = !texto || name.indexOf(texto) !== -1;
        var showEstado = !estado || est === estado;
        row.style.display = (showText && showEstado) ? '' : 'none';
    });
}
</script>
</body>
</html>
