<?php
// concurso_nobel/index.php
// Acceso público NOBEX mediante código.
// Soporta accesos ligados a concurso y ADMIN_GLOBAL sin concurso fijo.

declare(strict_types=1);

session_start();

require_once __DIR__ . '/includes/db.php';

date_default_timezone_set('America/Lima');

function nobex_h($valor): string
{
    return htmlspecialchars((string)$valor, ENT_QUOTES, 'UTF-8');
}

function nobex_tabla_existe(mysqli $conn, string $tabla): bool
{
    $tabla = mysqli_real_escape_string($conn, $tabla);
    $res = @mysqli_query($conn, "SHOW TABLES LIKE '{$tabla}'");
    return $res && mysqli_num_rows($res) > 0;
}

function nobex_es_admin_global(array $acceso): bool
{
    $tipo = strtoupper(trim((string)($acceso['tipo_acceso'] ?? '')));
    $idConcurso = $acceso['id_concurso'] ?? null;
    $puedeAdministrar = (int)($acceso['puede_administrar'] ?? 0);

    return $tipo === 'ADMIN_GLOBAL' || ($puedeAdministrar === 1 && ($idConcurso === null || (int)$idConcurso === 0));
}

function nobex_auditar(
    mysqli $conn,
    ?int $idConcurso,
    ?int $idGrupo,
    ?int $idAcceso,
    ?int $idParticipante,
    string $accion,
    string $detalle
): void {
    if (!nobex_tabla_existe($conn, 'concurso_auditoria')) {
        return;
    }

    $ip = $_SERVER['REMOTE_ADDR'] ?? '';
    $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';

    $stmt = mysqli_prepare($conn, "
        INSERT INTO concurso_auditoria
            (id_concurso, id_grupo, id_acceso, id_participante, accion, detalle, ip, user_agent, created_at)
        VALUES
            (?, ?, ?, ?, ?, ?, ?, ?, NOW())
    ");

    if (!$stmt) {
        return;
    }

    mysqli_stmt_bind_param($stmt, 'iiiissss', $idConcurso, $idGrupo, $idAcceso, $idParticipante, $accion, $detalle, $ip, $userAgent);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_close($stmt);
}

function nobex_limpiar_sesion(): void
{
    unset(
        $_SESSION['cn_acceso_id'],
        $_SESSION['cn_concurso_id'],
        $_SESSION['cn_grupo_id'],
        $_SESSION['cn_salon_id'],
        $_SESSION['cn_codigo'],
        $_SESSION['cn_responsable'],
        $_SESSION['cn_last_activity'],
        $_SESSION['cn_admin_global'],
        $_SESSION['cn_admin_concurso_trabajo']
    );
}

function nobex_acceso_activo(mysqli $conn): bool
{
    $idAcceso = (int)($_SESSION['cn_acceso_id'] ?? 0);
    $idConcursoSesion = (int)($_SESSION['cn_concurso_id'] ?? 0);

    if ($idAcceso <= 0) {
        return false;
    }

    $stmt = mysqli_prepare($conn, "
        SELECT
            a.id_acceso,
            a.id_concurso,
            a.id_grupo,
            a.id_salon,
            a.codigo,
            a.nombre_responsable,
            a.tipo_acceso,
            a.puede_registrar_participantes,
            a.puede_registrar_resultados,
            a.puede_ver_resultados,
            a.puede_administrar,
            a.activo,
            a.fecha_expiracion,
            c.estado AS concurso_estado,
            c.fecha_inicio,
            c.fecha_fin
        FROM concurso_accesos a
        LEFT JOIN concursos c ON c.id_concurso = a.id_concurso
        WHERE a.id_acceso = ?
        LIMIT 1
    ");

    if (!$stmt) {
        nobex_limpiar_sesion();
        return false;
    }

    mysqli_stmt_bind_param($stmt, 'i', $idAcceso);
    mysqli_stmt_execute($stmt);
    $res = mysqli_stmt_get_result($stmt);
    $acceso = mysqli_fetch_assoc($res);
    mysqli_stmt_close($stmt);

    if (!$acceso) {
        nobex_limpiar_sesion();
        return false;
    }

    $hoy = date('Y-m-d');
    $esAdminGlobal = nobex_es_admin_global($acceso);
    $idConcursoAcceso = $acceso['id_concurso'] !== null ? (int)$acceso['id_concurso'] : 0;

    if ((int)$acceso['activo'] !== 1) {
        nobex_limpiar_sesion();
        return false;
    }

    if (!empty($acceso['fecha_expiracion']) && $hoy > $acceso['fecha_expiracion']) {
        nobex_limpiar_sesion();
        return false;
    }

    if ($esAdminGlobal) {
        $_SESSION['cn_admin_global'] = 1;
        $_SESSION['cn_concurso_id'] = 0;
        $_SESSION['cn_grupo_id'] = 0;
        $_SESSION['cn_salon_id'] = 0;
        return true;
    }

    if ($idConcursoAcceso <= 0 || $idConcursoSesion <= 0 || $idConcursoSesion !== $idConcursoAcceso) {
        nobex_limpiar_sesion();
        return false;
    }

    if (strtoupper((string)$acceso['concurso_estado']) !== 'ACTIVO') {
        nobex_limpiar_sesion();
        return false;
    }

    if (!empty($acceso['fecha_inicio']) && $hoy < $acceso['fecha_inicio']) {
        nobex_limpiar_sesion();
        return false;
    }

    if (!empty($acceso['fecha_fin']) && $hoy > $acceso['fecha_fin']) {
        nobex_limpiar_sesion();
        return false;
    }

    $_SESSION['cn_admin_global'] = 0;

    return true;
}

if (nobex_acceso_activo($conn)) {
    header('Location: panel.php');
    exit;
}

if (empty($_SESSION['csrf_index_nobex'])) {
    $_SESSION['csrf_index_nobex'] = bin2hex(random_bytes(32));
}

$csrf = (string)$_SESSION['csrf_index_nobex'];
$mensajeError = '';
$codigoIngresado = '';

$tablasNecesarias = [
    'concursos',
    'concurso_grupos',
    'concurso_salones',
    'concurso_accesos',
    'concurso_participantes',
    'concurso_resultados',
    'concurso_auditoria'
];

$tablasFaltantes = [];

foreach ($tablasNecesarias as $tabla) {
    if (!nobex_tabla_existe($conn, $tabla)) {
        $tablasFaltantes[] = $tabla;
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $codigoIngresado = strtoupper(trim((string)($_POST['codigo'] ?? '')));
    $csrfPost = (string)($_POST['csrf_token'] ?? '');

    if (!hash_equals($csrf, $csrfPost)) {
        $mensajeError = 'Solicitud no válida. Recarga la página e inténtalo nuevamente.';
    } elseif (!empty($tablasFaltantes)) {
        $mensajeError = 'Faltan tablas en la base de datos: ' . implode(', ', $tablasFaltantes);
    } elseif ($codigoIngresado === '') {
        $mensajeError = 'Ingresa tu código de acceso.';
    } elseif (!preg_match('/^[A-Z0-9\-]{4,60}$/', $codigoIngresado)) {
        $mensajeError = 'El código solo debe contener letras, números y guiones.';
    } else {
        $stmt = mysqli_prepare($conn, "
            SELECT
                a.id_acceso,
                a.id_concurso,
                a.id_grupo,
                a.id_salon,
                a.codigo,
                a.nombre_responsable,
                a.tipo_acceso,
                a.puede_registrar_participantes,
                a.puede_registrar_resultados,
                a.puede_ver_resultados,
                a.puede_administrar,
                a.activo,
                a.fecha_expiracion,
                c.nombre AS concurso_nombre,
                c.subtitulo AS concurso_subtitulo,
                c.estado AS concurso_estado,
                c.fecha_inicio,
                c.fecha_fin,
                g.nombre AS grupo_nombre,
                s.nombre_salon
            FROM concurso_accesos a
            LEFT JOIN concursos c ON c.id_concurso = a.id_concurso
            LEFT JOIN concurso_grupos g ON g.id_grupo = a.id_grupo
            LEFT JOIN concurso_salones s ON s.id_salon = a.id_salon
            WHERE UPPER(TRIM(a.codigo)) = ?
            LIMIT 1
        ");

        if (!$stmt) {
            $mensajeError = 'No se pudo preparar la consulta de acceso.';
        } else {
            mysqli_stmt_bind_param($stmt, 's', $codigoIngresado);
            mysqli_stmt_execute($stmt);
            $res = mysqli_stmt_get_result($stmt);
            $acceso = mysqli_fetch_assoc($res);
            mysqli_stmt_close($stmt);

            if (!$acceso) {
                $mensajeError = 'Código incorrecto.';
                nobex_auditar($conn, null, null, null, null, 'ACCESO_FALLIDO', 'Código incorrecto: ' . $codigoIngresado);
            } else {
                $hoy = date('Y-m-d');
                $idConcurso = $acceso['id_concurso'] !== null ? (int)$acceso['id_concurso'] : null;
                $idAcceso = (int)$acceso['id_acceso'];
                $idGrupo = $acceso['id_grupo'] !== null ? (int)$acceso['id_grupo'] : null;
                $idSalon = $acceso['id_salon'] !== null ? (int)$acceso['id_salon'] : null;
                $esAdminGlobal = nobex_es_admin_global($acceso);

                if ((int)$acceso['activo'] !== 1) {
                    $mensajeError = 'Este código está desactivado.';
                    nobex_auditar($conn, $idConcurso, $idGrupo, $idAcceso, null, 'ACCESO_DENEGADO', 'Código desactivado.');
                } elseif (!empty($acceso['fecha_expiracion']) && $hoy > $acceso['fecha_expiracion']) {
                    $mensajeError = 'Este código ya expiró.';
                    nobex_auditar($conn, $idConcurso, $idGrupo, $idAcceso, null, 'ACCESO_DENEGADO', 'Código expirado.');
                } elseif (!$esAdminGlobal && ($idConcurso === null || $idConcurso <= 0)) {
                    $mensajeError = 'Este código no está vinculado a un concurso. Solo ADMIN_GLOBAL puede entrar sin concurso.';
                    nobex_auditar($conn, null, $idGrupo, $idAcceso, null, 'ACCESO_DENEGADO', 'Código sin concurso y sin permiso global.');
                } elseif (!$esAdminGlobal && strtoupper((string)$acceso['concurso_estado']) !== 'ACTIVO') {
                    $mensajeError = 'El concurso no está activo.';
                    nobex_auditar($conn, $idConcurso, $idGrupo, $idAcceso, null, 'ACCESO_DENEGADO', 'Concurso no activo.');
                } elseif (!$esAdminGlobal && !empty($acceso['fecha_inicio']) && $hoy < $acceso['fecha_inicio']) {
                    $mensajeError = 'El concurso todavía no ha iniciado.';
                    nobex_auditar($conn, $idConcurso, $idGrupo, $idAcceso, null, 'ACCESO_DENEGADO', 'Antes de fecha de inicio.');
                } elseif (!$esAdminGlobal && !empty($acceso['fecha_fin']) && $hoy > $acceso['fecha_fin']) {
                    $mensajeError = 'El concurso ya finalizó.';
                    nobex_auditar($conn, $idConcurso, $idGrupo, $idAcceso, null, 'ACCESO_DENEGADO', 'Después de fecha final.');
                } else {
                    session_regenerate_id(true);

                    $_SESSION['cn_acceso_id'] = $idAcceso;
                    $_SESSION['cn_concurso_id'] = $esAdminGlobal ? 0 : (int)$idConcurso;
                    $_SESSION['cn_grupo_id'] = $esAdminGlobal ? 0 : ($idGrupo ?? 0);
                    $_SESSION['cn_salon_id'] = $esAdminGlobal ? 0 : ($idSalon ?? 0);
                    $_SESSION['cn_codigo'] = (string)$acceso['codigo'];
                    $_SESSION['cn_responsable'] = (string)$acceso['nombre_responsable'];
                    $_SESSION['cn_last_activity'] = time();
                    $_SESSION['cn_admin_global'] = $esAdminGlobal ? 1 : 0;

                    if ($esAdminGlobal) {
                        unset($_SESSION['cn_admin_concurso_trabajo']);
                    }

                    $stmtUpdate = mysqli_prepare($conn, "
                        UPDATE concurso_accesos
                        SET ultimo_ingreso = NOW()
                        WHERE id_acceso = ?
                        LIMIT 1
                    ");

                    if ($stmtUpdate) {
                        mysqli_stmt_bind_param($stmtUpdate, 'i', $idAcceso);
                        mysqli_stmt_execute($stmtUpdate);
                        mysqli_stmt_close($stmtUpdate);
                    }

                    nobex_auditar(
                        $conn,
                        $esAdminGlobal ? null : (int)$idConcurso,
                        $esAdminGlobal ? null : $idGrupo,
                        $idAcceso,
                        null,
                        'ACCESO_CORRECTO',
                        'Ingreso correcto con código ' . $codigoIngresado . ($esAdminGlobal ? ' como ADMIN_GLOBAL' : '')
                    );

                    header('Location: panel.php');
                    exit;
                }
            }
        }
    }
}

$ejemplos = [
    'ADMIN-CONCURSO',
    'REGISTRADOR-GENERAL',
    'INI-5-A',
    'PRI-1-A',
    'SEC-5-A'
];
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <title>NOBEX | Acceso</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style>
        :root{--red:#c9151b;--red2:#921118;--gold:#f5bd16;--ink:#111827;--muted:#64748b;--line:#e2e8f0;--soft:#f6f7fb}
        *{box-sizing:border-box}
        body{margin:0;min-height:100vh;font-family:Arial,Helvetica,sans-serif;background:linear-gradient(180deg,#fff 0%,var(--soft) 55%,#eef2f7 100%);color:var(--ink);display:grid;place-items:center;padding:24px}
        .shell{width:min(1050px,100%);display:grid;grid-template-columns:1fr 420px;background:#fff;border:1px solid var(--line);border-radius:18px;overflow:hidden;box-shadow:0 24px 60px rgba(15,23,42,.16)}
        .brand{min-height:560px;padding:38px;background:linear-gradient(140deg,rgba(17,24,39,.95),rgba(17,24,39,.86)),linear-gradient(135deg,var(--red),#1f2937);color:#fff;border-right:7px solid var(--gold);display:flex;flex-direction:column;justify-content:space-between}
        .logo{display:flex;gap:14px;align-items:center}
        .mark{width:54px;height:54px;border-radius:16px;background:linear-gradient(135deg,var(--red),var(--red2));display:grid;place-items:center;border:2px solid rgba(255,255,255,.18);font-weight:900;font-size:24px}
        .eyebrow{margin:0;color:var(--gold);font-weight:900;font-size:12px;text-transform:uppercase;letter-spacing:.04em}
        h1{margin:2px 0 0;font-size:22px;line-height:1.05}
        .hero h2{font-size:clamp(34px,5vw,56px);line-height:.96;margin:0;font-weight:950}
        .hero p{color:#cbd5e1;line-height:1.65;font-weight:700;max-width:460px}
        .features{display:grid;gap:10px;margin-top:28px}
        .feature{display:flex;gap:10px;align-items:center;font-weight:800;color:#e5e7eb}
        .dot{width:30px;height:30px;border-radius:10px;display:grid;place-items:center;background:rgba(255,255,255,.08);color:var(--gold);border:1px solid rgba(255,255,255,.16)}
        .access{padding:38px;display:flex;flex-direction:column;justify-content:center}
        .access .eyebrow{color:var(--red)}
        .access h2{font-size:30px;margin:4px 0 8px;font-weight:950}
        .desc{color:var(--muted);line-height:1.55;margin:0 0 20px}
        .msg{border-radius:12px;padding:13px 14px;margin-bottom:16px;font-weight:800;line-height:1.5}
        .error{background:#fee2e2;color:#991b1b;border:1px solid #fca5a5}
        .warn{background:#fef3c7;color:#92400e;border:1px solid #fcd34d}
        label{display:block;font-weight:900;margin-bottom:8px;color:#334155}
        input{width:100%;height:54px;border:1px solid #cbd5e1;border-radius:12px;padding:0 14px;font-size:18px;text-transform:uppercase;letter-spacing:1px;outline:none}
        input:focus{border-color:#1d4ed8;box-shadow:0 0 0 4px rgba(29,78,216,.12)}
        button{width:100%;height:54px;border:0;border-radius:12px;background:linear-gradient(135deg,var(--red),var(--red2));color:#fff;font-weight:950;font-size:16px;cursor:pointer;margin-top:16px;box-shadow:0 14px 26px rgba(201,21,27,.24)}
        .help{margin-top:18px;padding-top:18px;border-top:1px solid var(--line);color:var(--muted);font-size:13px;line-height:1.55}
        .codes{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
        .code{background:#f8fafc;color:#1e40af;border:1px solid #dbeafe;border-radius:999px;padding:7px 10px;font-size:12px;font-weight:900}
        @media(max-width:850px){body{padding:0}.shell{grid-template-columns:1fr;min-height:100vh;border:0;border-radius:0}.brand{min-height:auto;border-right:0;border-bottom:7px solid var(--gold);gap:34px}.brand,.access{padding:26px 20px}}
    </style>
</head>
<body>
<div class="shell">
    <section class="brand">
        <div class="logo">
            <div class="mark">N</div>
            <div>
                <p class="eyebrow">Colegio</p>
                <h1>Nobel Ingenieros</h1>
            </div>
        </div>

        <div class="hero">
            <p class="eyebrow">NOBEX</p>
            <h2>Concurso en orden, de principio a resultados.</h2>
            <p>Acceso centralizado para administrar concursos, participantes, salones, calificaciones y reportes.</p>
            <div class="features">
                <div class="feature"><span class="dot">✓</span>Admin global sin concurso fijo</div>
                <div class="feature"><span class="dot">✓</span>Códigos por concurso, grado y salón</div>
                <div class="feature"><span class="dot">✓</span>Participantes por I.E. y código modular</div>
            </div>
        </div>

        <div class="eyebrow">America/Lima · Sistema NOBEX</div>
    </section>

    <section class="access">
        <p class="eyebrow">Acceso seguro</p>
        <h2>Ingresa tu código</h2>
        <p class="desc">Usa el código entregado por la organización para continuar.</p>

        <?php if (!empty($tablasFaltantes)): ?>
            <div class="msg warn">Faltan tablas en la base de datos: <?php echo nobex_h(implode(', ', $tablasFaltantes)); ?></div>
        <?php endif; ?>

        <?php if ($mensajeError !== ''): ?>
            <div class="msg error"><?php echo nobex_h($mensajeError); ?></div>
        <?php endif; ?>

        <form method="post" action="">
            <input type="hidden" name="csrf_token" value="<?php echo nobex_h($csrf); ?>">
            <label for="codigo">Código de acceso</label>
            <input
                type="text"
                id="codigo"
                name="codigo"
                maxlength="60"
                value="<?php echo nobex_h($codigoIngresado); ?>"
                placeholder="ADMIN-CONCURSO"
                autocomplete="off"
                required
            >
            <button type="submit">Ingresar al panel</button>
        </form>

        <div class="help">
            <strong>Códigos de referencia</strong>
            <div class="codes">
                <?php foreach ($ejemplos as $ejemplo): ?>
                    <span class="code"><?php echo nobex_h($ejemplo); ?></span>
                <?php endforeach; ?>
            </div>
        </div>
    </section>
</div>

<script>
document.addEventListener('DOMContentLoaded', function () {
    var input = document.getElementById('codigo');

    if (input) {
        input.focus();

        input.addEventListener('input', function () {
            input.value = input.value.toUpperCase().replace(/[^A-Z0-9\-]/g, '');
        });
    }
});
</script>
</body>
</html>
