<?php
header('Expires: Sun, 01 Jan 2014 00:00:00 GMT');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header('Cache-Control: no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header("Content-Type: application/json; charset=utf-8");
header("Access-Control-Allow-Origin: *");

date_default_timezone_set('America/Mexico_City');
#die("error");

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);

ignore_user_abort(true);
set_time_limit(0);

function error_response($failure, array $info = [], array $errores = [])
{
    $mensajes = [
        "clave" => "Faltó la clave del profesor",
        "profesor" => "No se encontró el profesor",
        "horario" => "No se encontró el horario",
        "asistencia" => "No se pudo registrar la asistencia",
        "hora" => "No se pudo obtener la hora",
    ];

    die(json_encode(array_merge([
        'ok' => false,
        'msg' => $mensajes[$failure],
        'failure' => $failure,
        'errores' => $errores,
        'horarios' => [],
        'duplicadas' => [],
        // 'env' => $_ENV,

    ], $info), JSON_PRETTY_PRINT));
}

require_once "include/bd_pdo.php";
require_once "include/LogAsistencias.php";

$log = new LogAsistencias();

$clave = $_POST['cve'] ?? $_GET['cve'] ?? null;
$origen = $_POST['origen'] ?? null;

$log_id = $db->insert('log_registro', [
    'clave' => $clave,
    'ip' => $_SERVER['REMOTE_ADDR'],
    'navegador' => $_SERVER['HTTP_USER_AGENT'] ?? 'Móvil',
    'informacion' => 'Conexión',
    'detalle' => 'Se hizo una conexión al servidor',
    'origen' => $origen,
], 'log_id');

if (is_null($clave))
    error_response("datos");

// Datos de usuario

$profesor = $db->querySingle(
    "SELECT * FROM profesor WHERE profesor_clave::INT = :clave",
    [':clave' => intval(preg_replace('/[^0-9]/', '', $clave))]
);

if (empty($profesor)) {
    $log->appendLog($clave, "ND", "No registrada [Error] Msg: No se encontró el profesor");
    $db->where('log_id', $log_id)->update(
        'log_registro',
        [
            'informacion' => 'Profesor',
            'detalle' => 'No registrada [Error] Msg: No se encontró el profesor',
        ]
    );
    error_response("profesor", array("clave" => $clave));
} else {
    $db->where('log_id', $log_id)->update(
        'log_registro',
        [
            'profesor' => $profesor['profesor_nombre'],
        ]
    );
    // profesor -> profesor_horario -> horario -> materia -> carrera
    // get carreras from a profesor:
    $carreras = array_map(
        fn($carrera) => $carrera['carrera_id'],
        $db->query(
            "SELECT DISTINCT carrera_id FROM horario_profesor
        join horario using (horario_id)
        join materia using (materia_id)
        join carrera using (carrera_id)
        where profesor_id = :profesor_id",
            [':profesor_id' => $profesor['profesor_id']]
        )
    );
}

$avisos = array_map(fn($aviso) => $aviso['aviso_texto'], $db
    ->join('aviso_profesor', 'aviso.aviso_id = aviso_profesor.aviso_id', 'LEFT')
    ->join('aviso_carrera', 'aviso.aviso_id = aviso_carrera.aviso_id', 'LEFT')
    ->where('carrera_id', $carreras)
    ->where('profesor_id', $profesor['profesor_id'], '=', 'OR')
    ->where('aviso_fecha_inicial', date('Y-m-d'), '<=')
    ->where('aviso_fecha_final', date('Y-m-d'), '>=')
    ->where('aviso_estado')
    ->get("aviso"));

$asistencia = $db->query(
    isset($_POST['cve']) ?
    "WITH horarios AS (
        SELECT horario_view.*, profesor_id, CURRENT_TIME > (HORARIO_HORA + :retardo * INTERVAL '1 minute') as retardo FROM horario_view
        join horario_profesor using (horario_id)
        where CURRENT_TIME between horario_hora - interval '1 MINUTE' * :antes and horario_hora + interval '1 MINUTE' * :despues
        and (HORARIO_DIA, PROFESOR_ID) = (EXTRACT('DOW' FROM CURRENT_DATE), :profesor_id)
    ),
    reposiciones AS (
        SELECT horario_view.*, profesor_id, CURRENT_TIME > (HORARIO_HORA + :retardo * INTERVAL '1 minute') as retardo FROM horario_view
        join registro using (horario_id)
        join reposicion using (reposicion_id)
        where CURRENT_TIME between REPOSICION_HORA - interval '1 MINUTE' * :antes and REPOSICION_HORA + interval '1 MINUTE' * :despues
        and (REPOSICION_FECHA, PROFESOR_ID) = (CURRENT_DATE, :profesor_id)
    ),
    registros AS (
        INSERT INTO public.registro(registro_fecha, registro_retardo, horario_id, registro_fecha_ideal, profesor_id)
        select NOW(), retardo, horario_id, current_date, profesor_id from horarios
                                            UNION
        SELECT NOW(), retardo, horario_id, current_date, profesor_id from reposiciones
        ON CONFLICT (horario_id, registro_fecha_ideal, profesor_id) DO UPDATE SET registro_fecha = COALESCE(registro.registro_fecha, NOW())
        RETURNING *, (NOW() <> registro_fecha) duplicado
    )
    SELECT HORARIOS.*, REGISTROS.*
        FROM horarios
        LEFT JOIN registros using (horario_id, profesor_id)
                    UNION
    SELECT REPOSICIONES.*, REGISTROS.*
        FROM reposiciones
        LEFT JOIN registros using (horario_id, profesor_id)
    "
    : (isset($_GET['cve']) ?
        "SELECT *, registro_fecha is not null duplicado, :retardo FROM horario_view
                join horario_profesor using (horario_id)
                left join registro on (horario_view.horario_id, horario_profesor.profesor_id, current_date) = (registro.horario_id, registro.profesor_id, registro.registro_fecha_ideal)
                where current_time between horario_hora - interval '1 MINUTE' * :antes and horario_hora + interval '1 MINUTE' * :despues
                and (HORARIO_DIA, horario_profesor.PROFESOR_ID) = (EXTRACT('DOW' FROM CURRENT_DATE), :profesor_id)"
        : "SELECT NULL"),
    [
        ':antes' => $_ENV['ANTES'],
        ':despues' => $_ENV['DESPUES'],
        ':retardo' => $_ENV['RETARDO'],
        ':profesor_id' => $profesor['profesor_id'],
    ]
);

if (empty($asistencia)) {
    $log->appendLog($profesor['profesor_clave'], $profesor['profesor_nombre'], "No registrada [Error] Msg: No se encontró el horario");
    $db->where('log_id', $log_id)->update(
        'log_registro',
        [
            'informacion' => 'Horario',
            'detalle' => 'No registrada [Error] Msg: No se encontró el horario',
        ]
    );

    // if method post
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {


        $curl = curl_init();

        curl_setopt_array($curl, [
            CURLOPT_URL => "{$_ENV['PAAD_URL']}/api/horario_profesor_log.php",
            CURLOPT_TIMEOUT => 1,
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS => json_encode([
                'profesor_id' => $profesor['profesor_id'],
                'log_id' => $log_id,
            ])
        ]);

        curl_exec($curl);
        curl_close($curl);
    }

    error_response(
        "horario",
        info: [
            'nombre' => $profesor['profesor_nombre'],
            'avisos' => $avisos,
        ]
    );
}
$duplicadas = array_filter($asistencia, fn($registro) => $registro['duplicado']);
$horarios = array_filter($asistencia, fn($registro) => !$registro['duplicado']);

if (!empty($duplicadas)) {
    $log->appendLog($profesor['profesor_clave'], $profesor['profesor_nombre'], "No registrada [Duplicada] Msg: Ya se registró la asistencia");
    $db->where('log_id', $log_id)->update(
        'log_registro',
        [
            'informacion' => 'Asistencia',
            'detalle' => 'No registrada [Duplicada] Msg: Ya se registró la asistencia',
            'success' => true,
            'horarios' => json_encode($asistencia),
        ]
    );
} else {
    $log->appendLog($profesor['profesor_clave'], $profesor['profesor_nombre'], "Registrada");
    $db->where('log_id', $log_id)->update(
        'log_registro',
        [
            'informacion' => 'Asistencia',
            'detalle' => 'Registrada',
            'success' => true,
            'horarios' => json_encode($asistencia),
        ]
    );
}

$duplicadas = array_reduce($duplicadas, function ($carry, $horario) use ($db) {
    // $facultad = $horario['facultad_id'];
    $facultad = $db->where('facultad_id', $horario['facultad_id'])->getOne('facultad')['facultad_nombre'];
    if (!isset($carry[$facultad]))
        $carry[$facultad] = [];
    $carry[$facultad][] = $horario;
    return $carry;
}, []);


// collect in one array all the horarios by facultad_nombre => {$horarios}
$horarios = array_reduce($horarios, function ($carry, $horario) use ($db) {
    // $facultad = $horario['facultad_id'];
    $facultad = $db->where('facultad_id', $horario['facultad_id'])->getOne('facultad')['facultad_nombre'];
    if (!isset($carry[$facultad]))
        $carry[$facultad] = [];
    $carry[$facultad][] = $horario;
    return $carry;
}, []);

die(json_encode([
    'ok' => true,
    'profesor' => $profesor,
    'horarios' => $horarios,
    'duplicadas' => $duplicadas,
    'avisos' => $avisos,
], JSON_PRETTY_PRINT));