<?php

// Requiere el modelo de logIn

require_once __DIR__ . '/../models/logInModel.php';
$loginmodel = new logInModel();

$opt = $_GET['opt'] ?? 'login_operador';

// Manejo de opt enviado por URL

switch ($opt) {

    // LOGIN

    case 'login':

        if ($_SERVER['REQUEST_METHOD'] === 'GET') {

            if (isset($_SESSION['reset_autorizado'])) {
                unset($_SESSION['reset_autorizado']);
            }

            ob_start();
            require __DIR__ . '/../views/login/logInView.php';
            return ob_get_clean();
        }

        $usuario  = trim($_POST['usuario'] ?? ''); // Se almacenan los datos enviados por $_POST desde el form en las variables
        $password = trim($_POST['password'] ?? '');

        $errores = [];

        // Validaciones para iniciar sesión

        if ($usuario === '') {
            $errores[] = "El usuario no puede estar vacío.";
        } elseif (!preg_match('/^(?=.*[a-zA-Z])(?!.*[._]{2})[a-zA-Z0-9._]{5,30}$/', $usuario)) {
            $errores[] = "El usuario debe tener 5–30 caracteres, incluir al menos una letra y solo usar letras, números, puntos o guiónes bajos no consecutivos.";
        }

        if ($password === '') {
            $errores[] = "La contraseña no puede estar vacía.";
        } elseif (strpos($password, ' ') !== false) {
            $errores[] = "La contraseña no puede contener espacios.";
        } elseif (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{6,}$/', $password)) {
            $errores[] = "La contraseña debe tener al menos una mayúscula, una minúscula y un número, y mínimo 6 caracteres.";
        }

        // Control de intentos de inicio de sesión

        $maxIntentos = 3;
        $tiempoBloqueo = 60; // segundos

        if (!isset($_SESSION['login_intentos'])) {
            $_SESSION['login_intentos'] = 0;
            $_SESSION['login_ultimo_intento'] = time();
        }

        // Si pasó el tiempo, resetear

        if (time() - $_SESSION['login_ultimo_intento'] > $tiempoBloqueo) {
            $_SESSION['login_intentos'] = 0;
        }

        // Verificar bloqueo

        if ($_SESSION['login_intentos'] >= $maxIntentos) {
            $_SESSION['flash_error'] = "Demasiados intentos. Espere 1 minuto antes de volver a intentar.";
            header("Location: index.php?opt=login_operador");
            exit;
        }

        // Si existen errores de validación, se informan definiendo flash_error en el array asociativo $_SESSION

        if (!empty($errores)) {

            // Se suma el intento erroneo de inicio de sesión y se guarda el tiempo

            $_SESSION['login_intentos']++;
            $_SESSION['login_ultimo_intento'] = time();

            $_SESSION['flash_error'] = implode('<br>', $errores); // Agrega un salto de linea entre cada error encontrado y los guarda en $_SESSION
            header("Location: index.php?opt=login_operador");
            exit;
        }

        // Si no existen errores, buscamos el usuario mediante logInModel

        $user = $loginmodel->buscarPorUsuario($usuario);

        if (!$user || !password_verify($password, $user['password'])) {

            $_SESSION['login_intentos']++;
            $_SESSION['login_ultimo_intento'] = time();

            $_SESSION['flash_error'] = 'Usuario o contraseña incorrectos';
            header("Location: index.php?opt=login_operador");
            exit;
        }

        // Verificamos el rol del usuario para cargar la vista correspondiente

        if ($user['rol'] === 'operador') {

            // Se resetean los intentos

            $_SESSION['login_intentos'] = 0;
            $_SESSION['login_ultimo_intento'] = time();

            $_SESSION['user'] = $user; // Se define $user dentro del array asociativo $_SESSION para tenerlo disponible en todo el sistema
            header("Location: index.php?opt=inicio_operador");
            exit;

        } else if ($user['rol'] === 'admin') {

            // Se resetean los intentos

            $_SESSION['login_intentos'] = 0;
            $_SESSION['login_ultimo_intento'] = time();

            $_SESSION['user'] = $user; // Se define $user dentro del array asociativo $_SESSION para tenerlo disponible en todo el sistema
            header("Location: index.php?opt=inicio_admin");
            exit;
        }

    // HOME OPERADOR

    case 'home_operador':

        // Validar sesión

        if (!isset($_SESSION['user'])) {
            header("Location: index.php?opt=login_operador");
            exit;
        }

        // Si el rol es admin, se redirigue al home_admin (en caso de ingresar por URL)

        if ($_SESSION['user']['rol'] !== 'operador') {
            header("Location: index.php?opt=home_admin");
            exit;
        }

        // Se carga en caché el home operador y se envía el HTML

        ob_start();
        require __DIR__ . '/../views/login/homeOperadorView.php';
        return ob_get_clean();

    // HOME ADMIN

    case 'home_admin':

        // Validar sesión

        if (!isset($_SESSION['user'])) {
            header("Location: index.php?opt=login_admin");
            exit;
        }

        // Si el rol es operador, se redirigue al home_operador (en caso de ingresar por URL)

        if ($_SESSION['user']['rol'] !== 'admin') {
            header("Location: index.php?opt=home_operador");
            exit;
        }

        // Se carga en caché el home admin y se envía el HTML

        ob_start();
        require __DIR__ . '/../views/login/homeAdminView.php';
        return ob_get_clean();

    // INICIO OPERADOR

    case 'inicio_operador':

        // Validar sesión

        if (!isset($_SESSION['user'])) {
            header("Location: index.php?opt=login_operador");
            exit;
        }

        // Si el rol es admin, se redirigue al inicio_admin (en caso de ingresar por URL)

        if ($_SESSION['user']['rol'] !== 'operador') {
            header("Location: index.php?opt=inicio_admin");
            exit;
        }

        // Se carga en caché el inicio operador y se envía el HTML

        ob_start();
        require __DIR__ . '/../views/login/inicioOperadorView.php';
        return ob_get_clean();

    // INICIO ADMIN

    case 'inicio_admin':

        // Validar sesión

        if (!isset($_SESSION['user'])) {
            header("Location: index.php?opt=login_admin");
            exit;
        }

        // Si el rol es operador, se redirigue al inicio_operador (en caso de ingresar por URL)

        if ($_SESSION['user']['rol'] !== 'admin') {
            header("Location: index.php?opt=inicio_operador");
            exit;
        }

        // Calcular si mostrar alerta de backup (solo a admin)

        if ($_SESSION['user']['rol'] === 'admin') {

            require __DIR__ . '/../models/configuracionModel.php';
            $configuracionmodel = new configuracionModel();

            $fechaUltimoBackup = $configuracionmodel->obtenerFechaUltimoBackup();

            if ($fechaUltimoBackup) {

                $dias = (new DateTime($fechaUltimoBackup))->diff(new DateTime())->days;

                if ($dias >= 7) {

                    header("Location: index.php?opt=generar_backup&from=inicio_admin&auto=1");
                    exit;
                }

            } else {

                $ahora = time();

                // Si nunca se mostró o ya pasó 1 hora

                if (!isset($_SESSION['ultimo_aviso_backup']) || ($ahora - $_SESSION['ultimo_aviso_backup']) >= 3600) {
                    
                    $_SESSION['flash_error'] = "No se encontraron copias de seguridad. Por favor, verifique.";

                    // Guardamos cuándo mostramos el mensaje
                    
                    $_SESSION['ultimo_aviso_backup'] = $ahora;
                }
            }
        }

        // Se carga en caché el inicio admin y se envía el HTML

        ob_start();
        require __DIR__ . '/../views/login/inicioAdminView.php';
        return ob_get_clean();

    // LOGOUT

    case 'logout':

        session_unset(); // Libera las variables almacenadas en $_SESSION
        session_destroy(); // Destruye la sesión del servidor
        setcookie(session_name(), '', time() - 3600, '/'); // Borra la cookie en el navegaodor

        header("Location: index.php?opt=login");
        exit;

    // CARGAR VISTA README (AYUDA)

    case 'readme':

        if ($_SERVER['REQUEST_METHOD'] === 'GET') {

            ob_start();
            require __DIR__ . '/../views/ayudas/readMe.php';
            return ob_get_clean();
        }

    // RECUPERACIÓN DE CUENTA

    case 'recuperar_cuenta':

        if ($_SERVER['REQUEST_METHOD'] === 'GET') {

            ob_start();
            require __DIR__ . '/../views/login/recuperarCuentaView.php';
            return ob_get_clean();
        }

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

            if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) { // Recorre todos los caracteres (siempre) y retorna true or false
                $_SESSION['flash_error'] = 'Acción inválida.';
                header('Location: index.php?opt=login');
                exit;
            }

            // Requiero modelos necesarios

            require_once __DIR__ . '/../models/usuarioModel.php';
            $usuariomodel = new usuarioModel();
            
            require_once __DIR__ . '/../models/logInModel.php';
            $loginmodel = new logInModel();

            require_once __DIR__ . '/../helpers/email_recuperar_cuenta.php';

            $email = trim($_POST['email'] ?? $_SESSION['reset_email'] ?? '');

            // Cooltime de envío de mails

            if (isset($_SESSION['ultimo_envio_codigo'])) {

                $segundosRestantes = 60 - (time() - $_SESSION['ultimo_envio_codigo']);

                if ($segundosRestantes > 0) {

                    $_SESSION['flash_success'] = "Ya se envió un código recientemente. Espere {$segundosRestantes} segundos.";

                    header('Location: index.php?opt=verificar_codigo');
                    exit;
                }
            }

            // Validación

            if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $_SESSION['flash_error'] = 'Email inválido';
                header('Location: index.php?opt=recuperar_cuenta');
                exit;
            }

            // Buscar usuario

            $usuario = $usuariomodel->obtenerPorEmail($email);

            // Siempre respuesta genérica (seguridad)

            if (!$usuario || $usuario['rol'] !== 'admin') {
                $_SESSION['flash_error'] = 'Si el correo ingresado es válido, recibirás un código de verificación.';
                header('Location: index.php?opt=recuperar_cuenta');
                exit;
            }

            // Generar código

            $codigo = random_int(100000, 999999);
            $codigoHash = password_hash($codigo, PASSWORD_DEFAULT);

            $expira = date('Y-m-d H:i:s', strtotime('+10 minutes'));

            // Invalidar códigos anteriores

            if (!$loginmodel->invalidarPorUsuario($usuario['id'])) {
                $_SESSION['flash_error'] = 'Ocurrió un error inesperado.';
                header('Location: index.php?opt=recuperar_cuenta');
                exit;
            }

            // Guardar nuevo código

            if (!$loginmodel->crear([
                'id_usuario' => $usuario['id'],
                'codigo' => $codigoHash,
                'expira_a' => $expira
            ])) {
                $_SESSION['flash_error'] = 'Ocurrió un error inesperado.';
                header('Location: index.php?opt=recuperar_cuenta');
                exit;
            }

            // Guardar email en sesión (UX)

            $_SESSION['reset_email'] = $email;

            // Enviar mail

            if (!enviarCodigoRecuperacion($email, $codigo)) {
                $_SESSION['flash_error'] = 'Ocurrió un error inesperado al enviar el email.';
                header('Location: index.php?opt=recuperar_cuenta');
                exit;
            }

            $_SESSION['ultimo_envio_codigo'] = time();

            // Redirigir a verificación

            $_SESSION['flash_success'] = 'Si el correo ingresado es válido, recibirás un código de verificación.';
            header('Location: index.php?opt=verificar_codigo');
            exit;
        }

    case 'verificar_codigo':

        if ($_SERVER['REQUEST_METHOD'] === 'GET') {

            if (empty($_SESSION['reset_email'])) {
                header('Location: index.php?opt=recuperar_cuenta');
                exit;
            }

            ob_start();
            require __DIR__ . '/../views/login/verificarCodigoView.php';
            return ob_get_clean();
        }

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

            if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
                $_SESSION['flash_error'] = 'Acción inválida.';
                header('Location: index.php?opt=login');
                exit;
            }

            // Inicializamos contador

            if (!isset($_SESSION['codigo_intentos'])) {
                $_SESSION['codigo_intentos'] = 0;
            }

            // VALIDAMOS BLOQUEO ACTIVO

            // SI EL BLOQUEO YA EXPIRÓ, RESETEAMOS

            if (isset($_SESSION['codigo_bloqueado_hasta']) && time() >= $_SESSION['codigo_bloqueado_hasta']) {

                unset($_SESSION['codigo_bloqueado_hasta']);
                $_SESSION['codigo_intentos'] = 0;
            }

            // SI SIGUE BLOQUEADO

            if (isset($_SESSION['codigo_bloqueado_hasta']) && time() < $_SESSION['codigo_bloqueado_hasta']) {

                $segundos = $_SESSION['codigo_bloqueado_hasta'] - time();

                $minutos = ceil($segundos / 60);

                $_SESSION['flash_error'] = "Demasiados intentos fallidos. Espere {$minutos} minuto(s).";

                header('Location: index.php?opt=verificar_codigo');
                exit;
            }

            require_once __DIR__ . '/../models/usuarioModel.php';
            $usuariomodel = new usuarioModel();

            require_once __DIR__ . '/../models/logInModel.php';
            $loginmodel = new logInModel();

            $codigo = trim($_POST['codigo'] ?? '');
            $email = $_SESSION['reset_email'] ?? null;

            if (empty($codigo) || empty($email)) {
                $_SESSION['flash_error'] = 'Debe ingresar el código.';
                header('Location: index.php?opt=verificar_codigo');
                exit;
            }

            $usuario = $usuariomodel->obtenerPorEmail($email);

            if (!$usuario) {
                $_SESSION['flash_error'] = 'Ocurrió un error.';
                header('Location: index.php?opt=login');
                exit;
            }

            $registro = $loginmodel->obtenerCodigoValido($usuario['id']);

            if (!$registro) {

                $_SESSION['codigo_intentos']++;

                // BLOQUEO AUTOMÁTICO

                if ($_SESSION['codigo_intentos'] >= 5) {

                    $_SESSION['codigo_bloqueado_hasta'] = time() + (15 * 60);

                    $_SESSION['flash_error'] = 'Demasiados intentos fallidos. Intente nuevamente en 15 minutos.';

                } else {
                    $_SESSION['flash_error'] = 'El código no es válido.';
                }

                header('Location: index.php?opt=verificar_codigo');
                exit;
            }

            // EXPIRACIÓN

            if (strtotime($registro['expira_a']) < time()) {

                $loginmodel->marcarComoUsado($registro['id']);

                $_SESSION['flash_error'] = 'El código ha expirado.';

                header('Location: index.php?opt=verificar_codigo');
                exit;
            }

            // VALIDACIÓN HASH

            if (!password_verify($codigo, $registro['codigo'])) {

                $_SESSION['codigo_intentos']++;

                // BLOQUEAR SI LLEGA AL LÍMITE

                if ($_SESSION['codigo_intentos'] >= 5) {

                    $_SESSION['codigo_bloqueado_hasta'] = time() + (15 * 60);

                    $_SESSION['flash_error'] = 'Demasiados intentos fallidos. Intente nuevamente en 15 minutos.';

                } else {
                    $_SESSION['flash_error'] = 'Código incorrecto.';
                }

                header('Location: index.php?opt=verificar_codigo');
                exit;
            }

            // ÉXITO

            $loginmodel->marcarComoUsado($registro['id']);

            $_SESSION['reset_autorizado'] = $usuario['id'];

            // Limpiar protección

            unset($_SESSION['codigo_intentos']);
            unset($_SESSION['codigo_bloqueado_hasta']);

            header('Location: index.php?opt=restablecer_contrasenia');
            exit;
        }

    // RESTABLECER CONTRASENIA

    case 'restablecer_contrasenia':

        if (!isset($_SESSION['reset_autorizado'])) {
            header('Location: index.php?opt=login');
            exit;
        }

        // MOSTRAR VISTA

        if ($_SERVER['REQUEST_METHOD'] === 'GET') {

            ob_start();
            require __DIR__ . '/../views/login/restablecerContraseniaView.php';
            return ob_get_clean();
        }

        // GUARDAR NUEVA CONTRASENIA

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

            if (!isset($_POST['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $_POST['csrf_token'])) {
                $_SESSION['flash_error'] = 'Acción inválida.';
                header('Location: index.php?opt=login');
                exit;
            }

            require_once __DIR__ . '/../models/usuarioModel.php';
            $usuariomodel = new usuarioModel();

            $password = trim($_POST['password'] ?? '');
            $confirmar = trim($_POST['confirmar_password'] ?? '');

            $errores = [];

            // VALIDACIONES

            if (empty($password) || empty($confirmar)) {
                $_SESSION['flash_error'] = 'Complete todos los campos.';
                header('Location: index.php?opt=restablecer_contrasenia');
                exit;
            }

            // VALIDACIONES DE CONTRASENIA

            if ($password === '') {
                $errores[] = "La contraseña no puede estar vacía.";
            } elseif (strpos($password, ' ') !== false) {
                $errores[] = "La contraseña no puede contener espacios.";
            } elseif (!preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{6,}$/', $password)) {
                $errores[] = "La contraseña debe tener al menos una mayúscula, una minúscula y un número, y mínimo 6 caracteres.";
            }

            if ($password !== $confirmar) {
                $_SESSION['flash_error'] = 'Las contraseñas no coinciden.';
                header('Location: index.php?opt=restablecer_contrasenia');
                exit;
            }

            if (!empty($errores)) {
                $_SESSION['flash_error'] = implode('<br>', $errores);
                header("Location: index.php?opt=restablecer_contrasenia");
                exit;
            }

            // HASH

            $passwordHash = password_hash($password, PASSWORD_DEFAULT);

            // ACTUALIZAR

            if (!$usuariomodel->actualizarContrasenia (
                $_SESSION['reset_autorizado'], $passwordHash
            )) {
                $_SESSION['flash_error'] = 'Ocurrió un error inesperado.';
                header('Location: index.php?opt=restablecer_contrasenia');
                exit;
            }

            // INVALIDAMOS TODOS LOS CODIGOS (PARA PREVENIR)

            $loginmodel->invalidarPorUsuario($_SESSION['reset_autorizado']);

            // Limpiar sesión temporal

            unset($_SESSION['reset_autorizado']);
            unset($_SESSION['reset_email']);

            // REGENERACION DE SESSION ID

            session_regenerate_id(true);

            $_SESSION['flash_success'] = 'Contraseña actualizada correctamente.';

            header('Location: index.php?opt=login');
            exit;
        }

    // DEFAULT (404)

    default:
        ob_start();
        require __DIR__ . '/../views/404View.php';
        return ob_get_clean();
}