<?php
// concurso_nobel/calificaciones_autosave.php
// Autoguardado de calificaciones por fila mediante AJAX.

declare(strict_types=1);

session_start();

header('Content-Type: application/json; charset=utf-8');

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

function cal_json(bool $ok, string $mensaje, array $extra = []): void
{
    echo json_encode(array_merge([
        'ok' => $ok,
        'message' => $mensaje
    ], $extra), JSON_UNESCAPED_UNICODE);
    exit;
}

function cal_formato_tiempo(?int $segundos): ?string
{
    if ($segundos === null) {
        return null;
    }

    $h = intdiv($segundos, 3600);
    $m = intdiv($segundos % 3600, 60);
    $s = $segundos % 60;

    if ($h > 0) {
        return sprintf('%02d:%02d:%02d', $h, $m, $s);
    }

    return sprintf('%02d:%02d', $m, $s);
}

function cal_parse_tiempo(string $txt): ?int
{
    $txt = trim($txt);

    if ($txt === '') {
        return null;
    }

    if (preg_match('/^\d+$/', $txt)) {
        return (int)$txt;
    }

    if (preg_match('/^(\d{1,2}):(\d{2})$/', $txt, $m)) {
        return ((int)$m[1] * 60) + (int)$m[2];
    }

    if (preg_match('/^(\d{1,2}):(\d{2}):(\d{2})$/', $txt, $m)) {
        return ((int)$m[1] * 3600) + ((int)$m[2] * 60) + (int)$m[3];
    }

    return -1;
}

function cal_puntaje(int $correctas, int $incorrectas, int $blanco, float $pCorrecta, float $pIncorrecta, float $pBlanco): float
{
    return ($correctas * $pCorrecta) - ($incorrectas * $pIncorrecta) + ($blanco * $pBlanco);
}

function cal_recalcular_puestos_categoria(mysqli $conn, int $idConcurso, int $idGrupo, string $tipoInstitucion): void
{
    $stmt = mysqli_prepare($conn, "
        SELECT r.id_resultado
        FROM concurso_resultados r
        INNER JOIN concurso_participantes p
            ON p.id_participante = r.id_participante
        WHERE r.id_concurso = ?
          AND r.id_grupo = ?
          AND r.estado = 'ACTIVO'
          AND p.estado = 'ACTIVO'
          AND p.tipo_institucion = ?
        ORDER BY
          r.puntaje DESC,
          (r.tiempo_segundos IS NULL) ASC,
          r.tiempo_segundos ASC,
          r.correctas DESC,
          r.incorrectas ASC,
          r.id_resultado ASC
    ");

    if (!$stmt) {
        return;
    }

    mysqli_stmt_bind_param($stmt, 'iis', $idConcurso, $idGrupo, $tipoInstitucion);
    mysqli_stmt_execute($stmt);
    $res = mysqli_stmt_get_result($stmt);

    $puesto = 1;

    while ($row = mysqli_fetch_assoc($res)) {
        $idResultado = (int)$row['id_resultado'];

        $up = mysqli_prepare($conn, "
            UPDATE concurso_resultados
            SET puesto = ?
            WHERE id_resultado = ?
            LIMIT 1
        ");

        if ($up) {
            mysqli_stmt_bind_param($up, 'ii', $puesto, $idResultado);
            mysqli_stmt_execute($up);
            mysqli_stmt_close($up);
        }

        $puesto++;
    }

    mysqli_stmt_close($stmt);
}

function cal_recalcular_puestos_grupo(mysqli $conn, int $idConcurso, int $idGrupo): void
{
    cal_recalcular_puestos_categoria($conn, $idConcurso, $idGrupo, 'PRIVADA');
    cal_recalcular_puestos_categoria($conn, $idConcurso, $idGrupo, 'PUBLICA');
}

try {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        cal_json(false, 'Método no permitido.');
    }

    $acceso = cn_validar_acceso($conn, 'index.php');

    if ((int)$acceso['puede_registrar_resultados'] !== 1 && !cn_es_admin($acceso)) {
        cal_json(false, 'Tu código no tiene permiso para registrar calificaciones.');
    }

    $idConcurso = cn_concurso_trabajo($conn, $acceso);

    if ($idConcurso <= 0) {
        cal_json(false, 'No hay concurso activo disponible.');
    }

    $csrfSesion = (string)($_SESSION['csrf_calificaciones_nobex'] ?? '');
    $csrfPost = (string)($_POST['csrf_token'] ?? '');

    if ($csrfSesion === '' || !hash_equals($csrfSesion, $csrfPost)) {
        cal_json(false, 'Solicitud no válida. Recarga la página.');
    }

    $idParticipante = (int)($_POST['id_participante'] ?? 0);
    $idGrupoSeleccionado = (int)($_POST['id_grupo'] ?? 0);

    $correctasRaw = trim((string)($_POST['correctas'] ?? ''));
    $incorrectasRaw = trim((string)($_POST['incorrectas'] ?? ''));
    $tiempoRaw = trim((string)($_POST['tiempo'] ?? ''));
    $observacion = trim((string)($_POST['observacion'] ?? ''));

    if ($idParticipante <= 0) {
        cal_json(false, 'Participante inválido.');
    }

    if ($correctasRaw === '' && $incorrectasRaw === '') {
        cal_json(false, 'Ingrese correctas o incorrectas para guardar.');
    }

    if ($correctasRaw !== '' && !preg_match('/^\d+$/', $correctasRaw)) {
        cal_json(false, 'Correctas debe ser un número entero.');
    }

    if ($incorrectasRaw !== '' && !preg_match('/^\d+$/', $incorrectasRaw)) {
        cal_json(false, 'Incorrectas debe ser un número entero.');
    }

    $correctas = $correctasRaw === '' ? 0 : (int)$correctasRaw;
    $incorrectas = $incorrectasRaw === '' ? 0 : (int)$incorrectasRaw;

    $esAdmin = cn_es_admin($acceso);
    $idGrupoFijo = $esAdmin ? 0 : cn_id_grupo_fijo($acceso);
    $idSalonFijo = $esAdmin ? 0 : cn_id_salon_fijo($acceso);

    $stmtPart = mysqli_prepare($conn, "
        SELECT
            p.id_participante,
            p.id_concurso,
            p.id_grupo,
            p.id_salon,
            p.apellidos_nombres,
            p.tipo_institucion,
            g.total_preguntas,
            g.puntos_correcta,
            g.penalizacion_incorrecta,
            g.puntos_blanco
        FROM concurso_participantes p
        INNER JOIN concurso_grupos g ON g.id_grupo = p.id_grupo
        WHERE p.id_participante = ?
          AND p.id_concurso = ?
          AND p.estado = 'ACTIVO'
        LIMIT 1
    ");

    if (!$stmtPart) {
        cal_json(false, 'No se pudo validar el participante.');
    }

    mysqli_stmt_bind_param($stmtPart, 'ii', $idParticipante, $idConcurso);
    mysqli_stmt_execute($stmtPart);
    $resPart = mysqli_stmt_get_result($stmtPart);
    $part = mysqli_fetch_assoc($resPart);
    mysqli_stmt_close($stmtPart);

    if (!$part) {
        cal_json(false, 'Participante inválido o pertenece a otro concurso.');
    }

    if ($idGrupoFijo > 0 && (int)$part['id_grupo'] !== $idGrupoFijo) {
        cal_json(false, $part['apellidos_nombres'] . ': no pertenece a tu grado asignado.');
    }

    if ($idSalonFijo > 0 && (int)$part['id_salon'] !== $idSalonFijo) {
        cal_json(false, $part['apellidos_nombres'] . ': no pertenece a tu salón asignado.');
    }

    if ($idGrupoSeleccionado > 0 && (int)$part['id_grupo'] !== $idGrupoSeleccionado) {
        cal_json(false, $part['apellidos_nombres'] . ': no pertenece al grado seleccionado.');
    }

    $totalPreguntas = (int)$part['total_preguntas'];

    if ($correctas < 0 || $incorrectas < 0) {
        cal_json(false, 'Correctas e incorrectas no pueden ser negativas.');
    }

    if (($correctas + $incorrectas) > $totalPreguntas) {
        cal_json(false, 'Correctas + incorrectas no puede superar ' . $totalPreguntas . '.');
    }

    $blanco = $totalPreguntas - $correctas - $incorrectas;
    $tiempoSegundos = cal_parse_tiempo($tiempoRaw);

    if ($tiempoSegundos === -1) {
        cal_json(false, 'Tiempo inválido. Usa MM:SS, HH:MM:SS o segundos.');
    }

    $pCorrecta = (float)$part['puntos_correcta'];
    $pIncorrecta = (float)$part['penalizacion_incorrecta'];
    $pBlanco = (float)$part['puntos_blanco'];

    $puntaje = cal_puntaje($correctas, $incorrectas, $blanco, $pCorrecta, $pIncorrecta, $pBlanco);
    $tiempoTexto = cal_formato_tiempo($tiempoSegundos);

    $idGrupoResultado = (int)$part['id_grupo'];
    $idSalonResultado = (int)$part['id_salon'];
    $idAcceso = (int)$acceso['id_acceso'];

    mysqli_begin_transaction($conn);

    $stmtExiste = mysqli_prepare($conn, "
        SELECT id_resultado
        FROM concurso_resultados
        WHERE id_participante = ?
        LIMIT 1
    ");

    $idResultadoExiste = 0;

    if ($stmtExiste) {
        mysqli_stmt_bind_param($stmtExiste, 'i', $idParticipante);
        mysqli_stmt_execute($stmtExiste);
        $resExiste = mysqli_stmt_get_result($stmtExiste);
        $rowExiste = mysqli_fetch_assoc($resExiste);
        $idResultadoExiste = $rowExiste ? (int)$rowExiste['id_resultado'] : 0;
        mysqli_stmt_close($stmtExiste);
    }

    if ($idResultadoExiste > 0) {
        $stmtSave = mysqli_prepare($conn, "
            UPDATE concurso_resultados
            SET
                id_acceso_registro = ?,
                total_preguntas_usada = ?,
                puntos_correcta_usada = ?,
                penalizacion_incorrecta_usada = ?,
                puntos_blanco_usada = ?,
                correctas = ?,
                incorrectas = ?,
                blanco = ?,
                puntaje = ?,
                tiempo_segundos = ?,
                tiempo_texto = ?,
                observacion = ?,
                estado = 'ACTIVO',
                updated_at = NOW()
            WHERE id_resultado = ?
            LIMIT 1
        ");

        if (!$stmtSave) {
            throw new Exception('No se pudo preparar actualización.');
        }

        mysqli_stmt_bind_param(
            $stmtSave,
            'iidddiiidissi',
            $idAcceso,
            $totalPreguntas,
            $pCorrecta,
            $pIncorrecta,
            $pBlanco,
            $correctas,
            $incorrectas,
            $blanco,
            $puntaje,
            $tiempoSegundos,
            $tiempoTexto,
            $observacion,
            $idResultadoExiste
        );
    } else {
        $stmtSave = mysqli_prepare($conn, "
            INSERT INTO concurso_resultados
                (
                    id_concurso,
                    id_grupo,
                    id_salon,
                    id_participante,
                    id_acceso_registro,
                    total_preguntas_usada,
                    puntos_correcta_usada,
                    penalizacion_incorrecta_usada,
                    puntos_blanco_usada,
                    correctas,
                    incorrectas,
                    blanco,
                    puntaje,
                    tiempo_segundos,
                    tiempo_texto,
                    observacion,
                    estado,
                    created_at
                )
            VALUES
                (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'ACTIVO', NOW())
        ");

        if (!$stmtSave) {
            throw new Exception('No se pudo preparar registro.');
        }

        mysqli_stmt_bind_param(
            $stmtSave,
            'iiiiiidddiiidiss',
            $idConcurso,
            $idGrupoResultado,
            $idSalonResultado,
            $idParticipante,
            $idAcceso,
            $totalPreguntas,
            $pCorrecta,
            $pIncorrecta,
            $pBlanco,
            $correctas,
            $incorrectas,
            $blanco,
            $puntaje,
            $tiempoSegundos,
            $tiempoTexto,
            $observacion
        );
    }

    if (!mysqli_stmt_execute($stmtSave)) {
        mysqli_stmt_close($stmtSave);
        throw new Exception('No se pudo guardar la calificación.');
    }

    mysqli_stmt_close($stmtSave);

    cal_recalcular_puestos_grupo($conn, $idConcurso, $idGrupoResultado);

    cn_auditar(
        $conn,
        $idConcurso,
        $idGrupoResultado,
        $idAcceso,
        $idParticipante,
        'CALIFICACION_AUTOGUARDADA',
        'Calificación autoguardada para ' . $part['apellidos_nombres'] . ' | ' . $part['tipo_institucion'] . ' | puntaje ' . $puntaje
    );

    $puestos = [];

    $stmtPuestos = mysqli_prepare($conn, "
        SELECT r.id_participante, r.puesto
        FROM concurso_resultados r
        INNER JOIN concurso_participantes p
            ON p.id_participante = r.id_participante
        WHERE r.id_concurso = ?
          AND r.id_grupo = ?
          AND r.estado = 'ACTIVO'
          AND p.estado = 'ACTIVO'
    ");

    if ($stmtPuestos) {
        mysqli_stmt_bind_param($stmtPuestos, 'ii', $idConcurso, $idGrupoResultado);
        mysqli_stmt_execute($stmtPuestos);
        $resPuestos = mysqli_stmt_get_result($stmtPuestos);

        while ($rowP = mysqli_fetch_assoc($resPuestos)) {
            $puestos[(int)$rowP['id_participante']] = (int)$rowP['puesto'];
        }

        mysqli_stmt_close($stmtPuestos);
    }

    mysqli_commit($conn);

    cal_json(true, 'Guardado automáticamente.', [
        'id_participante' => $idParticipante,
        'correctas' => $correctas,
        'incorrectas' => $incorrectas,
        'blanco' => $blanco,
        'puntaje' => number_format($puntaje, 2, '.', ''),
        'tiempo_texto' => $tiempoTexto ?? '',
        'observacion' => $observacion,
        'puestos' => $puestos
    ]);
} catch (Throwable $e) {
    if (isset($conn) && $conn instanceof mysqli) {
        @mysqli_rollback($conn);
    }

    cal_json(false, 'Error al autoguardar: ' . $e->getMessage());
}