<?php
/**
 * CORRECTOR DE defer_js EN LOCAL.PHP - SUBDOMINIOS SIE
 * ====================================================
 * Cambia $conf['defer_js'] = 0 a $conf['defer_js'] = 1 en conf/local.php
 * de todos los subdominios DokuWiki.
 *
 * SIN defer_js=1, todos los archivos JS bloquean el renderizado de la pagina.
 * CON defer_js=1, DokuWiki agrega el atributo "defer" a los scripts,
 * permitiendo que el HTML se renderice sin esperar la descarga de JS.
 *
 * MODOS:
 *   ?modo=escanear   (default) - Solo detectar, no modificar nada
 *   ?modo=corregir              - Corregir TODOS los afectados
 *   ?sub=nombre                 - Verificar/corregir uno solo
 *
 * CAMBIO QUE REALIZA:
 *   $conf['defer_js'] = 0;  -->  $conf['defer_js'] = 1;
 *   Si no existe la linea, la agrega despues de $conf['updatecheck']
 */

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

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

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

// =====================================================================
//  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
// =====================================================================

/**
 * Lee el valor actual de defer_js en conf/local.php
 * Retorna: 0, 1, o 'NO_DEFINIDO'
 */
function leerDeferJs($subPath)
{
    $localPhp = $subPath . '/conf/local.php';
    if (!file_exists($localPhp)) return 'NO_FILE';

    $content = @file_get_contents($localPhp);
    if ($content === false) return 'NO_READ';

    if (preg_match("/\\\$conf\['defer_js'\]\s*=\s*(\d+)\s*;/", $content, $m)) {
        return (int)$m[1];
    }

    return 'NO_DEFINIDO';
}

/**
 * Analiza un subdominio
 */
function analizarSubdominio($subPath, $carpeta)
{
    $r = [
        'carpeta'    => $carpeta,
        'tiene_doku' => false,
        'defer_js'   => null,
        'estado'     => 'NO_DOKU',
        'problema'   => '',
    ];

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

    $valor = leerDeferJs($subPath);
    $r['defer_js'] = $valor;

    if ($valor === 'NO_FILE') {
        $r['estado'] = 'SIN_LOCAL';
        $r['problema'] = 'No existe conf/local.php';
    } elseif ($valor === 'NO_READ') {
        $r['estado'] = 'ERROR';
        $r['problema'] = 'No se puede leer conf/local.php';
    } elseif ($valor === 'NO_DEFINIDO') {
        $r['estado'] = 'FALTA';
        $r['problema'] = 'defer_js no esta definido (usa default del core)';
    } elseif ($valor === 0) {
        $r['estado'] = 'DESACTIVADO';
        $r['problema'] = 'defer_js = 0 (JS bloqueante)';
    } elseif ($valor === 1) {
        $r['estado'] = 'OK';
    } else {
        $r['estado'] = 'RARO';
        $r['problema'] = "defer_js = {$valor} (valor inesperado)";
    }

    return $r;
}

/**
 * Corrige defer_js en conf/local.php de un subdominio
 */
function corregirSubdominio($subPath, $carpeta, $estadoActual)
{
    $localPhp = $subPath . '/conf/local.php';

    if (!file_exists($localPhp)) {
        return ['ok' => false, 'msg' => 'conf/local.php no existe'];
    }

    $content = @file_get_contents($localPhp);
    if ($content === false) {
        return ['ok' => false, 'msg' => 'No se puede leer conf/local.php'];
    }

    // Crear backup con timestamp
    $timestamp = date('Ymd_His');
    $backupName = "local.php.bak_deferjs_{$timestamp}";
    $backupPath = $subPath . '/conf/' . $backupName;
    if (!@copy($localPhp, $backupPath)) {
        return ['ok' => false, 'msg' => 'No se pudo crear backup'];
    }

    $modificado = false;
    $nuevoContent = $content;

    if ($estadoActual === 'DESACTIVADO' || $estadoActual === 'RARO') {
        // Reemplazar valor existente
        $nuevoContent = preg_replace(
            "/\\\$conf\['defer_js'\]\s*=\s*\d+\s*;/",
            "\$conf['defer_js'] = 1;",
            $nuevoContent
        );
        $modificado = true;
    } elseif ($estadoActual === 'FALTA') {
        // Agregar despues de updatecheck si existe, o al final
        if (preg_match("/(\\\$conf\['updatecheck'\]\s*=\s*\d+\s*;)/", $nuevoContent, $m)) {
            $nuevoContent = str_replace(
                $m[1],
                $m[1] . "\n\$conf['defer_js'] = 1;",
                $nuevoContent
            );
            $modificado = true;
        } elseif (preg_match("/(\\\$conf\['hidewarnings'\]\s*=\s*\d+\s*;)/", $nuevoContent, $m)) {
            // Alternativa: antes de hidewarnings
            $nuevoContent = str_replace(
                $m[1],
                "\$conf['defer_js'] = 1;\n" . $m[1],
                $nuevoContent
            );
            $modificado = true;
        } else {
            // Ultima opcion: agregar antes del cierre o al final
            $nuevoContent = rtrim($nuevoContent) . "\n\$conf['defer_js'] = 1;\n";
            $modificado = true;
        }
    }

    if (!$modificado) {
        @unlink($backupPath); // No hubo cambios, eliminar backup
        return ['ok' => false, 'msg' => 'Sin cambios necesarios'];
    }

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

    return ['ok' => true, 'msg' => "OK. Backup: {$backupName}"];
}

// =====================================================================
//  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 = analizarSubdominio($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 = corregirSubdominio($subPath, $carpeta, $r['estado']);
        $correcciones[$carpeta] = $fix;
    }
}

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

// Estadisticas
$totalOK         = count(array_filter($resultados, fn($r) => $r['estado'] === 'OK'));
$totalDesactivado = count(array_filter($resultados, fn($r) => $r['estado'] === 'DESACTIVADO'));
$totalFalta      = count(array_filter($resultados, fn($r) => $r['estado'] === 'FALTA'));
$totalOtro       = count(array_filter($resultados, fn($r) => !in_array($r['estado'], ['OK', 'DESACTIVADO', 'FALTA'])));
$totalCorregir   = $totalDesactivado + $totalFalta + $totalOtro;

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

if ($esCLI) {
    echo "================================================================\n";
    echo " CORRECTOR DE defer_js - 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 (defer=1): {$totalOK} | defer=0: {$totalDesactivado} | No definido: {$totalFalta}\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\n",
                $r['carpeta'],
                $r['estado'],
                $fix ? ($fix['ok'] ? '-> ' . $fix['msg'] : '-> ERROR: ' . $fix['msg']) : ''
            );
        }
    }
    exit(0);
}

// =====================================================================
//  SALIDA HTML
// =====================================================================
?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Corrector defer_js - 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: #eff6ff; border: 1px solid #93c5fd; border-radius: 10px; padding: 16px; margin-bottom: 20px; }
    .explain h2 { color: #1e40af; margin-bottom: 8px; font-size: 1em; }
    .explain p { font-size: 0.86em; color: #334155; margin-bottom: 4px; }
    .explain code { background: #dbeafe; color: #1e40af; padding: 1px 4px; border-radius: 3px; font-size: 0.9em; }

    .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-defer0 { background: #fee2e2; border: 1px solid #fecaca; }
    .pg-falta { background: #fef3c7; border: 1px solid #fde68a; }
    .pg-otro { 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; }
    code.err { background: #fee2e2; color: #991b1b; }
    code.ok { background: #dcfce7; color: #166534; }

    .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; }
</style>
</head>
<body>
<div class="container">

<h1>&#9889; Corrector de defer_js - 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>&#128161; Que hace este script</h2>
    <p><strong>Problema:</strong> Con <code>defer_js = 0</code>, todos los archivos JavaScript bloquean el renderizado. El navegador no pinta la pagina hasta descargar y ejecutar cada JS.</p>
    <p><strong>Solucion:</strong> Con <code>defer_js = 1</code>, DokuWiki agrega <code>defer</code> a los tags <code>&lt;script&gt;</code>, permitiendo que el HTML se renderice inmediatamente.</p>
    <p><strong>Escanear:</strong> Detecta sistemas donde <code>defer_js</code> esta en 0 o no definido.</p>
    <p><strong>Corregir:</strong> Cambia <code>defer_js = 0</code> a <code>defer_js = 1</code> en <code>conf/local.php</code>. Crea backup antes de modificar.</p>
</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">defer_js = 1 (OK)</div></div>
    <div class="card"><div class="num <?= $totalDesactivado > 0 ? 'red' : 'green' ?>"><?= $totalDesactivado ?></div><div class="label">defer_js = 0</div></div>
    <div class="card"><div class="num <?= $totalFalta > 0 ? 'yellow' : 'green' ?>"><?= $totalFalta ?></div><div class="label">No definido</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 cambiar defer_js a 1 en <?= $totalCorregir ?> sistemas.\n\nSe creara backup de conf/local.php antes de modificar cada uno.\n\nContinuar?')">
            &#9889; 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 $afectadosDefer0 = array_filter($resultados, fn($r) => $r['estado'] === 'DESACTIVADO'); ?>
    <?php if (!empty($afectadosDefer0)): ?>
    <div class="problema-grupo pg-defer0">
        <div class="pg-title">&#9940; defer_js = 0 — JS BLOQUEANTE (<?= count($afectadosDefer0) ?>)</div>
        <div class="pg-lista">
            <?php foreach ($afectadosDefer0 as $r): ?>
                <span>&#8226; <strong><?= htmlspecialchars($r['carpeta']) ?></strong></span>
            <?php endforeach; ?>
        </div>
    </div>
    <?php endif; ?>

    <?php $afectadosFalta = array_filter($resultados, fn($r) => $r['estado'] === 'FALTA'); ?>
    <?php if (!empty($afectadosFalta)): ?>
    <div class="problema-grupo pg-falta">
        <div class="pg-title">&#9888;&#65039; defer_js NO DEFINIDO — usa default del core (<?= count($afectadosFalta) ?>)</div>
        <div class="pg-lista">
            <?php foreach ($afectadosFalta as $r): ?>
                <span>&#8226; <strong><?= htmlspecialchars($r['carpeta']) ?></strong></span>
            <?php endforeach; ?>
        </div>
    </div>
    <?php endif; ?>

    <?php $afectadosOtro = array_filter($resultados, fn($r) => !in_array($r['estado'], ['OK', 'DESACTIVADO', 'FALTA'])); ?>
    <?php if (!empty($afectadosOtro)): ?>
    <div class="problema-grupo pg-otro">
        <div class="pg-title">&#10060; Otros problemas (<?= count($afectadosOtro) ?>)</div>
        <div class="pg-lista">
            <?php foreach ($afectadosOtro 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>defer_js</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;
            ?>
            <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>
                </td>
                <td>
                    <?php if ($r['defer_js'] === 1): ?>
                        <code class="ok">1 (defer)</code>
                    <?php elseif ($r['defer_js'] === 0): ?>
                        <code class="err">0 (bloqueante)</code>
                    <?php elseif ($r['defer_js'] === 'NO_DEFINIDO'): ?>
                        <code style="background:#fef3c7;color:#92400e;">no definido</code>
                    <?php else: ?>
                        <code><?= htmlspecialchars($r['defer_js']) ?></code>
                    <?php endif; ?>
                </td>
                <td>
                    <?php if ($r['estado'] === 'OK'): ?>
                        <span class="badge badge-ok">OK</span>
                    <?php elseif ($r['estado'] === 'DESACTIVADO'): ?>
                        <span class="badge badge-err">defer=0</span>
                    <?php elseif ($r['estado'] === 'FALTA'): ?>
                        <span class="badge badge-warn">NO DEFINIDO</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>
