<?php
require_once(dirname(__DIR__) . "/app/functions.php");
$pag = basename($_SERVER['PHP_SELF']);

/**
 * Esta tarea cron comprueba las horas realizadas por los empleados y las compara con las horas relativas
 */

//Como el sistema de incidencias lo gestiona de otra forma, si está activado no se hace nada
if (SISTEMA_INCIDENCIAS) {
    exit;
}

//PRIMERO COGER HORAS DEL CONTRATO DE LOS EMPLEADOS QUE NO ESTÉN EN UN GRUPO FLEXIBLE SEMANAL
$cols_slots = "";
$dias_s = ['lun','mar','mie','jue','vie','sab','dom'];
foreach($dias_s as $d) {
    for($i=1; $i<=10; $i++) {
        $cols_slots .= "g.{$d}h{$i} AS g_{$d}h{$i}, ";
    }
}

$empleados = consulta(
    "SELECT e.*, g.tipo_grupo, g.tipo_flexible, 
            $cols_slots
            g.lunh as g_lunh, g.marh as g_marh, g.mieh as g_mieh, g.jueh as g_jueh, g.vieh as g_vieh, g.sabh as g_sabh, g.domh as g_domh,
            g.lunes as g_lunes, g.martes as g_martes, g.miercoles as g_miercoles, g.jueves as g_jueves, g.viernes as g_viernes, g.sabado as g_sabado, g.domingo as g_domingo
     FROM empleados AS e
    INNER JOIN grupos AS g ON e.id_grupo = g.id
    WHERE g.tipo_grupo=0 OR (g.tipo_grupo=1 AND g.tipo_flexible=1)
    ORDER BY e.id;",
    [],
    true
);

//SEGUNDO RECOGER REGISTROS DEL DÍA ANTERIOR

$registros_dia_anterior = consulta(
    "SELECT id_empleado, hora1, hora2, hora3, hora4, hora5, hora6, hora7, hora8, hora9, hora10, fecha
    FROM `registros` WHERE `fecha`=? AND `activo`=1
    GROUP BY id_empleado;",
    [date('Y-m-d', strtotime('-1 day'))],
    true
);

$tolerancia_minutos = (get_config('minutos_tolerancia_fichaje') ?? 15) * 60;
$minimo_minutos_acumulables = (get_config('minimo_minutos_acumulables') ?? 15) * 60;
$intervalo_redondeo = (get_config('minutos_tolerancia_fichaje') ?? 15) / 60; // En horas (0.25 para 15 min)

/**
 * Redondea las horas al intervalo de tolerancia, siempre hacia abajo (hacia cero)
 * - Si es positivo: redondea hacia abajo (8.03 → 8.00)
 * - Si es negativo: redondea hacia cero (-31.97 → -31.75)
 */
function redondear_horas_tolerancia($horas, $intervalo)
{
    if ($horas >= 0) {
        return floor($horas / $intervalo) * $intervalo;
    } else {
        // Para negativos: floor del valor absoluto, luego negativo
        return floor(abs($horas) / $intervalo) * $intervalo * -1;
    }
}

// TERCERO RECORRER TODOS LOS EMPLEADOS NO FLEXIBLES PARA EL DÍA ANTERIOR

$fecha_ayer = date('Y-m-d', strtotime('-1 day'));

// Cargar inhabilitaciones (vacaciones y festivos) activas ayer
$inh = consulta(
    "SELECT id_empleado, id_grupo FROM dias_inhabiles WHERE fecha_entrada<=? AND fecha_termina>=?;",
    [$fecha_ayer, $fecha_ayer],
    true
);
$inhEmp = [];
$inhGrp = [];
for ($h = 0; $h < count($inh); $h++) {
    if (!empty($inh[$h]['id_empleado'])) $inhEmp[$inh[$h]['id_empleado']] = true;
    if (!empty($inh[$h]['id_grupo'])) $inhGrp[$inh[$h]['id_grupo']] = true;
}

// Cargar bajas médicas activas ayer
$bajas = consulta(
    "SELECT id_empleado FROM bajas_empleado WHERE fecha<=? AND (fecha_incorporacion IS NULL OR fecha_incorporacion>=?);",
    [$fecha_ayer, $fecha_ayer],
    true
);
$bajasEmp = [];
for ($b = 0; $b < count($bajas); $b++) {
    $bajasEmp[$bajas[$b]['id_empleado']] = true;
}

// Convertir registros del día anterior a mapa para acceso ultra-rápido por id_empleado
$regMap = [];
for ($r = 0; $r < count($registros_dia_anterior); $r++) {
    if (!empty($registros_dia_anterior[$r]['hora2'])) {
        $regMap[$registros_dia_anterior[$r]['id_empleado']] = $registros_dia_anterior[$r];
    }
}

for ($e = 0; $e < count($empleados); $e++) {
    $id_empleado = $empleados[$e]['id'];

    // Saber día de la semana para ayer
    $num_dia_semana = (int) date('N', strtotime($fecha_ayer));
    $inicial_dia_semana = match ($num_dia_semana) {
        1 => 'lun', 2 => 'mar', 3 => 'mie', 4 => 'jue', 5 => 'vie', 6 => 'sab', 7 => 'dom',
    };
    $nombre_dia_semana = match ($num_dia_semana) {
        1 => 'lunes', 2 => 'martes', 3 => 'miercoles', 4 => 'jueves', 5 => 'viernes', 6 => 'sabado', 7 => 'domingo',
    };

    // Primero comprobar si el empleado tiene horario personalizado para ese día
    $h1_empleado = $empleados[$e][$inicial_dia_semana . 'h1'] ?? null;
    $tiene_horario_propio = !empty($h1_empleado) && $h1_empleado !== '00:00:00' && $h1_empleado !== '00:00';

    if ($tiene_horario_propio) {
        // El empleado tiene horario personalizado -> usarlo
        $horas_contrato_str = calculo_horas_totales(
            $empleados[$e][$inicial_dia_semana . 'h1'], $empleados[$e][$inicial_dia_semana . 'h2'],
            $empleados[$e][$inicial_dia_semana . 'h3'], $empleados[$e][$inicial_dia_semana . 'h4'],
            $empleados[$e][$inicial_dia_semana . 'h5'], $empleados[$e][$inicial_dia_semana . 'h6'],
            $empleados[$e][$inicial_dia_semana . 'h7'], $empleados[$e][$inicial_dia_semana . 'h8'],
            $empleados[$e][$inicial_dia_semana . 'h9'], $empleados[$e][$inicial_dia_semana . 'h10']
        );
    } else {
        // El empleado NO tiene horario propio -> usar el del grupo
        if ($empleados[$e]['tipo_grupo'] == 0) {
            // Grupo FIJO: calcular horas segun los tramos del grupo
            $horas_contrato_str = calculo_horas_totales(
                $empleados[$e]['g_' . $inicial_dia_semana . 'h1'] ?? '', $empleados[$e]['g_' . $inicial_dia_semana . 'h2'] ?? '',
                $empleados[$e]['g_' . $inicial_dia_semana . 'h3'] ?? '', $empleados[$e]['g_' . $inicial_dia_semana . 'h4'] ?? '',
                $empleados[$e]['g_' . $inicial_dia_semana . 'h5'] ?? '', $empleados[$e]['g_' . $inicial_dia_semana . 'h6'] ?? '',
                $empleados[$e]['g_' . $inicial_dia_semana . 'h7'] ?? '', $empleados[$e]['g_' . $inicial_dia_semana . 'h8'] ?? '',
                $empleados[$e]['g_' . $inicial_dia_semana . 'h9'] ?? '', $empleados[$e]['g_' . $inicial_dia_semana . 'h10'] ?? ''
            );
        } else {
            // Grupo FLEXIBLE diario: verificar si el día está activo
            $dia_activo = $empleados[$e]['g_'.$nombre_dia_semana] ?? false;
            if (!$dia_activo) {
                $horas_contrato_str = '00:00';
            } else {
                $horas_contrato_str = $empleados[$e]['g_'.$inicial_dia_semana . 'h'];
            }
        }
    }

    // Convertir horas teóricas (contrato) a segundos
    if (empty($horas_contrato_str) || $horas_contrato_str === false || strpos($horas_contrato_str, ':') === false) {
        $horas_contrato_segundos = 0;
    } else {
        list($horas_h, $minutos_h) = explode(":", $horas_contrato_str);
        $horas_contrato_segundos = ((int) $horas_h * 3600) + ((int) $minutos_h * 60);
    }

    // SI EL EMPLEADO TRABAJÓ (TIENE REGISTRO)
    if (isset($regMap[$id_empleado])) {
        $reg = $regMap[$id_empleado];
        $horas_realizadas = calculo_horas_totales(
            $reg['hora1'], $reg['hora2'], $reg['hora3'], $reg['hora4'], $reg['hora5'],
            $reg['hora6'], $reg['hora7'], $reg['hora8'], $reg['hora9'], $reg['hora10']
        );

        // Si no hay horas válidas, saltar este registro
        if (empty($horas_realizadas) || $horas_realizadas === false || strpos($horas_realizadas, ':') === false) {
            continue;
        }

        list($horas_r, $minutos_r) = explode(":", $horas_realizadas);
        $horas_realizadas_segundos = ((int) $horas_r * 3600) + ((int) $minutos_r * 60);

        // CUARTO COMPROBAR SI HAY DIFERENCIA Y ACTUALIZAR BOLSA DE HORAS
        $diferencia_segundos = $horas_realizadas_segundos - $horas_contrato_segundos;

        // Si trabajó más horas de las contratadas (fuera de tolerancia superior)
        if ($horas_realizadas_segundos > ($horas_contrato_segundos + $tolerancia_minutos)) {
            if (abs($diferencia_segundos) >= $minimo_minutos_acumulables) {
                $exceso_segundos = $horas_realizadas_segundos - $horas_contrato_segundos;
                $exceso_horas = redondear_horas_tolerancia($exceso_segundos / 3600, $intervalo_redondeo);

                $horas_ant = $empleados[$e]['horas_acu'] ?? 0;
                consulta("UPDATE empleados SET horas_acu=COALESCE(horas_acu, 0)+? WHERE id=?;", [$exceso_horas, $id_empleado], false);
                consulta("INSERT INTO historial_horas_acumuladas_cron (id_empleado, horas_ant, horas, fecha) VALUES (?, ?, ?, ?);", [$id_empleado, $horas_ant, $exceso_horas, $fecha_ayer], false);

                crear_log('info', 'Actualizado horas acumuladas', $pag, "Se han añadido $exceso_horas horas a la bolsa del empleado $id_empleado por horas extras.");
            }
        }
        // Si trabajó menos horas de las contratadas (fuera de tolerancia inferior)
        elseif ($horas_realizadas_segundos < ($horas_contrato_segundos - $tolerancia_minutos)) {
            if (abs($diferencia_segundos) >= $minimo_minutos_acumulables) {
                $exceso_segundos = $horas_contrato_segundos - $horas_realizadas_segundos;
                $exceso_horas = redondear_horas_tolerancia(($exceso_segundos / 3600) * -1, $intervalo_redondeo);

                $horas_ant = $empleados[$e]['horas_acu'] ?? 0;
                consulta("UPDATE empleados SET horas_acu=COALESCE(horas_acu, 0)+? WHERE id=?;", [$exceso_horas, $id_empleado], false);
                consulta("INSERT INTO historial_horas_acumuladas_cron (id_empleado, horas_ant, horas, fecha) VALUES (?, ?, ?, ?);", [$id_empleado, $horas_ant, $exceso_horas, $fecha_ayer], false);

                crear_log('info', 'Actualizado horas acumuladas', $pag, "Se han restado $exceso_horas horas a la bolsa del empleado $id_empleado por defecto de horas.");
            }
        }
    } else {
        // NO TIENE REGISTRO (Ausente)
        // ¿Tenía que trabajar?
        if ($horas_contrato_segundos > 0) {
            // Comprobar justificaciones (vacaciones, festivos, baja)
            $es_inhabil_emp = isset($inhEmp[$id_empleado]);
            $es_inhabil_grp = isset($inhGrp[$empleados[$e]['id_grupo']]);
            $es_baja = isset($bajasEmp[$id_empleado]);

            if (!$es_inhabil_emp && !$es_inhabil_grp && !$es_baja) {
                // Ausencia injustificada
                $exceso_segundos = $horas_contrato_segundos; // todo el turno no trabajado
                // Se resta el total de horas que debió realizar, sin tolerancia y redondeado hacia 0 (será exacto)
                $exceso_horas = redondear_horas_tolerancia(($exceso_segundos / 3600) * -1, $intervalo_redondeo);

                $horas_ant = $empleados[$e]['horas_acu'] ?? 0;
                consulta("UPDATE empleados SET horas_acu=COALESCE(horas_acu, 0)+? WHERE id=?;", [$exceso_horas, $id_empleado], false);
                consulta("INSERT INTO historial_horas_acumuladas_cron (id_empleado, horas_ant, horas, fecha) VALUES (?, ?, ?, ?);", [$id_empleado, $horas_ant, $exceso_horas, $fecha_ayer], false);

                crear_log(
                    'info',
                    'Deducción horas acumuladas (Ausencia)',
                    $pag,
                    "Se han restado $exceso_horas horas al empleado $id_empleado por ausencia injustificada (no hay registros y no es festivo/vacaciones/baja)."
                );
            }
        }
    }
}

//EMPLEADOS DE GRUPOS FLEXIBLES SEMANALES

//Comprobar solo los domingos
if (date('N') != 7)
    exit;

//PRIMERO COGER LOS EMPLEADOS FLEXIBLES SEMANALES
$empleados_flexibles = consulta(
    "SELECT e.*, g.horas, g.dias_trabaja_semana FROM empleados AS e
    INNER JOIN grupos AS g ON e.id_grupo = g.id
    WHERE g.tipo_grupo=1
    AND g.tipo_flexible=2
    ORDER BY e.id;",
    [],
    true
);

//SEGUNDO COGER LOS REGISTROS DE LA SEMANA
$registros_semana = consulta(
    "SELECT id_empleado, hora1, hora2, hora3, hora4, hora5, hora6, hora7, hora8, hora9, hora10, fecha
    FROM `registros` WHERE `fecha` BETWEEN ? AND ? AND `activo`=1
    ORDER BY id;",
    [date('Y-m-d', strtotime('monday this week')), date('Y-m-d', strtotime('sunday this week'))],
    true
);



//TERCERO RECORRER LOS EMPLEADOS FLEXIBLES SEMANALES
for ($e = 0; $e < count($empleados_flexibles); $e++) {

    $id_empleado = $empleados_flexibles[$e]['id'];
    $horas_semana = $empleados_flexibles[$e]['horas'];

    // Si no hay horas definidas, saltar este empleado
    if (empty($horas_semana) || strpos($horas_semana, ':') === false) {
        continue;
    }

    list($horas_h, $minutos_h) = explode(":", $horas_semana);
    $horas_contrato_segundos = ((int) $horas_h * 3600) + ((int) $minutos_h * 60);

    $tolerancia_minutos_semanales = $tolerancia_minutos * ($empleados_flexibles[$e]['dias_trabaja_semana'] ?? 5);

    $horas_realizadas_segundos = 0;

    //CUARTO RECORRER LOS REGISTROS DE LA SEMANA DE ESE EMPLEADO
    for ($r = 0; $r < count($registros_semana); $r++) {
        if ($registros_semana[$r]['id_empleado'] == $id_empleado) {
            // Si el registro es impar o no tiene hora2, no se cuenta
            if (empty($registros_semana[$r]['hora2']))
                continue;

            $horas_realizadas = calculo_horas_totales($registros_semana[$r]['hora1'], $registros_semana[$r]['hora2'], $registros_semana[$r]['hora3'], $registros_semana[$r]['hora4'], $registros_semana[$r]['hora5'], $registros_semana[$r]['hora6'], $registros_semana[$r]['hora7'], $registros_semana[$r]['hora8'], $registros_semana[$r]['hora9'], $registros_semana[$r]['hora10']);

            // Validar que horas_realizadas sea válido
            if (empty($horas_realizadas) || $horas_realizadas === false || strpos($horas_realizadas, ':') === false) {
                continue;
            }

            //convertir string 12:00 a segundos
            list($horas_realizadas_dia, $minutos) = explode(":", $horas_realizadas);
            $horas_realizadas_segundos += ((int) $horas_realizadas_dia * 3600) + ((int) $minutos * 60);
        }
    }

    //QUINTO COMPROBAR SI HAY DIFERENCIA Y ACTUALIZAR BOLSA DE HORAS

    // Calcular diferencia
    $diferencia_segundos_semanal = $horas_realizadas_segundos - $horas_contrato_segundos;
    $minimo_minutos_acumulables_semanal = $minimo_minutos_acumulables * ($empleados_flexibles[$e]['dias_trabaja_semana'] ?? 5);

    // Si trabajó más horas de las contratadas (fuera de tolerancia superior)
    if ($horas_realizadas_segundos > ($horas_contrato_segundos + $tolerancia_minutos_semanales)) {
        // Solo acumular si supera el mínimo de minutos acumulables
        if (abs($diferencia_segundos_semanal) >= $minimo_minutos_acumulables_semanal) {
            $exceso_segundos = $horas_realizadas_segundos - $horas_contrato_segundos;
            //convertir a horas y redondear al intervalo de tolerancia
            $exceso_horas = redondear_horas_tolerancia($exceso_segundos / 3600, $intervalo_redondeo);

            // Sumar las horas a la bolsa
            $horas_ant = $empleados_flexibles[$e]['horas_acu'] ?? 0; // Usar el array de flexibles
            $horas_new = $horas_ant + $exceso_horas;

            consulta(
                "UPDATE empleados SET horas_acu=COALESCE(horas_acu, 0)+? WHERE id=?;",
                [$exceso_horas, $id_empleado],
                false
            );

            // Log change
            consulta(
                "INSERT INTO historial_horas_acumuladas_cron (id_empleado, horas_ant, horas, fecha) VALUES (?, ?, ?, ?);",
                [$id_empleado, $horas_ant, $exceso_horas, date('Y-m-d')],
                false
            );

            crear_log(
                'info',
                'Actualizado horas acumuladas semanal',
                $pag,
                "Se han añadido $exceso_horas horas a la bolsa de horas del empleado con ID $id_empleado por haber trabajado más horas de las contratadas."
            );
        }
        // Si trabajó menos horas de las contratadas (fuera de tolerancia inferior)
    } elseif ($horas_realizadas_segundos < ($horas_contrato_segundos - $tolerancia_minutos_semanales)) {
        // Solo acumular si supera el mínimo de minutos acumulables
        if (abs($diferencia_segundos_semanal) >= $minimo_minutos_acumulables_semanal) {
            $exceso_segundos = $horas_contrato_segundos - $horas_realizadas_segundos;
            //convertir a horas y redondear al intervalo de tolerancia
            $exceso_horas = redondear_horas_tolerancia(($exceso_segundos / 3600) * -1, $intervalo_redondeo);

            // Restar las horas a la bolsa
            $horas_ant = $empleados_flexibles[$e]['horas_acu'] ?? 0;
            $horas_new = $horas_ant + $exceso_horas; // $exceso_horas es negativo

            consulta(
                "UPDATE empleados SET horas_acu=COALESCE(horas_acu, 0)+? WHERE id=?;",
                [$exceso_horas, $id_empleado],
                false
            );

            // Log change
            consulta(
                "INSERT INTO historial_horas_acumuladas_cron (id_empleado, horas_ant, horas, fecha) VALUES (?, ?, ?, ?);",
                [$id_empleado, $horas_ant, $exceso_horas, date('Y-m-d')],
                false
            );

            crear_log(
                'info',
                'Actualizado horas acumuladas semanal',
                $pag,
                "Se han restado $exceso_horas horas a la bolsa de horas del empleado con ID $id_empleado por no haber llegado a las horas contratadas."
            );
        }
    }
    // Si está dentro de la tolerancia: no hacer nada
}
