<?php
require_once("../../functions.php");
if (comprobar_override(str_replace($_SERVER['DOCUMENT_ROOT'], '', __FILE__)))
    exit;
$pag = basename($_SERVER['PHP_SELF']);

$pag_origen = filter_input(INPUT_POST, "pag_origen", FILTER_SANITIZE_SPECIAL_CHARS) ?? 'desconocida';

if ($pag_origen == 'index' && get_config('recaptcha_fichar')) {

    $projectId = RECAPTCHA_PROYECTO;
    $apiKey = RECAPTCHA_API_KEY;
    $siteKey = RECAPTCHA_CLAVE;

    $token = $_POST['recaptcha_token'] ?? '';
    $expectedAction = $_POST['recaptcha_action'] ?? RECAPTCHA_ACTION_FICHAR;
    $threshold = RECAPTCHA_SCORE_FICHAR;

    if (!$token) {
        crear_log("advertencia", "Error reCaptcha", $pag, "Token ausente");
        crear_notificacion('error', 'No se pudo conectar con reCAPTCHA');
        exit;
    }

    $url = "https://recaptchaenterprise.googleapis.com/v1/projects/{$projectId}/assessments?key=" . urlencode($apiKey);

    $payload = [
        'event' => [
            'token' => $token,
            'expectedAction' => $expectedAction,
            'siteKey' => $siteKey,
        ],
    ];

    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'Accept: application/json'],
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_TIMEOUT => 8,
        CURLOPT_CONNECTTIMEOUT => 5,
        CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, // por si IPv6 está roto en el hosting
    ]);
    $response = curl_exec($ch);
    $errno = curl_errno($ch);
    $error = curl_error($ch);
    $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($response === false) {
        crear_log("advertencia", "Error reCaptcha", $pag, "cURL $errno: $error");
        crear_notificacion('error', 'No se pudo conectar con reCAPTCHA');
        exit;
    }

    $r = json_decode($response, true);
    if ($http !== 200 || !is_array($r)) {
        crear_log("advertencia", "Error reCaptcha", $pag, "HTTP $http Body: $response");
        crear_notificacion('error', 'Error de validación reCAPTCHA');
        exit;
    }

    $valid = $r['tokenProperties']['valid'] ?? false;
    $actionToken = $r['tokenProperties']['action'] ?? '';
    $score = $r['riskAnalysis']['score'] ?? 0.0;

    if (!($valid && $actionToken === $expectedAction)) {
        $razones = implode(',', $r['riskAnalysis']['reasons'] ?? []);
        $inv = $r['tokenProperties']['invalidReason'] ?? '';
        crear_log("advertencia", "Error reCaptcha", $pag, "valid=$valid action=$actionToken score=$score reasons=$razones invalid=$inv");
        crear_notificacion('error', 'Verificación reCAPTCHA no superada');
        exit;
    }

    if ($score < $threshold) {
        $razones = implode(',', $r['riskAnalysis']['reasons'] ?? []);
        $inv = $r['tokenProperties']['invalidReason'] ?? '';
        crear_log("advertencia", "Error reCaptcha", $pag, "valid=$valid action=$actionToken score=$score reasons=$razones invalid=$inv");
    }
}
if ($pag_origen == 'index') {
    $id = filter_input(INPUT_POST, "id_empleado", FILTER_SANITIZE_NUMBER_INT);
    $contra = filter_input(INPUT_POST, "pin", FILTER_SANITIZE_NUMBER_INT);

    $latitud = filter_input(INPUT_POST, "latitud", FILTER_SANITIZE_SPECIAL_CHARS) ?? filter_input(INPUT_GET, "latitud", FILTER_SANITIZE_SPECIAL_CHARS);
    $longitud = filter_input(INPUT_POST, "longitud", FILTER_SANITIZE_SPECIAL_CHARS) ?? filter_input(INPUT_GET, "longitud", FILTER_SANITIZE_SPECIAL_CHARS);
    // Sanitizar valores inválidos que llegan como string "null" o "undefined" desde JS
    if ($latitud === 'null' || $latitud === 'undefined' || $latitud === '') $latitud = null;
    if ($longitud === 'null' || $longitud === 'undefined' || $longitud === '') $longitud = null;
} else {
    // NUEVO: Fichaje por huella
    if ($pag_origen == 'huella' && !empty($_POST['id_empleado'])) {
        $id = filter_input(INPUT_POST, "id_empleado", FILTER_SANITIZE_NUMBER_INT);
        $latitud = null;
        $longitud = null;
    } else {
        if (session_status() !== PHP_SESSION_ACTIVE)
            session_start();

        // Obtener id_empleado de la sesión, o buscarlo por id_usuario si no está disponible
        if (!empty($_SESSION['id_empleado'])) {
            $id = $_SESSION['id_empleado'];
        } elseif (!empty($_SESSION['id_usuario'])) {
            $emp = consulta("SELECT id FROM empleados WHERE id_usuario = ? LIMIT 1;", [$_SESSION['id_usuario']], true);
            if (!empty($emp)) {
                $id = $emp[0]['id'];
            } else {
                crear_log("error", "Error al fichar", $pag, "No se encontró empleado para el usuario ID: " . $_SESSION['id_usuario']);
                crear_notificacion('error', "No se encontró tu perfil de empleado");
                exit;
            }
        } else {
            crear_log("error", "Error al fichar", $pag, "Sesión sin id_empleado ni id_usuario");
            crear_notificacion('error', "Sesión inválida, vuelve a iniciar sesión");
            exit;
        }

        // Leer ubicación si viene desde fichajes con LOCALIZACION activo
        $latitud = filter_input(INPUT_POST, "latitud", FILTER_SANITIZE_SPECIAL_CHARS);
        $longitud = filter_input(INPUT_POST, "longitud", FILTER_SANITIZE_SPECIAL_CHARS);
        if ($latitud === 'null' || $latitud === 'undefined' || $latitud === '') $latitud = null;
        if ($longitud === 'null' || $longitud === 'undefined' || $longitud === '') $longitud = null;
    }
}
$nombre = consulta("SELECT nombre FROM empleados WHERE id=?;", [$id], true)[0]["nombre"];

const TiempoEspera = 0.25;
const HorasMax = 10;
$actual = date("Y-m-d");
$actualh = date("H:i:s");
$horaactual = date("H");
$minactual = date("i");
$horas = date("H:i:s");

// Determinar origen del fichaje para guardar en BD y log
$origen_label = match ($pag_origen) {
    'index' => 'Tablet',
    'fichajes' => 'Sesión',
    'huella' => 'Huella',
    default => $pag_origen,
};

if (!empty($contra) || $pag_origen == 'fichajes' || $pag_origen == 'huella') {
    if ($pag_origen == 'index') {
        $empleado = consulta(
            "SELECT * FROM `empleados` WHERE id=? AND pin=?;",
            [$id, $contra],
            true
        );
    } elseif ($pag_origen == 'fichajes' || $pag_origen == 'huella') {
        // Fichaje por huella o desde fichajes - no requiere PIN
        $empleado = consulta(
            "SELECT * FROM `empleados` WHERE id=?;",
            [$id],
            true
        );
    }
    if (empty($empleado)) {
        $ip = $_SERVER['REMOTE_ADDR'];
        $cache_file = sys_get_temp_dir() . '/fichapp_bf_' . md5($ip) . '.txt';
        
        $intentos = 0;
        if (file_exists($cache_file)) {
            // Reiniciar contador si han pasado más de 15 minutos desde el último intento fallido
            if (time() - filemtime($cache_file) > 900) {
                unlink($cache_file);
            } else {
                $intentos = (int)file_get_contents($cache_file);
            }
        }
        $intentos++;
        file_put_contents($cache_file, $intentos);
        
        // Retraso progresivo solo después de 3 intentos fallidos recientes
        if ($intentos > 3) {
            sleep(min(($intentos - 3) * 2, 8)); // Sube hasta 8s máximo
        }

        crear_log("error", "Error al fichar", $pag, "<b>[$nombre]</b>, empleado o pin incorrecto. Intento $intentos");
        crear_notificacion('error', "¡Pin incorrecto $nombre!");
        exit;
    } else {
        // Reset brute force counter on success
        $ip = $_SERVER['REMOTE_ADDR'];
        $cache_file = sys_get_temp_dir() . '/fichapp_bf_' . md5($ip) . '.txt';
        if (file_exists($cache_file)) unlink($cache_file);
    }

    // Determinar la fecha objetivo para el fichaje
    $fecha_fichaje = $actual;

    // Sistema de horarios nocturnos
    if (SISTEMA_HORARIOS_NOCTURNOS && $empleado[0]["horario_nocturno"] == 1) {
        $hora_actual = strtotime($actualh);
        $hora_limite = strtotime(HORA_LIMITE_HORARIOS_NOCTURNOS);
        $medianoche = strtotime("00:00:00");

        // Si la hora está entre 00:00 y la hora límite, usar el día anterior
        if ($hora_actual >= $medianoche && $hora_actual < $hora_limite) {
            $fecha_fichaje = date("Y-m-d", strtotime($actual . " -1 day"));
        }
    }

    // Obtener tipo de registro si existe
    $tipo_registro = filter_input(INPUT_POST, "tipo_registro", FILTER_SANITIZE_SPECIAL_CHARS) ?? '';

    if (
        !empty($registro = consulta(
            "SELECT * FROM registros WHERE id_empleado=? AND fecha=? AND activo=1 ORDER BY id DESC LIMIT 1;",
            [$id, $fecha_fichaje],
            true
        ))
    ) {
        if ($registro[0]["fecha"] == $fecha_fichaje) {
            $es_salida_sin_entrada = false;

            $max_filled = 0;
            $ultima_hora_registrada = null;
            for ($k = 10; $k >= 1; $k--) {
                if (!empty($registro[0]["hora" . $k]) && $registro[0]["hora" . $k] != "00:00:00") {
                    $ultima_hora_registrada = $registro[0]["hora" . $k];
                    $max_filled = $k;
                    break;
                }
            }

            if ($tipo_registro === 'entrada') {
                $o = ($max_filled % 2 === 0) ? $max_filled + 1 : $max_filled + 2;
                if ($max_filled === 0) $o = 1;
            } elseif ($tipo_registro === 'salida') {
                $o = ($max_filled % 2 === 0) ? $max_filled + 2 : $max_filled + 1;
                if ($max_filled === 0) $o = 2;
            } else {
                for ($o = 1; $o <= 10; $o++) {
                    if (empty($registro[0]["hora" . $o]) || $registro[0]["hora" . $o] == "00:00:00") {
                        break;
                    }
                }
            }

            if ($o > 10) {
                crear_notificacion('error', "No puedes realizar más de 10 fichajes al día.");
                exit;
            }

            if ($ultima_hora_registrada) {
                $h_registo = strtotime($ultima_hora_registrada);
                $h_act = strtotime($actualh);
                $resto = $h_act - $h_registo;
                $tolerancia_minutos = (get_config('minutos_tolerancia_fichaje') ?? 15) * 60;
                if ($resto <= $tolerancia_minutos) { // Menos de 15 minutos
                    crear_notificacion('advertencia', "¡Ya habías fichado, $nombre!");
                    exit;
                }
            }

            $relleno_ceros = '';
            if (isset($tipo_registro) && in_array($tipo_registro, ['entrada', 'salida'])) {
                for ($i = 1; $i < $o; $i++) {
                    if (empty($registro[0]["hora" . $i]) || $registro[0]["hora" . $i] == "00:00:00") {
                        $relleno_ceros .= "hora$i='00:00:00', ";
                    }
                }
            }

            $is_update = true;
            $condicion = "id=? AND activo=1";
            $array_cond = [$registro[0]["id"]];
            $ok = registrar_fichaje_db('registros', $is_update, $condicion, $array_cond, $id, $nombre, $fecha_fichaje, $o, $relleno_ceros, $latitud, $longitud, $origen_label, $horas, $tipo_registro);
        }
    } else {
        if ($tipo_registro === 'salida') {
            $o = 2;
            $es_salida_sin_entrada = true;
        } else {
            $es_salida_sin_entrada = false;
            $o = 1;
        }
        $is_update = false;
        $condicion = "";
        $array_cond = [];
        $ok = registrar_fichaje_db('registros', $is_update, $condicion, $array_cond, $id, $nombre, $fecha_fichaje, $o, '', $latitud, $longitud, $origen_label, $horas, $tipo_registro);
    }

    // Ejecutar consulta para `registros`
    if ($ok) {
        if (SISTEMA_INSPECTOR) {
            //Comprobar si usuario tiene horario asignado
            $horario_regular = consulta("SELECT sin_horario_asignado FROM `empleados` WHERE id=?;", [$id], true)[0]['sin_horario_asignado'];
            if (SISTEMA_CAMBIO_HORARIO_REGULAR && $horario_regular) {
                //Comprobar si existe ya el registro en el inspector
                if (empty($registro_insp = consulta("SELECT * FROM `registros_inspector` WHERE id_empleado=? AND fecha=?", [$id, $fecha_fichaje], true))) {
                    if (!registrar_fichaje_db('registros_inspector', false, "", [], $id, $nombre, $fecha_fichaje, $o, '', $latitud, $longitud, $origen_label, $horas, $tipo_registro)) {
                        crear_log("error", "Error al fichar", $pag, "<b>[$nombre]</b> no ha podido fichar porque ha ocurrido un error en la consulta en el sistema de horario asignado.");
                    }
                } else {
                    $cond_insp = "id_empleado=? AND fecha=?";
                    $arr_insp = [$id, $registro_insp[0]["fecha"]];
                    registrar_fichaje_db('registros_inspector', true, $cond_insp, $arr_insp, $id, $nombre, $fecha_fichaje, $o, $relleno_ceros, $latitud, $longitud, $origen_label, $horas, $tipo_registro);
                    crear_log("info", "Fichado", $pag, "<b>[$nombre]</b> no ha podido fichar porque ha ocurrido un error en la consulta en el sistema de horario asignado.");
                }
            } else {
                //Comprobar si existe registro
                if (!empty($registro_insp = consulta("SELECT * FROM registros_inspector WHERE id_empleado=? AND fecha=? AND activo=1 ORDER BY id DESC LIMIT 1;", [$id, $fecha_fichaje], true))) {
                    //Si es misma fecha actualiza
                    if ($registro_insp[0]["fecha"] == $fecha_fichaje) {
                        $cond_insp = "id_empleado=? AND fecha=?";
                        $arr_insp = [$id, $registro_insp[0]["fecha"]];
                        registrar_fichaje_db('registros_inspector', true, $cond_insp, $arr_insp, $id, $nombre, $fecha_fichaje, $o, $relleno_ceros, $latitud, $longitud, $origen_label, $horas, $tipo_registro);
                    }
                } else {
                    //Sino rellena crea con el normal
                    registrar_fichaje_db('registros_inspector', false, "", [], $id, $nombre, $fecha_fichaje, $o, '', $latitud, $longitud, $origen_label, $horas, $tipo_registro);
                }
            }
        }
        // Log del fichaje exitoso
        // $origen_label ya definido arriba
        $ubicacion = (!empty($latitud) && !empty($longitud))
            ? "Lat: $latitud, Lon: $longitud"
            : "Sin ubicacion";
        crear_log(
            "info",
            "Fichaje registrado",
            $pag,
            "ID empleado: <b>$id</b> | Fecha: <b>$fecha_fichaje</b> | Origen: <b>$origen_label</b> | Ubicacion: $ubicacion"
        );
        crear_notificacion('correcto', "¡Fichado correctamente $nombre, $horaactual:$minactual!");
    } else {
        crear_log("error", "Error al fichar", $pag, "<b>[$nombre]</b> no ha podido fichar porque ha ocurrido un error en la consulta [$consulta1].");
        crear_notificacion('error', "¡Error al fichar $nombre, ha ocurrido un error interno!");
    }
} else {
    crear_log("error", "Error al fichar", $pag, "<b>[$nombre]</b> no hay pin.");
    crear_notificacion('error', "¡Pin incorrecto $nombre!");
}
