<?php

require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/Response.php';

ini_set('log_errors', 1);
ini_set('error_log', 'C:/xampp/apache/logs/error.log');


class AuthController {
    private $db;

    public function __construct() {
        $database = new Database();
        $this->db = $database->getConnection();
    }

    function generateCsrfToken() {
        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }
        $token = bin2hex(random_bytes(32));
        $_SESSION['csrf_token'] = $token;
        return $token;
    }

    function validateCsrfToken($token) {
        if (session_status() == PHP_SESSION_NONE) {
            session_start();
        }
        return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
    }

    // public function login($data) {
    //     // Validar el token CSRF
    //     // if (!isset($data['csrf_token']) || !$this->validateCsrfToken($data['csrf_token'])) {
    //     //     return Response::json(['success' => false, 'message' => 'CSRF token inválido'], 403);
    //     // }

    //     // Validación de entrada
    //     if (!isset($data['usuario']) || !isset($data['password']) || !isset($data['token'])) {
    //         return Response::json(['success' => false, 'message' => 'Datos incompletos'], 400);
    //     }

    //     if (!is_string($data['usuario']) || !is_string($data['password']) || !is_string($data['token'])) {
    //         return Response::json(['success' => false, 'message' => 'Formato de datos incorrecto'], 400);
    //     }

    //     if (empty($data['usuario']) || empty($data['password']) || empty($data['token'])) {
    //         return Response::json(['success' => false, 'message' => 'Usuario, contraseña o token vacío'], 400);
    //     }

    //     // Validación del token de autenticación
    //     $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    //     if ($data['token'] !== $token) {
    //         return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    //     }

    //     // Declaración preparada para evitar inyecciones SQL
       

    //     $query = "SELECT * FROM PER WHERE PER_ONLINE_LOG = :usuario AND PER_ONLINE_PWD = :password AND PER_EST = 1";
    //     $stmt = $this->db->prepare($query);
    //     $stmt->bindParam(':usuario', $data['usuario']);
    //     $stmt->bindParam(':password', $data['password']);
    //     $stmt->execute();

    //     $user = $stmt->fetch(PDO::FETCH_ASSOC);

    //     if ($user) {
    //         // Si la autenticación es exitosa
    //         return Response::json(['success' => true, 'message' => 'Autenticación exitosa', 'data' => $user], 200);
    //     } else {
    //         // Si la autenticación falla
    //         return Response::json(['success' => false, 'message' => 'Usuario o contraseña incorrectos'], 401);
    //     }
    // }

 
public function login($data) {
    if (!isset($data['usuario']) || !isset($data['password']) || !isset($data['iv']) || !isset($data['token'])) {
        return Response::json(['success' => false, 'message' => 'Datos incompletos'], 400);
    }

    if ($data['token'] !== 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313') {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    try {
        $key = base64_decode('ZH0xT4YqD/qD4P5ANHZnJQn5x96fOkMGzrWXu14hki4=');
        $iv = base64_decode($data['iv']);
        $passwordEncriptada = base64_decode($data['password']);

        if (strlen($iv) !== 16) {
            return Response::json(['success' => false, 'message' => 'Error: IV incorrecto, tiene ' . strlen($iv) . ' bytes en lugar de 16.'], 500);
        }

        // 🔐 Descifrar la contraseña
        $passwordDescifrada = openssl_decrypt(
            $passwordEncriptada,
            'AES-256-CBC',
            $key,
            0,
            $iv
        );

        if (!$passwordDescifrada) {
            return Response::json(['success' => false, 'message' => 'Error al descifrar la contraseña'], 500);
        }

        // Normalizar y quitar espacios en blanco al usuario
        $usuarioInput = trim($data['usuario']);
        $usuarioNormalized = strtoupper($usuarioInput);
		
		$passwordNormalized = trim($passwordDescifrada);

        // 📌 Buscar usuario en la BD (compara en mayúsculas)
		$query = "SELECT TOP 1 * FROM PER 
          WHERE UPPER(LTRIM(RTRIM(PER_ONLINE_LOG))) = :usuario 
          AND LTRIM(RTRIM(PER_ONLINE_PWD2)) = :password
          AND PER_EST = 1 
          AND PER_ACT_WEB = 1
          ORDER BY PER_NUM DESC";

$stmt = $this->db->prepare($query);
$stmt->bindParam(':usuario', $usuarioNormalized);
$stmt->bindParam(':password', $passwordNormalized);
$stmt->execute();

        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        // Comparar contraseñas quitando espacios en ambos lados
        if ($user && trim($passwordDescifrada) === trim($user['PER_ONLINE_PWD2'])) {
            
            if (!empty($user['PER_NUM'])) {
                $fechaActual = date('Y-m-d H:i:s');
                $updateQuery = "UPDATE PER SET PER_ULTIMA_FEC = CONVERT(DATETIME, :fechaActual, 120) WHERE PER_NUM = :perNum";
                $updateStmt = $this->db->prepare($updateQuery);
                $updateStmt->bindValue(':fechaActual', $fechaActual, PDO::PARAM_STR);
                $updateStmt->bindValue(':perNum', (int)$user['PER_NUM'], PDO::PARAM_INT);

                if ($updateStmt->execute()) {
                    error_log("✅ Última conexión actualizada para PER_NUM: " . $user['PER_NUM']);
                } else {
                    $errorInfo = $updateStmt->errorInfo();
                    error_log("❌ Error al actualizar PER_ULTIMA_FEC: " . implode(" | ", $errorInfo));
                    return Response::json(['success' => false, 'message' => 'Error al actualizar PER_ULTIMA_FEC: ' . implode(" | ", $errorInfo)], 500);
                }
            } else {
                error_log("⚠ PER_NUM no válido para actualizar PER_ULTIMA_FEC");
            }

          unset($user['PER_ONLINE_PWD2']);
return Response::json([
    'success' => true,
    'message' => 'Autenticación exitosa',
    'data' => $user,
], 200);

        }

        return Response::json(['success' => false, 'message' => 'Usuario o contraseña incorrectos'], 401);
    } catch (\Exception $e) {
        return Response::json(['success' => false, 'message' => 'Error en el servidor: ' . $e->getMessage()], 500);
    }
}






public function updateUser($data) {
    if (!isset($data['per_num']) || !isset($data['password']) || !isset($data['iv']) || !isset($data['email']) || !isset($data['token'])) {
        return Response::json(['success' => false, 'message' => 'Datos incompletos'], 400);
    }

    if ($data['token'] !== 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313') {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    try {
    // 🔑 Clave secreta para descifrado (debe ser la misma en Laravel)
    $key = base64_decode('ZH0xT4YqD/qD4P5ANHZnJQn5x96fOkMGzrWXu14hki4=');
    $iv = base64_decode($data['iv']); // ✅ Obtener IV
    $passwordEncriptada = base64_decode($data['password']); // ✅ Obtener contraseña cifrada

    // 📌 Log para verificar datos de entrada
    error_log('🔑 Clave secreta decodificada (base64): ' . base64_encode($key));
    error_log('🔓 IV recibido (hex): ' . bin2hex($iv));
    error_log('🔒 Contraseña cifrada recibida (base64): ' . $data['password']);
    error_log('🔒 Contraseña cifrada recibida (hex): ' . bin2hex($passwordEncriptada));

    // 🚨 Validar IV
    if (strlen($iv) !== 16) {
        error_log('❌ Error: IV incorrecto, tiene ' . strlen($iv) . ' bytes en lugar de 16.');
        return Response::json(['success' => false, 'message' => 'Error: IV incorrecto'], 500);
    }

    // 🔐 Intentar descifrar la contraseña
    $passwordDescifrada = openssl_decrypt($passwordEncriptada, 'AES-256-CBC', $key, 0, $iv);

    if (!$passwordDescifrada) {
        error_log('❌ Error al descifrar la contraseña');
        return Response::json(['success' => false, 'message' => 'Error al descifrar la contraseña'], 500);
    }

    error_log('🔓 Contraseña descifrada correctamente: ' . $passwordDescifrada);

    // 🚨 Verificar si el correo ya está en uso por otro usuario
    $queryCheckEmail = "SELECT PER_NUM FROM PER WHERE PER_MAI = :email AND PER_NUM != :per_num";
    $stmtCheckEmail = $this->db->prepare($queryCheckEmail);
    $stmtCheckEmail->bindParam(':email', $data['email']);
    $stmtCheckEmail->bindParam(':per_num', $data['per_num']);
    $stmtCheckEmail->execute();

    if ($stmtCheckEmail->fetch()) {
        return Response::json(['success' => false, 'message' => 'El correo ya está en uso por otro usuario'], 409);
    }

    // 📌 Guardar la contraseña en texto plano en PER_ONLINE_PWD2
    $query = "UPDATE PER SET PER_ONLINE_PWD2 = :password, PER_MAI = :email, PER_PRIMER_ACCESO = 0 WHERE PER_NUM = :per_num";
    $stmt = $this->db->prepare($query);
    $stmt->bindParam(':password', $passwordDescifrada);
    $stmt->bindParam(':email', $data['email']);
    $stmt->bindParam(':per_num', $data['per_num']);
    $stmt->execute();

    error_log('✅ Usuario actualizado correctamente');

    return Response::json(['success' => true, 'message' => 'Usuario actualizado correctamente'], 200);
} catch (\Exception $e) {
    error_log('❌ Error al actualizar el usuario: ' . $e->getMessage());
    return Response::json(['success' => false, 'message' => 'Error al actualizar el usuario: ' . $e->getMessage()], 500);
}

}


public function updateUserA($data) {
    if (!isset($data['per_num']) || !isset($data['token'])) {
        return Response::json(['success' => false, 'message' => 'Datos incompletos'], 400);
    }

    if ($data['token'] !== 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313') {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    try {
        $updatePassword = false;
        $updateEmail = false;

        // ✅ Si se proporciona la contraseña y el IV, intentar actualizar
        if (isset($data['password']) && isset($data['iv'])) {
            $key = base64_decode('ZH0xT4YqD/qD4P5ANHZnJQn5x96fOkMGzrWXu14hki4=');
            $iv = base64_decode($data['iv']);
            $passwordEncriptada = base64_decode($data['password']);

            // ✅ Asegurar que el IV tenga exactamente 16 bytes
            if (strlen($iv) !== 16) {
                $iv = substr($iv . str_repeat("\0", 16), 0, 16);
            }

            // ✅ Intentar descifrar con padding automático
            $passwordDescifrada = openssl_decrypt($passwordEncriptada, 'AES-256-CBC', $key, 0, $iv);

            if (!$passwordDescifrada) {
                error_log('❌ openssl_error_string(): ' . openssl_error_string());
                return Response::json(['success' => false, 'message' => 'Error al descifrar la contraseña'], 500);
            }

            $updatePassword = true;
        }

        // ✅ Si se proporciona un correo, intentar actualizar
        if (isset($data['email'])) {
            $queryCheckEmail = "SELECT PER_NUM FROM PER WHERE PER_MAI = :email AND PER_NUM != :per_num";
            $stmtCheckEmail = $this->db->prepare($queryCheckEmail);
            $stmtCheckEmail->bindParam(':email', $data['email']);
            $stmtCheckEmail->bindParam(':per_num', $data['per_num']);
            $stmtCheckEmail->execute();

            if ($stmtCheckEmail->fetch()) {
                return Response::json(['success' => false, 'message' => 'El correo ya está en uso por otro usuario'], 409);
            }

            $updateEmail = true;
        }

        // ✅ Actualizar la base de datos solo si hay cambios
        if ($updatePassword || $updateEmail) {
            $query = "UPDATE PER SET ";

            if ($updatePassword) {
                $query .= "PER_ONLINE_PWD2 = :password";
            }

            if ($updateEmail) {
                $query .= $updatePassword ? ", " : ""; // Si hay contraseña y email, añade coma
                $query .= "PER_MAI = :email";
            }

            $query .= " WHERE PER_NUM = :per_num";

            $stmt = $this->db->prepare($query);

            if ($updatePassword) {
                $stmt->bindParam(':password', $passwordDescifrada);
            }
            if ($updateEmail) {
                $stmt->bindParam(':email', $data['email']);
            }

            $stmt->bindParam(':per_num', $data['per_num']);
            $stmt->execute();
        }

        return Response::json([
            'success' => true,
            'message' => 'Usuario actualizado correctamente'
        ], 200);
    } catch (\Exception $e) {
        error_log('❌ Error interno del servidor: ' . $e->getMessage());
        return Response::json([
            'success' => false,
            'message' => 'Error interno del servidor: ' . $e->getMessage()
        ], 500);
    }
}






public function requestPasswordReset($data)
{
    // 📌 Asegurar que los datos llegan correctamente
    if (!isset($data['email']) || !isset($data['token'])) {
        return Response::json(['success' => false, 'message' => 'Email y token API requeridos'], 400);
    }

    if ($data['token'] !== 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313') {
        return Response::json(['success' => false, 'message' => 'Token API inválido'], 403);
    }

    try {
        // 📌 Buscar usuario en la BD
        $query = "SELECT * FROM PER WHERE PER_MAI = :email";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':email', $data['email']);
        $stmt->execute();
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$user) {
            return Response::json(['success' => false, 'message' => 'Correo no encontrado'], 404);
        }

        // 🛠 Generar token de recuperación
        $resetToken = bin2hex(random_bytes(16));

        // 💾 Guardar el token en la BD
        $query = "UPDATE PER SET PER_RESET_TOKEN = :token WHERE PER_MAI = :email";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':token', $resetToken);
        $stmt->bindParam(':email', $data['email']);
        $stmt->execute();

        // ✅ Enviar el token de recuperación a Laravel para que este envíe el email
        return Response::json([
            'success' => true,
            'message' => 'Token generado correctamente.',
            'token' => $resetToken
        ], 200);

    } catch (\Exception $e) {
        return Response::json(['success' => false, 'message' => 'Error en el servidor: ' . $e->getMessage()], 500);
    }
}






public function resetPassword($data)
{
    error_log('🔍 Recibiendo solicitud en la API: ' . json_encode($data));

    if (!isset($data['email']) || !isset($data['token']) || !isset($data['new_password']) || !isset($data['iv']) || !isset($data['token_api'])) {
        error_log('❌ Error: Datos incompletos en la API');
        return json_encode(['success' => false, 'message' => 'Datos incompletos'], JSON_UNESCAPED_UNICODE);
    }

    if ($data['token_api'] !== 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313') {
        error_log('❌ Error: Token API inválido');
        return json_encode(['success' => false, 'message' => 'Token API inválido'], JSON_UNESCAPED_UNICODE);
    }

    try {
        // 📌 Verificar si el email y el token existen en la BD
        $query = "SELECT * FROM PER WHERE PER_MAI = :email AND PER_RESET_TOKEN = :token";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':email', $data['email']);
        $stmt->bindParam(':token', $data['token']);
        $stmt->execute();
        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if (!$user) {
            error_log('❌ Error: Token inválido o usuario no encontrado');
            return json_encode(['success' => false, 'message' => 'Token inválido o usuario no encontrado'], JSON_UNESCAPED_UNICODE);
        }

        // 🔑 Clave secreta compartida con Laravel
        $key = base64_decode('ZH0xT4YqD/qD4P5ANHZnJQn5x96fOkMGzrWXu14hki4='); // 🔑 Misma clave en Laravel y la API
        $iv = base64_decode($data['iv']); // 🔓 Desciframos IV
        $encryptedPassword = base64_decode($data['new_password']); // 🔓 Desciframos la contraseña

        // 🚨 Validar IV
        if (strlen($iv) !== 16) {
            error_log('❌ Error: IV incorrecto');
            return json_encode(['success' => false, 'message' => 'Error: IV incorrecto'], JSON_UNESCAPED_UNICODE);
        }

        // 🔓 Intentar descifrar la contraseña
        $passwordPlain = openssl_decrypt(
            $encryptedPassword,
            'AES-256-CBC',
            $key,
            0,
            $iv
        );

        if (!$passwordPlain) {
            error_log('❌ Error al descifrar la contraseña');
            return json_encode(['success' => false, 'message' => 'Error al descifrar la contraseña'], JSON_UNESCAPED_UNICODE);
        }

        // 📌 Log para verificar descifrado
        error_log('🔓 Contraseña descifrada correctamente: ' . $passwordPlain);

        // ✅ Guardar la contraseña en texto plano y eliminar el token de recuperación
        $queryUpdate = "UPDATE PER SET PER_ONLINE_PWD2 = :new_password, PER_RESET_TOKEN = NULL WHERE PER_MAI = :email";
        $stmtUpdate = $this->db->prepare($queryUpdate);
        $stmtUpdate->bindParam(':new_password', $passwordPlain);
        $stmtUpdate->bindParam(':email', $data['email']);
        $stmtUpdate->execute();

        error_log('✅ Contraseña actualizada correctamente');
        return json_encode([
            'success' => true,
            'message' => 'Contraseña actualizada correctamente'
        ], JSON_UNESCAPED_UNICODE);

    } catch (\Exception $e) {
        error_log('❌ Error al actualizar la contraseña: ' . $e->getMessage());
        return json_encode(['success' => false, 'message' => 'Error al actualizar la contraseña: ' . $e->getMessage()], JSON_UNESCAPED_UNICODE);
    }
}



public function updateUserStatus($data) {
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';

    // Validación del token de autenticación
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validación de parámetros
    if (!isset($data['per_num']) || !isset($data['status'])) {
        return Response::json(['success' => false, 'message' => 'Datos incompletos'], 400);
    }

    $per_num = $data['per_num'];
    $status = (int) $data['status']; // 0 o 1

    try {
        $query = "UPDATE PER SET PER_ACT_WEB = :status WHERE PER_NUM = :per_num";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':status', $status, PDO::PARAM_INT);
        $stmt->bindParam(':per_num', $per_num, PDO::PARAM_INT);
        $stmt->execute();

        if ($stmt->rowCount()) {
            return Response::json([
                'success' => true,
                'message' => 'Estado actualizado correctamente',
                'new_status' => $status
            ], 200);
        } else {
            return Response::json([
                'success' => false,
                'message' => 'No se pudo actualizar el estado o ya está actualizado'
            ], 400);
        }
    } catch (PDOException $e) {
        return Response::json([
            'success' => false,
            'message' => 'Error en la base de datos: ' . $e->getMessage()
        ], 500);
    }
}



public function actualizarNumeroNotificaciones($data)
{
    if (!isset($data['per_num']) || !isset($data['numero_notificaciones']) || !isset($data['token_api'])) {
        return response()->json(['success' => false, 'message' => 'Datos incompletos'], 400);
    }

    if ($data['token_api'] !== 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313') {
        return response()->json(['success' => false, 'message' => 'Token API inválido'], 403);
    }

    try {
        // Actualizar PER_CTD_NOT con el número de notificaciones pendientes
        $query = "UPDATE PER SET PER_CTD_NOT = :numero_notificaciones WHERE PER_NUM = :per_num";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':numero_notificaciones', $data['numero_notificaciones']);
        $stmt->bindParam(':per_num', $data['per_num']);
        $stmt->execute();

        return response()->json(['success' => true, 'message' => 'Número de notificaciones actualizado correctamente.']);
    } catch (\Exception $e) {
        return response()->json(['success' => false, 'message' => 'Error al actualizar el número de notificaciones: ' . $e->getMessage()], 500);
    }
}



public function getVacationTypes($data)
{
    $tokenEsperado = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    
    if (!isset($data['token']) || $data['token'] !== $tokenEsperado) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }
    
    try {
        $query = "SELECT * FROM VAC_TIP WHERE VT_PORTALVIR = 1";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        $vacationTypes = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        return Response::json(['success' => true, 'data' => $vacationTypes], 200);
    } catch (\Exception $e) {
        return Response::json(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()], 500);
    }
}







    public function getOperarioNumber($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validación de entrada
    if (!isset($data['usuario'])) {
        return Response::json(['success' => false, 'message' => 'Usuario no especificado'], 400);
    }

    if (!is_string($data['usuario'])) {
        return Response::json(['success' => false, 'message' => 'Formato de usuario incorrecto'], 400);
    }

    // Declaración preparada para evitar inyecciones SQL
    $query = "SELECT PER_NUM, PER_CTR, PER_NOM, PER_DNI, PER_APE FROM PER WHERE PER_ONLINE_LOG = :usuario";
    
    try {
        // Ejecutar la consulta
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario'], PDO::PARAM_STR);
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        // Verificar si se encuentra el usuario
        if ($result) {
            return Response::json(['success' => true, 'data' => $result], 200);
        } else {
            return Response::json(['success' => false, 'message' => 'Usuario no encontrado'], 404);
        }
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()], 500);
    }
}


    // Nuevo método para obtener los detalles completos de un usuario basado en el PER_ONLINE_LOG
    public function getUserDetails($data) {
        // Validación del token de autenticación
        $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
        if ($data['token'] !== $token) {
            return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
        }

        // Validación de entrada
        if (!isset($data['usuario'])) {
            return Response::json(['success' => false, 'message' => 'Usuario no especificado'], 400);
        }

        if (!is_string($data['usuario'])) {
            return Response::json(['success' => false, 'message' => 'Formato de usuario incorrecto'], 400);
        }

        // Declaración preparada para evitar inyecciones SQL
        $query = "SELECT * FROM PER WHERE PER_ONLINE_LOG = :usuario";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();

        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            // Si se encuentra el usuario, devolver los datos
            return Response::json(['success' => true, 'data' => $user], 200);
        } else {
            // Si el usuario no se encuentra
            return Response::json(['success' => false, 'message' => 'Usuario no encontrado'], 404);
        }
    }

    
public function getConfirmedVacations($data) {
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    header('Content-Type: application/json');

    if (!isset($data['token']) || $data['token'] !== $token) {
        echo json_encode(['success' => false, 'message' => 'Token inválido']); return;
    }
    if (empty($data['usuario']) || !is_string($data['usuario'])) {
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']); return;
    }

    $usuario = $data['usuario'];

    $queryVacations = "
;WITH Q AS (
    SELECT
        p.PER_CTR,
        v.VAC_ID,
        v.VAC_OPE,
        v.VAC_FSOL,
        v.VAC_FINI,
        v.VAC_FFIN,
        v.VAC_HFEC,
        COALESCE(v.VAC_LAB,0.0) AS VAC_LAB,
        COALESCE(v.VAC_HOR,0.0) AS VAC_HOR,
        CASE
            WHEN COALESCE(v.VAC_HOR,0) > 0 AND v.VAC_HFEC IS NOT NULL
                THEN CAST(v.VAC_HFEC AS date)
            ELSE CAST(v.VAC_FINI AS date)
        END AS FechaReal
    FROM VAC v
    LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
    WHERE p.PER_NUM = :usuario
      AND v.VAC_TIP IN (1,3)
      AND (COALESCE(v.VAC_LAB,0) > 0 OR COALESCE(v.VAC_HOR,0) > 0)
),
QH AS (
    SELECT
        Q.*,
        COALESCE(NULLIF(ch.HorasDia, 0), 8.0) AS HorasDiaBase
    FROM Q
    OUTER APPLY (
        SELECT TOP (1)
            CAST(NULLIF(c.[Nº Horas],0)/5.0 AS DECIMAL(18,6)) AS HorasDia
        FROM LIST_PERSONAL_CONTRATOS c
        WHERE c.Operario = Q.VAC_OPE
          AND Q.FechaReal >= CAST(c.[Fecha Ini] AS date)
          AND (c.[Fecha Fin] IS NULL OR Q.FechaReal < DATEADD(day,1, CAST(c.[Fecha Fin] AS date)))
        ORDER BY c.[Fecha Ini] DESC
    ) ch
),
Conv AS (
    SELECT
        QH.*,
        CAST(QH.VAC_LAB AS DECIMAL(18,6)) AS DiasEnteros,
        CAST(
            CASE WHEN QH.VAC_HOR > 0
                 THEN QH.VAC_HOR / (CASE WHEN MONTH(QH.FechaReal) IN (7,8) THEN 7.0 ELSE QH.HorasDiaBase END)
                 ELSE 0.0
            END AS DECIMAL(18,6)
        ) AS DiasEqHoras
    FROM QH
),
G AS (
    SELECT
        PER_CTR,
        VAC_ID,
        VAC_OPE,
        MIN(VAC_FSOL) AS Fecha_Sol,
        MIN(FechaReal) AS Fecha_Inicio,
        MAX(COALESCE(VAC_FFIN, FechaReal)) AS Fecha_Fin,
        CAST(SUM(DiasEnteros) AS DECIMAL(18,6))     AS Dias_Laborables,
        CAST(SUM(VAC_HOR)     AS DECIMAL(18,6))     AS Horas,
        CAST(SUM(DiasEqHoras) AS DECIMAL(18,6))     AS Horas_Convertidas,
        CAST(SUM(DiasEnteros + DiasEqHoras) AS DECIMAL(18,6)) AS Total_Dias_Disfrutados,
        CASE WHEN MAX(COALESCE(VAC_HFEC, VAC_FFIN)) < GETDATE()
             THEN 'Disfrutadas' ELSE 'Confirmadas (Pendientes)' END AS Estado
    FROM Conv
    GROUP BY PER_CTR, VAC_ID, VAC_OPE
)
SELECT
    G.*,
    YEAR(COALESCE(G.Fecha_Sol, G.Fecha_Inicio)) AS Anio,
    CAST(SUM(G.Total_Dias_Disfrutados) OVER () AS DECIMAL(18,6)) AS Total_Dias_Disfrutados_Anio
FROM G
ORDER BY G.Fecha_Inicio DESC;
";

    // Años disponibles para el selector
    $queryYears = "
        SELECT DISTINCT YEAR(COALESCE(v.VAC_FSOL, CASE WHEN v.VAC_HFEC IS NOT NULL THEN v.VAC_HFEC ELSE v.VAC_FINI END)) AS Year
        FROM VAC v
        LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
        WHERE p.PER_NUM = :usuario
          AND v.VAC_TIP IN (1,3)
          AND (COALESCE(v.VAC_LAB,0) > 0 OR COALESCE(v.VAC_HOR,0) > 0)
        ORDER BY Year DESC
    ";

    try {
        $stmtVacations = $this->db->prepare($queryVacations);
        $stmtVacations->bindParam(':usuario', $usuario);
        // ❌ No bindees :anio porque ya no existe en el SQL
        $stmtVacations->execute();
        $vacations = $stmtVacations->fetchAll(PDO::FETCH_ASSOC);

        foreach ($vacations as &$r) {
            foreach (['Dias_Laborables','Horas','Horas_Convertidas','Total_Dias_Disfrutados','Total_Dias_Disfrutados_Anio'] as $k) {
                if (isset($r[$k])) $r[$k] = (float)round($r[$k], 6);
            }
        }

        $stmtYears = $this->db->prepare($queryYears);
        $stmtYears->bindParam(':usuario', $usuario);
        $stmtYears->execute();
        $years = $stmtYears->fetchAll(PDO::FETCH_COLUMN);

        echo json_encode([
            'success' => true,
            'data' => [
                'vacations' => $vacations,
                'years'     => $years
            ]
        ]);
    } catch (PDOException $e) {
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}










public function getConfirmedButNotTakenVacations($data) {

    // // Validación del token de autenticación
    // $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    // if ($data['token'] !== $token) {
    //     header('Content-Type: application/json');
    //     echo json_encode(['success' => false, 'message' => 'Token inválido']);
    //     exit;
    // }

    // // Validación de entrada
    // if (!isset($data['per_num'])) {
    //     header('Content-Type: application/json');
    //     echo json_encode(['success' => false, 'message' => 'Usuario no especificado']);
    //     exit;
    // }

    // if (!is_string($data['per_num'])) {
    //     header('Content-Type: application/json');
    //     echo json_encode(['success' => false, 'message' => 'Formato de usuario incorrecto']);
    //     exit;
    // }



    // $query = "
    //     SELECT
    //         sv.SV_ID,
    //         sv.SV_OPE,
    //         sv.SV_FINI AS Fecha_Inicio,
    //         sv.SV_FFIN AS Fecha_Fin,
    //         sv.SV_LAB AS Días_Laborables,
    //         'No-Confirmada/No-Disfrutadas' AS Estado
    //     FROM
    //         SOL_VAC sv
    //     JOIN
    //         PER p ON sv.SV_OPE = p.PER_NUM
    //     WHERE
    //         p.PER_NUM = :per_num
    //         AND sv.SV_EST = 1
    //         AND sv.SV_VAC IS NULL -- No disfrutadas (sin referencia en VAC)
    //         AND sv.SV_FINI > GETDATE() -- La fecha de inicio es en el futuro
    //     ORDER BY Fecha_Inicio ASC
    // ";

    // try {
    //     // Ejecutar la consulta
    //     $stmt = $this->db->prepare($query);
    //     $stmt->bindParam(':per_num', $data['per_num']);
    //     $stmt->execute();
    //     $vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);

    //     // Formatear fechas para mejor legibilidad
    //     foreach ($vacations as &$vacation) {
    //         $vacation['Fecha_Inicio'] = date('d/m/Y', strtotime($vacation['Fecha_Inicio']));
    //         $vacation['Fecha_Fin'] = date('d/m/Y', strtotime($vacation['Fecha_Fin']));
    //     }

    //     // Devolver los resultados como JSON
    //     header('Content-Type: application/json');
    //     echo json_encode(['success' => true, 'data' => $vacations]);
    // } catch (PDOException $e) {
    //     // Devolver un mensaje de error si ocurre una excepción
        //header('Content-Type: application/json');
        //echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);



    //}

     // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Validación de entrada
    if (!isset($data['per_num'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado']);
        exit;
    }

    if (!is_string($data['per_num'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Formato de usuario incorrecto']);
        exit;
    }

    // Declaración preparada para evitar inyecciones SQL
    $queryVacations = "
    SELECT
        p.PER_CTR,
        v.VAC_ID,
        v.VAC_OPE,
        v.VAC_FSOL as Fecha_Sol,
        CASE
            WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC
            ELSE v.VAC_FINI
        END AS Fecha_Inicio,
        CASE
            WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC
            ELSE v.VAC_FFIN
        END AS Fecha_Fin,
        (COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS Días_Laborables,
        'Confirmadas - No Disfrutadas' AS Estado,
        CASE
            WHEN v.VAC_FINI > GETDATE() THEN 1 -- Puede borrar si la fecha de inicio es en el futuro
            ELSE 0 -- No puede borrar si la fecha ya pasó
        END AS can_delete
    FROM
        VAC v
    LEFT JOIN
        PER p ON v.VAC_OPE = p.PER_NUM
    WHERE
        p.PER_NUM = :per_num
        AND v.VAC_TIP = 1
        AND YEAR(CASE
            WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC
            ELSE v.VAC_FINI
        END) = YEAR(GETDATE()) -- Solo para el año actual
        AND (v.VAC_FINI > GETDATE()) -- Solo mostrar registros donde can_delete = 1
    ORDER BY Fecha_Inicio DESC
";

try {
    // Ejecutar la consulta
    $stmtVacations = $this->db->prepare($queryVacations);
    $stmtVacations->bindParam(':per_num', $data['per_num']);
    $stmtVacations->execute();
    $vacations = $stmtVacations->fetchAll(PDO::FETCH_ASSOC);

    // Devolver los resultados como JSON
    header('Content-Type: application/json');
    echo json_encode([
        'success' => true,
        'data' => [
            'vacations' => $vacations,
        ]
    ]);
} catch (PDOException $e) {
    // Manejar errores
    header('Content-Type: application/json');
    echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
}
}


   // Método para eliminar vacaciones confirmadas no disfrutadas
public function deleteConfirmedVacation($data) {

    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if (!isset($data['token']) || $data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Obtener la fecha de inicio de la solicitud de vacaciones en la tabla VAC
    $query = "SELECT VAC_ID, VAC_FINI FROM VAC WHERE VAC_ID = :id";
    
    try {
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':id', $data['id']);
        $stmt->execute();
        $vacation = $stmt->fetch(PDO::FETCH_ASSOC);

        // Si la solicitud existe, proceder con el borrado
        if ($vacation) {
            // Eliminar la solicitud de vacaciones de la tabla VAC
            $deleteQuery = "DELETE FROM VAC WHERE VAC_ID = :id";
            $stmtDelete = $this->db->prepare($deleteQuery);
            $stmtDelete->bindParam(':id', $data['id']);
            $stmtDelete->execute();

            header('Content-Type: application/json');
            echo json_encode(['success' => true, 'message' => 'Vacación eliminada con éxito.']);
        } else {
            header('Content-Type: application/json');
            echo json_encode(['success' => false, 'message' => 'No se puede eliminar una vacación inexistente.']);
        }
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error al eliminar la vacación: ' . $e->getMessage()]);
    }
}

// Método para eliminar vacaciones solicitadas cuyo estado es 4
public function deleteSolicitadasVacation($data) {

    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if (!isset($data['token']) || $data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Obtener la solicitud de vacaciones cuyo estado es 4 (pendiente) y SV_VAC es NULL
    $query = "SELECT SV_ID FROM SOL_VAC WHERE SV_ID = :id AND SV_EST = 4 AND SV_VAC IS NULL";
    
    try {
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':id', $data['id']);
        $stmt->execute();
        $vacation = $stmt->fetch(PDO::FETCH_ASSOC);

        // Si se encontró la vacación
        if ($vacation) {
            // Eliminar la solicitud de vacaciones
            $deleteQuery = "DELETE FROM SOL_VAC WHERE SV_ID = :id";
            $stmtDelete = $this->db->prepare($deleteQuery);
            $stmtDelete->bindParam(':id', $data['id']);
            
            if ($stmtDelete->execute()) {
                header('Content-Type: application/json');
                echo json_encode(['success' => true, 'message' => 'Vacación eliminada con éxito.']);
            } else {
                header('Content-Type: application/json');
                echo json_encode(['success' => false, 'message' => 'Error al eliminar la vacación.']);
            }
        } else {
            header('Content-Type: application/json');
            echo json_encode(['success' => false, 'message' => 'No se encontró ninguna vacación con estado pendiente o ya ha sido confirmada.']);
        }
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error al eliminar la vacación: ' . $e->getMessage()]);
    }
}


public function getRequestedVacations($data) {
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if (($data['token'] ?? '') !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']); exit;
    }
    if (!isset($data['usuario']) || !is_string($data['usuario'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']); exit;
    }

    // Normalizamos:
    // - FechaInicio/Fin: si es parcial (SV_FINI=1900-01-01) usamos SV_HFEC
    // - Laborales: si es parcial -> SV_HOR/8 (o /7 en jul/ago)
    // - Filtro por año: sobre la fecha normalizada (Inicio)
    $query = "
    WITH Base AS (
        SELECT
            sv.SV_ID,
            sv.SV_OPE,
            sv.SV_EST,
            sv.SV_FINI,
            sv.SV_FFIN,
            sv.SV_HFEC,
            sv.SV_LAB,
            sv.SV_HOR,
            CASE WHEN CONVERT(date, sv.SV_FINI) = '1900-01-01'
                 THEN CONVERT(date, sv.SV_HFEC)
                 ELSE CONVERT(date, sv.SV_FINI)
            END AS FechaInicioNorm,
            CASE WHEN CONVERT(date, sv.SV_FFIN) = '1900-01-01'
                 THEN CONVERT(date, sv.SV_HFEC)
                 ELSE CONVERT(date, sv.SV_FFIN)
            END AS FechaFinNorm
        FROM SOL_VAC sv
        JOIN PER p ON sv.SV_OPE = p.PER_NUM
        WHERE p.PER_NUM = :usuario
          AND sv.SV_EST IN (1,4)
    )
    SELECT
        b.SV_ID          AS VAC_ID,
        b.SV_OPE         AS VAC_OPE,
        b.FechaInicioNorm AS VAC_FINI,
        b.FechaFinNorm    AS VAC_FFIN,
        CAST(
            CASE 
              WHEN CONVERT(date, b.SV_FINI) = '1900-01-01' 
                   THEN b.SV_HOR / CASE WHEN MONTH(b.FechaInicioNorm) IN (7,8) THEN 7.0 ELSE 8.0 END
              ELSE b.SV_LAB
            END
        AS DECIMAL(10,2)) AS Días_Solicitados,
        b.SV_HOR         AS Horas_Solicitadas,
        est.SVE_DES      AS Estado
    FROM Base b
    JOIN SOL_VAC_EST est ON b.SV_EST = est.SVE_ID
    WHERE YEAR(b.FechaInicioNorm) IN (YEAR(GETDATE()), YEAR(GETDATE())+1)
    ORDER BY b.FechaInicioNorm DESC;
    ";

    try {
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);
        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'data' => $vacations]);
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}


public function getRequestedVacationsPerNumTipo5($data)
{
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    header('Content-Type: application/json');

    if (($data['token'] ?? '') !== $token) {
        echo json_encode(['success' => false, 'message' => 'Token inválido']); exit;
    }
    if (!isset($data['usuario']) || !is_string($data['usuario'])) {
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']); exit;
    }

    // 📌 Filtramos por ESTADO 5 (ausencia injustificada)
    // 📌 Si FINI/FFIN = 1900-01-01, tomamos SV_HFEC como fecha (inicio/fin el mismo día)
    // 📌 Días = SV_HOR / (7 si mes de SV_HFEC es 7 u 8; si no, 8)
    $queryVac = "
    WITH Base AS (
        SELECT
            sv.SV_ID,
            sv.SV_OPE,
            sv.SV_EST,
            CAST(sv.SV_FINI AS date) AS SV_FINI,
            CAST(sv.SV_FFIN AS date) AS SV_FFIN,
            CAST(sv.SV_HFEC AS date) AS SV_HFEC,
            COALESCE(sv.SV_LAB, 0.0) AS SV_LAB,
            COALESCE(sv.SV_HOR, 0.0) AS SV_HOR,

            -- Normalización de fechas visible en UI
            CASE 
                WHEN CAST(sv.SV_FINI AS date) = DATEFROMPARTS(1900,1,1) THEN CAST(sv.SV_HFEC AS date)
                ELSE CAST(sv.SV_FINI AS date)
            END AS FechaInicioNorm,
            CASE 
                WHEN CAST(sv.SV_FFIN AS date) = DATEFROMPARTS(1900,1,1) THEN CAST(sv.SV_HFEC AS date)
                ELSE CAST(sv.SV_FFIN AS date)
            END AS FechaFinNorm
        FROM SOL_VAC sv
        JOIN PER p ON sv.SV_OPE = p.PER_NUM
        WHERE p.PER_NUM = :usuario
          AND sv.SV_EST = 5
    )
    SELECT
        b.SV_ID            AS VAC_ID,
        b.SV_OPE           AS VAC_OPE,
        b.FechaInicioNorm  AS VAC_FINI,
        b.FechaFinNorm     AS VAC_FFIN,

        CAST(
            CASE 
              WHEN b.SV_FINI = DATEFROMPARTS(1900,1,1) 
                   OR b.SV_FFIN = DATEFROMPARTS(1900,1,1)
                -- usar el mes de SV_HFEC para 7h/8h
                THEN b.SV_HOR / CASE WHEN MONTH(b.SV_HFEC) IN (7,8) THEN 7.0 ELSE 8.0 END
              ELSE b.SV_LAB
            END
        AS DECIMAL(10,2))   AS Dias_Solicitados,

        CAST(b.SV_HOR AS DECIMAL(10,2)) AS Horas_Solicitadas,
        YEAR(COALESCE(b.SV_HFEC, b.FechaInicioNorm)) AS Anio,
        est.SVE_DES         AS Estado
    FROM Base b
    JOIN SOL_VAC_EST est ON b.SV_EST = est.SVE_ID
    WHERE YEAR(COALESCE(b.SV_HFEC, b.FechaInicioNorm)) IN (YEAR(GETDATE()), YEAR(GETDATE())+1)
    ORDER BY COALESCE(b.SV_HFEC, b.FechaInicioNorm) DESC;
    ";

    $queryYears = "
        SELECT DISTINCT YEAR(COALESCE(sv.SV_HFEC,
               CASE WHEN CAST(sv.SV_FINI AS date) = DATEFROMPARTS(1900,1,1) THEN CAST(sv.SV_HFEC AS date)
                    ELSE CAST(sv.SV_FINI AS date) END)) AS Year
        FROM SOL_VAC sv
        JOIN PER p ON sv.SV_OPE = p.PER_NUM
        WHERE p.PER_NUM = :usuario
          AND sv.SV_EST = 5
        ORDER BY Year DESC;
    ";

    try {
        $stmt = $this->db->prepare($queryVac);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $stmtY = $this->db->prepare($queryYears);
        $stmtY->bindParam(':usuario', $data['usuario']);
        $stmtY->execute();
        $years = $stmtY->fetchAll(PDO::FETCH_COLUMN);

        echo json_encode([
            'success' => true,
            'data' => [
                'vacations' => $vacations,
                'years'     => $years
            ]
        ]);
    } catch (PDOException $e) {
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}






    public function getOperarioContrato($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Validación de entrada
    if (!isset($data['usuario'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado']);
        exit;
    }

    if (!is_string($data['usuario'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Formato de usuario incorrecto']);
        exit;
    }

    // Declaración preparada para evitar inyecciones SQL
        
        $query = "
    SELECT 
        PC_OPE,  -- Operario
        PC_HOR AS Horas_Semanales,  -- Horas semanales del contrato
        CAST(
            23 * (PC_HOR / 40.0) * 
            CASE 
                WHEN YEAR(PC_FINI) = YEAR(GETDATE()) THEN 
                    DATEDIFF(DAY, PC_FINI, DATEFROMPARTS(YEAR(GETDATE()), 12, 31)) / 365.0
                ELSE 
                    1
            END
        AS INT) AS Dias_Laborables  -- Calcular días laborables proporcionales según la fecha de inicio del contrato
    FROM 
        LIST_PERSONAL_CONTRATO_ULTIMO
    WHERE 
        PC_OPE = (SELECT PER_NUM FROM PER WHERE PER_ONLINE_LOG = :usuario)
";

    try {
        // Ejecutar la consulta
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $contrato = $stmt->fetch(PDO::FETCH_ASSOC);

        // Devolver los resultados como JSON
        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'data' => $contrato]);
    } catch (PDOException $e) {
        // Devolver un mensaje de error si ocurre una excepción
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}


    //Bloque sacar  los datos de las vacaciones

//     public function getVacationSummary($data) {
//     // Validación del token de autenticación
//     $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
//     if ($data['token'] !== $token) {
//         header('Content-Type: application/json');
//         echo json_encode(['success' => false, 'message' => 'Token inválido']);
//         exit;
//     } 

//     // Validación de entrada
//     if (!isset($data['usuario'])) {
//         header('Content-Type: application/json');
//         echo json_encode(['success' => false, 'message' => 'Usuario no especificado']);
//         exit;
//     }

//     if (!is_string($data['usuario'])) {
//         header('Content-Type: application/json');
//         echo json_encode(['success' => false, 'message' => 'Formato de usuario incorrecto']);
//         exit;
//     }

//     try {
//         // Paso 1: Obtener los días asignados por contrato
//         $queryDiasAsignados = "
//             SELECT
//                 PC_OPE,
//                 CAST(22 * (PC_HOR / 40.0) AS DECIMAL(10,2)) AS Dias_Asignados
//             FROM
//                 LIST_PERSONAL_CONTRATO_ULTIMO
//             WHERE
//                 PC_OPE = :usuario
//         ";
//         $stmtAsignados = $this->db->prepare($queryDiasAsignados);
//         $stmtAsignados->bindParam(':usuario', $data['usuario']);
//         $stmtAsignados->execute();
//         $diasAsignados = $stmtAsignados->fetch(PDO::FETCH_ASSOC);

//         // Paso 2: Obtener los días disfrutados en el año en curso
//         $queryDiasDisfrutados = "
//             SELECT
//                 CAST(SUM(COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS DECIMAL(10,2)) AS Dias_Disfrutados
//             FROM
//                 VAC v
//             LEFT JOIN
//                 PER p ON v.VAC_OPE = p.PER_NUM
//             WHERE
//                 p.PER_NUM = :usuario
//                 AND v.VAC_TIP = 1
//                 AND YEAR(v.VAC_FSOL)= YEAR(GETDATE())
//             GROUP BY
//                 v.VAC_OPE
//         ";
//         $stmtDisfrutados = $this->db->prepare($queryDiasDisfrutados);
//         $stmtDisfrutados->bindParam(':usuario', $data['usuario']);
//         $stmtDisfrutados->execute();
//         $diasDisfrutados = $stmtDisfrutados->fetch(PDO::FETCH_ASSOC);

//         // Paso 3: Obtener los días pendientes de aprobación
//         $queryDiasPendientes = "
//             SELECT
//                 CAST(SUM(sv.SV_LAB) AS DECIMAL(10,2)) AS Dias_Pendientes
//             FROM
//                 SOL_VAC sv
//             LEFT JOIN
//                 PER p ON sv.SV_OPE = p.PER_NUM
//             WHERE
//                 p.PER_NUM = :usuario
//                 AND sv.SV_EST = 4
//                 AND YEAR(sv.SV_FFIN) = YEAR(GETDATE())
//             GROUP BY
//                 sv.SV_OPE
//         ";
//         $stmtPendientes = $this->db->prepare($queryDiasPendientes);
//         $stmtPendientes->bindParam(':usuario', $data['usuario']);
//         $stmtPendientes->execute();
//         $diasPendientes = $stmtPendientes->fetch(PDO::FETCH_ASSOC);

//         // Paso 4: Calcular los días restantes
//         $diasAsignadosTotal = floatval($diasAsignados['Dias_Asignados'] ?? 0);
//         $diasDisfrutadosTotal = floatval($diasDisfrutados['Dias_Disfrutados'] ?? 0);
//         $diasPendientesTotal = floatval($diasPendientes['Dias_Pendientes'] ?? 0);

//         $diasRestantes = $diasAsignadosTotal - $diasDisfrutadosTotal - $diasPendientesTotal;

//         // Devolver los resultados como JSON
//         header('Content-Type: application/json');
//         echo json_encode([
//             'success' => true,
//             'data' => [
//                 'Dias_Asignados' => number_format($diasAsignadosTotal, 2),
//                 'Dias_Disfrutados' => number_format($diasDisfrutadosTotal, 2),
//                 'Dias_Pendientes' => number_format($diasPendientesTotal, 2),
//                 'Dias_Restantes' => number_format($diasRestantes, 2)
//             ]
//         ]);
//     } catch (PDOException $e) {
//         // Manejar errores de base de datos
//         header('Content-Type: application/json');
//         echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
//     }
// }

public function getVacationSummary($data) {
    // 1) Token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if (($data['token'] ?? '') !== $token) {
        return json_encode(['success' => false, 'message' => 'Token inválido']);
    }
    // 2) Usuario
    if (empty($data['usuario']) || !is_string($data['usuario'])) {
        return json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']);
    }

    try {
        /* ===== 1) DÍAS ASIGNADOS ===== */
$queryDiasAsignados = "
WITH Contracts AS (
  SELECT
    [Operario]                AS PC_OPE,
    CAST([Fecha Ini] AS date) AS PC_FINI,
    CAST([Fecha Fin] AS date) AS PC_FFIN,
    LTRIM(RTRIM(UPPER(COALESCE([Tipo],N'')))) AS PC_TIPO
  FROM [LIST_PERSONAL_CONTRATOS]
  WHERE [Operario] = :usuario
),
Bounds AS (
  SELECT
    DATEFROMPARTS(YEAR(GETDATE()),1,1)  AS YStart,
    DATEFROMPARTS(YEAR(GETDATE()),12,31) AS YEnd
),
-- contratos que tocan el año
InYear AS (
  SELECT c.*, b.YStart, b.YEnd
  FROM Contracts c
  CROSS JOIN Bounds b
  WHERE (c.PC_FINI IS NULL OR c.PC_FINI <= b.YEnd)
    AND (c.PC_FFIN IS NULL OR c.PC_FFIN >= b.YStart)
),
-- recorte al año
Effective AS (
  SELECT
    LTRIM(RTRIM(UPPER(PC_TIPO))) AS PC_TIPO,
    CASE WHEN PC_FINI IS NULL OR PC_FINI < YStart THEN YStart ELSE PC_FINI END AS EffectiveStart,
    CASE WHEN PC_FFIN IS NULL OR PC_FFIN > YEnd   THEN YEnd   ELSE PC_FFIN END AS EffectiveEnd
  FROM InYear
),
-- solo NO BECARIO
NonBeca AS (
  SELECT *
  FROM Effective
  WHERE PC_TIPO <> N'BECARIO'
    AND EffectiveEnd >= EffectiveStart
),
-- meses devengo por tramo (incluye el mes si día fin >= día inicio)
Meses AS (
  SELECT
    CASE
      WHEN DAY(EffectiveEnd) >= DAY(EffectiveStart)
        THEN DATEDIFF(MONTH, EffectiveStart, EffectiveEnd) + 1
      ELSE DATEDIFF(MONTH, EffectiveStart, EffectiveEnd)
    END AS MesesDevengo
  FROM NonBeca
)
SELECT CAST(
  (23.0/12.0) * COALESCE((SELECT SUM(MesesDevengo) FROM Meses), 0)
AS DECIMAL(10,2)) AS Dias_Asignados;
";



        $stmtAsignados = $this->db->prepare($queryDiasAsignados);
        $stmtAsignados->bindParam(':usuario', $data['usuario']);
        $stmtAsignados->execute();
        $diasAsignados = $stmtAsignados->fetch(PDO::FETCH_ASSOC) ?: ['Dias_Asignados' => 0];

        /* ===== 2) DÍAS DISFRUTADOS =====
           - FechaReal: VAC_HFEC si hay horas (>0) y no es NULL; si no, VAC_FINI
           - Jornada: contrato que CUBRE FechaReal; si no hay, último anterior; si tampoco, primero posterior; si nada, 8.0
           - Divisor: si mes 7/8 y jornada ~8h (|8 - HorasDiaBase| < 0.01) ⇒ 7.0; si no ⇒ HorasDiaBase
           - Suma: VAC_LAB + (VAC_HOR / divisor)
           - Año: por año de SOLICITUD (VAC_FSOL) como en tu pantalla
        */
        $queryDiasDisfrutados = "
;WITH Q AS (
    SELECT
        v.VAC_ID, v.VAC_OPE, v.VAC_FSOL, v.VAC_FINI, v.VAC_FFIN, v.VAC_HFEC,
        COALESCE(v.VAC_LAB,0.0) AS VAC_LAB,
        COALESCE(v.VAC_HOR,0.0) AS VAC_HOR,
        CASE
            WHEN COALESCE(v.VAC_HOR,0) > 0 AND v.VAC_HFEC IS NOT NULL
                 THEN CAST(v.VAC_HFEC AS date)
            ELSE CAST(v.VAC_FINI AS date)
        END AS FechaReal
    FROM VAC v
    WHERE v.VAC_OPE = :usuario
      AND YEAR(v.VAC_FSOL) = YEAR(GETDATE())
      AND v.VAC_TIP IN (1,3)
      AND (COALESCE(v.VAC_LAB,0) > 0 OR COALESCE(v.VAC_HOR,0) > 0)
),
QH AS (
    SELECT
        Q.*,
        COALESCE(NULLIF(ch.HorasDia,0), 8.0) AS HorasDiaBase
    FROM Q
    OUTER APPLY (
        SELECT TOP (1)
               CAST(NULLIF(s.[Nº Horas],0)/5.0 AS DECIMAL(18,6)) AS HorasDia
        FROM (
            -- (1) CUBRE FechaReal (incluye abierto fin NULL)
            SELECT c.[Nº Horas], c.[Fecha Ini], 1 AS prio
            FROM LIST_PERSONAL_CONTRATOS c
            WHERE c.Operario = Q.VAC_OPE
              AND Q.FechaReal >= CAST(c.[Fecha Ini] AS date)
              AND (c.[Fecha Fin] IS NULL OR Q.FechaReal < DATEADD(day,1, CAST(c.[Fecha Fin] AS date)))
            UNION ALL
            -- (2) Último ANTERIOR
            SELECT c.[Nº Horas], c.[Fecha Ini], 2
            FROM LIST_PERSONAL_CONTRATOS c
            WHERE c.Operario = Q.VAC_OPE
              AND CAST(c.[Fecha Ini] AS date) <= Q.FechaReal
            UNION ALL
            -- (3) Primer POSTERIOR
            SELECT c.[Nº Horas], c.[Fecha Ini], 3
            FROM LIST_PERSONAL_CONTRATOS c
            WHERE c.Operario = Q.VAC_OPE
              AND CAST(c.[Fecha Ini] AS date) > Q.FechaReal
        ) s
        ORDER BY s.prio ASC, s.[Fecha Ini] DESC
    ) ch
),
Conv AS (
    SELECT
        QH.VAC_LAB,
        QH.VAC_HOR,
        QH.FechaReal,
        CASE
            WHEN QH.VAC_HOR > 0 THEN
                QH.VAC_HOR /
                (CASE
                    WHEN MONTH(QH.FechaReal) IN (7,8) AND ABS(QH.HorasDiaBase - 8.0) < 0.01 THEN 7.0
                    ELSE QH.HorasDiaBase
                 END)
            ELSE 0.0
        END AS DiasEqHoras
    FROM QH
)
SELECT CAST(
         ROUND(
           SUM( COALESCE(Conv.VAC_LAB,0) + COALESCE(Conv.DiasEqHoras,0) )
         , 2)
       AS DECIMAL(10,2)) AS Dias_Disfrutados
FROM Conv;

";
        $stmtDisfrutados = $this->db->prepare($queryDiasDisfrutados);
        $stmtDisfrutados->bindParam(':usuario', $data['usuario']);
        $stmtDisfrutados->execute();
        $diasDisfrutados = $stmtDisfrutados->fetch(PDO::FETCH_ASSOC) ?: ['Dias_Disfrutados' => 0];

        /* ===== 3) DÍAS PENDIENTES (hasta 15/01 del año siguiente) =====
           Regla simple y estable: 7h en jul/ago, 8h resto (sin mirar contrato)
        */
        $nextYear = (int)date('Y') + 1;
        $queryDiasPendientes = "
WITH Base AS (
  SELECT
    COALESCE(sv.SV_LAB,0) AS SV_LAB,
    COALESCE(sv.SV_HOR,0) AS SV_HOR,
    CAST(CASE WHEN CONVERT(date, sv.SV_FINI) = '1900-01-01' THEN sv.SV_HFEC ELSE sv.SV_FINI END AS date) AS FechaInicioNorm,
    CAST(CASE WHEN CONVERT(date, sv.SV_FFIN) = '1900-01-01' THEN sv.SV_HFEC ELSE sv.SV_FFIN END AS date) AS FechaFinNorm
  FROM SOL_VAC sv
  LEFT JOIN PER p ON sv.SV_OPE = p.PER_NUM
  WHERE p.PER_NUM = :usuario
    AND sv.SV_EST IN (4,1)
)
SELECT
  CAST(SUM(
    SV_LAB +
    CASE WHEN SV_HOR > 0
         THEN SV_HOR / CASE WHEN MONTH(FechaInicioNorm) IN (7,8) THEN 7.0 ELSE 8.0 END
         ELSE 0 END
  ) AS DECIMAL(10,2)) AS Dias_Pendientes
FROM Base
WHERE FechaFinNorm >= DATEFROMPARTS(YEAR(GETDATE()), 1, 1)
  AND FechaFinNorm <= DATEFROMPARTS(:next_year, 1, 15);
";
        $stmtPendientes = $this->db->prepare($queryDiasPendientes);
        $stmtPendientes->bindParam(':usuario', $data['usuario']);
        $stmtPendientes->bindParam(':next_year', $nextYear, PDO::PARAM_INT);
        $stmtPendientes->execute();
        $diasPendientes = $stmtPendientes->fetch(PDO::FETCH_ASSOC) ?: ['Dias_Pendientes' => 0];

        /* ===== 4) Ensamblado y redondeo (solo aquí) ===== */
        $diasAsignadosTotal   = (float)($diasAsignados['Dias_Asignados']    ?? 0);
        $diasDisfrutadosTotal = (float)($diasDisfrutados['Dias_Disfrutados'] ?? 0);
        $diasPendientesTotal  = (float)($diasPendientes['Dias_Pendientes']   ?? 0);

        // Mantén tu redondeo propio para asignados si aplica
        //$diasAsignadosTotal = $this->redondearDias($diasAsignadosTotal);
		// $diasAsignadosTotal = $this->redondearDias($diasAsignadosTotal);
		$diasAsignadosTotal = round($diasAsignadosTotal, 2);


        // Redondeo final a 2 decimales para presentación
        $diasAsignadosTotal   = round($diasAsignadosTotal,   2);
        $diasDisfrutadosTotal = round($diasDisfrutadosTotal, 2);
        $diasPendientesTotal  = round($diasPendientesTotal,  2);
        $diasRestantes        = round($diasAsignadosTotal - $diasDisfrutadosTotal - $diasPendientesTotal, 2);

        return json_encode([
            'success' => true,
            'data' => [
                'Dias_Asignados'   => $diasAsignadosTotal,
                'Dias_Disfrutados' => $diasDisfrutadosTotal, // ej. 16.64 en 2025
                'Dias_Pendientes'  => $diasPendientesTotal,
                'Dias_Restantes'   => $diasRestantes,
            ]
        ]);
    } catch (PDOException $e) {
        return json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage() ]);
    }
}







// public function getVacationSummary($data) {
//     // Validación del token de autenticación
//     $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
//     if ($data['token'] !== $token) {
//         return json_encode(['success' => false, 'message' => 'Token inválido']);
//     }

//     // Validación de entrada
//     if (empty($data['usuario']) || !is_string($data['usuario'])) {
//         return json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']);
//     }

//     $year = $data['year'] ?? date('Y'); // Año actual por defecto

//     try {
//         // Paso 1: Obtener los días asignados por contrato
//         $queryDiasAsignados = "
//             SELECT
//                 PC_OPE,
//                 CAST(
//                     22 * (PC_HOR / 40.0) * 
//                     CASE 
//                         WHEN YEAR(PC_FINI) = :year THEN 
//                             DATEDIFF(DAY, PC_FINI, DATEFROMPARTS(:year, 12, 31)) / 365.0
//                         ELSE 
//                             1
//                     END
//                 AS DECIMAL(10,2)) AS Dias_Asignados
//             FROM
//                 LIST_PERSONAL_CONTRATO_ULTIMO
//             WHERE
//                 PC_OPE = :usuario
//         ";
//         $stmtAsignados = $this->db->prepare($queryDiasAsignados);
//         $stmtAsignados->bindParam(':usuario', $data['usuario']);
//         $stmtAsignados->bindParam(':year', $year, PDO::PARAM_INT);
//         $stmtAsignados->execute();
//         $diasAsignados = $stmtAsignados->fetch(PDO::FETCH_ASSOC);

//         // Paso 2: Obtener los días disfrutados en el año seleccionado
//         $queryDiasDisfrutados = "
//             SELECT
//                 CAST(SUM(COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS DECIMAL(10,2)) AS Dias_Disfrutados
//             FROM
//                 VAC v
//             WHERE
//                 v.VAC_OPE = :usuario
//                 AND v.VAC_TIP = 1
//                 AND YEAR(v.VAC_FSOL) = :year
//         ";
//         $stmtDisfrutados = $this->db->prepare($queryDiasDisfrutados);
//         $stmtDisfrutados->bindParam(':usuario', $data['usuario']);
//         $stmtDisfrutados->bindParam(':year', $year, PDO::PARAM_INT);
//         $stmtDisfrutados->execute();
//         $diasDisfrutados = $stmtDisfrutados->fetch(PDO::FETCH_ASSOC);

//         // Paso 3: Obtener los días pendientes de aprobación
//         $queryDiasPendientes = "
//             SELECT
//                 CAST(SUM(COALESCE(sv.SV_LAB, 0)) AS DECIMAL(10,2)) AS Dias_Pendientes
//             FROM
//                 SOL_VAC sv
//             WHERE
//                 sv.SV_OPE = :usuario
//                 AND sv.SV_EST = 4
//                 AND YEAR(sv.SV_FFIN) = :year
//         ";
//         $stmtPendientes = $this->db->prepare($queryDiasPendientes);
//         $stmtPendientes->bindParam(':usuario', $data['usuario']);
//         $stmtPendientes->bindParam(':year', $year, PDO::PARAM_INT);
//         $stmtPendientes->execute();
//         $diasPendientes = $stmtPendientes->fetch(PDO::FETCH_ASSOC);

//         // Paso 4: Calcular los días restantes
//         $diasAsignadosTotal = floatval($diasAsignados['Dias_Asignados'] ?? 0);
//         $diasDisfrutadosTotal = floatval($diasDisfrutados['Dias_Disfrutados'] ?? 0);
//         $diasPendientesTotal = floatval($diasPendientes['Dias_Pendientes'] ?? 0);

//         $diasAsignadosTotal = $this->redondearDias($diasAsignadosTotal);
//         $diasDisfrutadosTotal = round($diasDisfrutadosTotal, 1);
//         $diasPendientesTotal = round($diasPendientesTotal, 1);

//         $diasRestantes = $diasAsignadosTotal - $diasDisfrutadosTotal - $diasPendientesTotal;

//         // Devolver los resultados como JSON
//         return json_encode([
//             'success' => true,
//             'data' => [
//                 'Dias_Asignados' => number_format($diasAsignadosTotal, 1),
//                 'Dias_Disfrutados' => number_format($diasDisfrutadosTotal, 1),
//                 'Dias_Pendientes' => number_format($diasPendientesTotal, 1),
//                 'Dias_Restantes' => number_format($diasRestantes, 1)
//             ]
//         ]);
//     } catch (PDOException $e) {
//         // Manejar errores de base de datos
//         return json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
//     }
// }




// Función para redondear los días asignados
private function redondearDias($dias) {
    $parteEntera = floor($dias);
    $parteDecimal = $dias - $parteEntera;

    return ($parteDecimal >= 0.5) ? ceil($dias) : floor($dias);
}








public function comprobarFechasVacaciones($data) {
    // Verificar si ya existen vacaciones para el operario en el mismo rango de fechas
    $query = "
        SELECT COUNT(*) AS total 
        FROM SOL_VAC 
        WHERE SV_OPE = :usuario 
        AND (
            (SV_FINI <= :fecha_fin AND SV_FFIN >= :fecha_inicio)  -- Rango de fechas que se solapan
        ) AND SV_EST = 4";  // Solo las solicitudes pendientes o confirmadas

    $stmt = $this->db->prepare($query);
    $stmt->bindParam(':usuario', $data['usuario']);
    $stmt->bindParam(':fecha_inicio', $data['fecha_inicio']);
    $stmt->bindParam(':fecha_fin', $data['fecha_fin']);
    $stmt->execute();
    $result = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($result['total'] > 0) {
        return json_encode(['success' => false, 'message' => 'Ya existe una solicitud confirmada en este rango de fechas.']);
    }

    return json_encode(['success' => true]);
}



// public function guardarSolicitudVacaciones($data) {
//     // Validación del token de autenticación
//     $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token esperado
//     if ($data['token'] !== $token) {
//         return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
//     }

//     // Validar si las fechas están dentro del año en curso
//     $currentYear = date('Y');
//     $fechaInicio = new DateTime($data['fecha_inicio']);
//     $fechaFin = new DateTime($data['fecha_fin']);
    
//     // Fecha actual (cuando se realiza la solicitud)
//     $fechaPeticion = new DateTime(); // Esto será el valor para SV_FEC

//     // Formatear las fechas en el formato 'Y-m-d H:i:s' para coincidir con el formato en la base de datos
//     $fechaInicioFormatted = $fechaInicio->format('Y-m-d H:i:s');
//     $fechaFinFormatted = $fechaFin->format('Y-m-d H:i:s');
//     $fechaPeticionFormatted = $fechaPeticion->format('Y-m-d H:i:s'); // Para SV_FEC

//     if ($fechaInicio->format('Y') !== $currentYear && $fechaFin->format('Y') !== $currentYear) {
//         return Response::json(['success' => false, 'message' => 'Las fechas deben estar dentro del año en curso.'], 400);
//     }

//     try {
//         // Comprobar si ya existe una solicitud SOL_VAC
//         $queryCheck = "
//             SELECT COUNT(*) AS total 
//             FROM SOL_VAC 
//             WHERE SV_OPE = :usuario 
//             AND (
//                 CONVERT(DATETIME, SV_FINI, 120) <= CONVERT(DATETIME, :fecha_fin, 120) 
//                 AND CONVERT(DATETIME, SV_FFIN, 120) >= CONVERT(DATETIME, :fecha_inicio, 120)
//             )
//             AND SV_EST IN (1,2,3,4)";
//         $stmtCheck = $this->db->prepare($queryCheck);
//         $stmtCheck->bindParam(':usuario', $data['usuario']);
//         $stmtCheck->bindParam(':fecha_inicio', $fechaInicioFormatted);
//         $stmtCheck->bindParam(':fecha_fin', $fechaFinFormatted);
//         $stmtCheck->execute();
//         $checkResult = $stmtCheck->fetch(PDO::FETCH_ASSOC);

//         if ($checkResult['total'] > 0) {
//             return Response::json(['success' => false, 'message' => 'Ya existe una solicitud confirmada en este rango de fechas.'], 400);
//         }


//         //Comprobar si ya existe en la tabla VAC
//         $queryCheckI = "
//             SELECT COUNT(*) AS total 
//             FROM VAC
//             WHERE VAC_OPE = :usuario 
//             AND (
//                 CONVERT(DATETIME, VAC_FINI, 120) <= CONVERT(DATETIME, :fecha_fin, 120) 
//                 AND CONVERT(DATETIME, VAC_FFIN, 120) >= CONVERT(DATETIME, :fecha_inicio, 120)
//             )
//             ";
//         $stmtCheckI = $this->db->prepare($queryCheckI);
//         $stmtCheckI->bindParam(':usuario', $data['usuario']);
//         $stmtCheckI->bindParam(':fecha_inicio', $fechaInicioFormatted);
//         $stmtCheckI->bindParam(':fecha_fin', $fechaFinFormatted);
//         $stmtCheckI->execute();
//         $checkResultI = $stmtCheckI->fetch(PDO::FETCH_ASSOC);

//         if ($checkResultI['total'] > 0) {
//             return Response::json(['success' => false, 'message' => 'Ya existe una solicitud confirmada en este rango de fechas..'], 400);
//         }



//         // Obtener el centro de trabajo del usuario (PER_CTR) desde la tabla PER
//         $queryCentroTrabajo = "SELECT PER_CTR FROM PER WHERE PER_NUM = :usuario";
//         $stmtCentroTrabajo = $this->db->prepare($queryCentroTrabajo);
//         $stmtCentroTrabajo->bindParam(':usuario', $data['usuario']);
//         $stmtCentroTrabajo->execute();
//         $centroTrabajo = $stmtCentroTrabajo->fetch(PDO::FETCH_ASSOC)['PER_CTR'];

//         // Obtener los días festivos nacionales (CL_CTR IS NULL) y locales por centro de trabajo
//         $queryFestivos = "
//             SELECT CONVERT(VARCHAR, CL_FEC, 23) AS Dia_Festivo
//             FROM CAL_LAB 
//             WHERE YEAR(CL_FEC) = :year
//             AND CL_FES = 1
//             AND (CL_CTR IS NULL OR CL_CTR = :centroTrabajo)";
//         $stmtFestivos = $this->db->prepare($queryFestivos);
//         $stmtFestivos->bindParam(':year', $currentYear);
//         $stmtFestivos->bindParam(':centroTrabajo', $centroTrabajo);
//         $stmtFestivos->execute();
//         $festivos = $stmtFestivos->fetchAll(PDO::FETCH_COLUMN);

//         // Calcular los días laborables excluyendo fines de semana y festivos
//         $diasLaborables = 0;
//         $fechaActual = clone $fechaInicio;
//         while ($fechaActual <= $fechaFin) {
//             $esFestivo = in_array($fechaActual->format('Y-m-d'), $festivos);
//             if (!$esFestivo && $fechaActual->format('N') < 6) { // Excluir fines de semana (sábado=6, domingo=7)
//                 $diasLaborables++;
//             }
//             $fechaActual->modify('+1 day');
//         }

//         // Obtener el último SV_ID e incrementar de manera personalizada
//         $query = "SELECT MAX(SV_ID) AS last_id FROM SOL_VAC";
//         $stmt = $this->db->prepare($query);
//         $stmt->execute();
//         $lastId = $stmt->fetch(PDO::FETCH_ASSOC)['last_id'];

//         // Extraer los últimos 4 dígitos del último SV_ID
//         $lastFourDigits = (int)substr($lastId, -4);

//         // Incrementar en 1
//         $newFourDigits = str_pad($lastFourDigits + 1, 4, '0', STR_PAD_LEFT);

//         // Concatenar el año actual con los 4 dígitos incrementados
//         $newId = $currentYear . $newFourDigits;

//         // Insertar la solicitud de vacaciones incluyendo SV_FEC (fecha de la solicitud)
//         $query = "INSERT INTO SOL_VAC (SV_ID, SV_OPE, SV_FINI, SV_FFIN, SV_FEC, SV_DIAS, SV_LAB, SV_EST, SV_USU, SV_EMP) 
//                   VALUES (:newId, :usuario, CONVERT(DATETIME, :fecha_inicio, 120), CONVERT(DATETIME, :fecha_fin, 120), CONVERT(DATETIME, :fecha_peticion, 120), :dias_naturales, :dias_laborables, 4, 1, 0)";

//         $diasNaturales = $fechaFin->diff($fechaInicio)->days + 1; // Total de días naturales
//         $stmt = $this->db->prepare($query);
//         $stmt->bindParam(':newId', $newId);
//         $stmt->bindParam(':usuario', $data['usuario']);
//         $stmt->bindParam(':fecha_inicio', $fechaInicioFormatted);
//         $stmt->bindParam(':fecha_fin', $fechaFinFormatted);
//         $stmt->bindParam(':fecha_peticion', $fechaPeticionFormatted);  // Fecha de la petición (SV_FEC)
//         $stmt->bindParam(':dias_naturales', $diasNaturales);
//         $stmt->bindParam(':dias_laborables', $diasLaborables);

//         if ($stmt->execute()) {
//             return Response::json(['success' => true, 'message' => 'Solicitud de vacaciones enviada exitosamente'], 200);
//         } else {
//             return Response::json(['success' => false, 'message' => 'Error al procesar la solicitud'], 500);
//         }
//     } catch (PDOException $e) {
//         return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
//     }
// }
    

//     public function guardarSolicitudVacaciones($data) {
//     // Validación del token de autenticación
//     $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token esperado
//     if ($data['token'] !== $token) {
//         return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
//     }

//     // Validar si las fechas están dentro del año en curso
//     $currentYear = date('Y');
//     $fechaInicio = new DateTime($data['fecha_inicio']);
//     $fechaFin = new DateTime($data['fecha_fin']);
    
//     // Fecha actual (cuando se realiza la solicitud)
//     $fechaPeticion = new DateTime(); // Esto será el valor para SV_FEC

//     // Formatear las fechas en el formato 'Y-m-d H:i:s' para coincidir con el formato en la base de datos
//     $fechaInicioFormatted = $fechaInicio->format('Y-m-d H:i:s');
//     $fechaFinFormatted = $fechaFin->format('Y-m-d H:i:s');
//     $fechaPeticionFormatted = $fechaPeticion->format('Y-m-d H:i:s'); // Para SV_FEC

//     if ($fechaInicio->format('Y') !== $currentYear && $fechaFin->format('Y') !== $currentYear) {
//         return Response::json(['success' => false, 'message' => 'Las fechas deben estar dentro del año en curso.'], 400);
//     }

//     try {
//         // Paso 1: Obtener los días asignados por contrato y aplicar redondeo
//         $queryDiasAsignados = "
//     SELECT 
//         CAST(
//             22 * (PC_HOR / 40.0) *
//             CASE 
//                 WHEN YEAR(PC_FINI) = YEAR(GETDATE()) THEN 
//                     DATEDIFF(DAY, PC_FINI, DATEFROMPARTS(YEAR(GETDATE()), 12, 31)) / 365.0
//                 ELSE 
//                     1
//             END
//         AS DECIMAL(10,2)) AS Dias_Asignados
//     FROM 
//         LIST_PERSONAL_CONTRATO_ULTIMO
//     WHERE 
//         PC_OPE = :usuario
// ";
//         $stmtDiasAsignados = $this->db->prepare($queryDiasAsignados);
//         $stmtDiasAsignados->bindParam(':usuario', $data['usuario']);
//         $stmtDiasAsignados->execute();
//         $diasAsignados = floatval($stmtDiasAsignados->fetch(PDO::FETCH_ASSOC)['Dias_Asignados'] ?? 0);

//         // Redondear los días asignados
//         $diasAsignados = round($diasAsignados, 0, PHP_ROUND_HALF_UP);

//         // Paso 2: Obtener los días disfrutados en el año en curso
//         $queryDiasDisfrutados = "
//             SELECT CAST(SUM(COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS DECIMAL(10,2)) AS Dias_Disfrutados
//             FROM VAC v
//             LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
//             WHERE p.PER_NUM = :usuario
//             AND v.VAC_TIP = 1
//             AND YEAR(v.VAC_FSOL) = YEAR(GETDATE())
//         ";
//         $stmtDiasDisfrutados = $this->db->prepare($queryDiasDisfrutados);
//         $stmtDiasDisfrutados->bindParam(':usuario', $data['usuario']);
//         $stmtDiasDisfrutados->execute();
//         $diasDisfrutados = floatval($stmtDiasDisfrutados->fetch(PDO::FETCH_ASSOC)['Dias_Disfrutados'] ?? 0);

//         // Paso 3: Obtener los días pendientes de aprobación
//         $queryDiasPendientes = "
//             SELECT CAST(SUM(sv.SV_LAB) AS DECIMAL(10,2)) AS Dias_Pendientes
//             FROM SOL_VAC sv
//             LEFT JOIN PER p ON sv.SV_OPE = p.PER_NUM
//             WHERE p.PER_NUM = :usuario
//             AND sv.SV_EST = 4
//             AND YEAR(sv.SV_FFIN) = YEAR(GETDATE())
//         ";
//         $stmtDiasPendientes = $this->db->prepare($queryDiasPendientes);
//         $stmtDiasPendientes->bindParam(':usuario', $data['usuario']);
//         $stmtDiasPendientes->execute();
//         $diasPendientes = floatval($stmtDiasPendientes->fetch(PDO::FETCH_ASSOC)['Dias_Pendientes'] ?? 0);

//         // Calcular los días restantes
//         $diasRestantes = $diasAsignados - $diasDisfrutados - $diasPendientes;

//         // Calcular los días laborables solicitados en la solicitud
//         $diasSolicitados = 0;
//         $fechaActual = clone $fechaInicio;
//         while ($fechaActual <= $fechaFin) {
//             if ($fechaActual->format('N') < 6) { // Excluir fines de semana
//                 $diasSolicitados++;
//             }
//             $fechaActual->modify('+1 day');
//         }

//         // Comprobar si el usuario tiene suficientes días restantes para la solicitud
//         if ($diasSolicitados > $diasRestantes) {
//             return Response::json(['success' => false, 'message' => 'No dispone de suficientes días laborables para esta solicitud.'], 400);
//         }

//         // Obtener el último SV_ID e incrementar de manera personalizada
//         $query = "SELECT MAX(SV_ID) AS last_id FROM SOL_VAC";
//         $stmt = $this->db->prepare($query);
//         $stmt->execute();
//         $lastId = $stmt->fetch(PDO::FETCH_ASSOC)['last_id'];

//         // Extraer los últimos 4 dígitos del último SV_ID
//         $lastFourDigits = (int)substr($lastId, -4);

//         // Incrementar en 1
//         $newFourDigits = str_pad($lastFourDigits + 1, 4, '0', STR_PAD_LEFT);

//         // Concatenar el año actual con los 4 dígitos incrementados
//         $newId = $currentYear . $newFourDigits;

//         // Insertar la solicitud de vacaciones incluyendo SV_FEC (fecha de la solicitud)
//         $query = "INSERT INTO SOL_VAC (SV_ID, SV_OPE, SV_FINI, SV_FFIN, SV_FEC, SV_DIAS, SV_LAB, SV_EST, SV_USU, SV_EMP) 
//                   VALUES (:newId, :usuario, CONVERT(DATETIME, :fecha_inicio, 120), CONVERT(DATETIME, :fecha_fin, 120), CONVERT(DATETIME, :fecha_peticion, 120), :dias_naturales, :dias_laborables, 4, 1, 0)";

//         $diasNaturales = $fechaFin->diff($fechaInicio)->days + 1; // Total de días naturales
//         $stmt = $this->db->prepare($query);
//         $stmt->bindParam(':newId', $newId);
//         $stmt->bindParam(':usuario', $data['usuario']);
//         $stmt->bindParam(':fecha_inicio', $fechaInicioFormatted);
//         $stmt->bindParam(':fecha_fin', $fechaFinFormatted);
//         $stmt->bindParam(':fecha_peticion', $fechaPeticionFormatted);  // Fecha de la petición (SV_FEC)
//         $stmt->bindParam(':dias_naturales', $diasNaturales);
//         $stmt->bindParam(':dias_laborables', $diasSolicitados);

//         if ($stmt->execute()) {
//             return Response::json(['success' => true, 'message' => 'Solicitud de vacaciones enviada exitosamente'], 200);
//         } else {
//             return Response::json(['success' => false, 'message' => 'Error al procesar la solicitud'], 500);
//         }
//     } catch (PDOException $e) {
//         return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
//     }
// }

    


public function guardarSolicitudVacaciones($data)
{
    $tokenEsperado = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';

    // 0) Seguridad básica
    if (($data['token'] ?? null) !== $tokenEsperado) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }
    if (!isset($data['usuario']) || !is_string($data['usuario'])) {
        return Response::json(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto'], 400);
    }
    if (!isset($data['tipo_solicitud']) || !in_array($data['tipo_solicitud'], ['completa', 'parcial'], true)) {
        return Response::json(['success' => false, 'message' => 'Tipo de solicitud no válido'], 400);
    }

    $usuario     = $data['usuario'];
    $currentYear = date('Y');

    try {
        // 1) Fechas
        $fechaInicio  = new \DateTime($data['fecha_inicio']);
        $fechaFin     = ($data['tipo_solicitud'] === 'parcial')
            ? clone $fechaInicio
            : new \DateTime($data['fecha_fin']);
        $fechaParcial = new \DateTime($data['sv_hfec'] ?? $data['fecha_inicio']);
        $fechaPeticion = new \DateTime();

        $fiStr   = $fechaInicio->format('Y-m-d H:i:s');
        $ffStr   = $fechaFin->format('Y-m-d H:i:s');
        $hfecStr = $fechaParcial->format('Y-m-d H:i:s');
        $svFecSoloFecha = $fechaPeticion->format('Y-m-d') . ' 00:00:00';

        // 2) Regla de año en curso
        if ($fechaInicio->format('Y') !== $currentYear && $fechaFin->format('Y') !== $currentYear) {
            return Response::json(['success' => false, 'message' => 'Las fechas deben estar dentro del año en curso.'], 400);
        }

        /* =====================================================================
         * 3) COMPROBACIÓN DE SOLAPES POR USUARIO (SOL_VAC + VAC)
         * ===================================================================== */
        $sqlOverlap = "
            SELECT COUNT(*) AS total
            FROM (
                -- Solicitudes de vacaciones (SOL_VAC)
                SELECT 1 AS src
                FROM SOL_VAC S
                WHERE S.SV_OPE = :usuario
                  AND S.SV_EST IN (1,2,3,4)
                  AND (
                        (
                          CONVERT(date, S.SV_FINI) <> '1900-01-01'
                          AND CONVERT(DATETIME, S.SV_FINI, 120) <= CONVERT(DATETIME, :ff_a, 120)
                          AND CONVERT(DATETIME, S.SV_FFIN, 120) >= CONVERT(DATETIME, :fi_a, 120)
                        )
                        OR
                        (
                          CONVERT(date, S.SV_FINI) = '1900-01-01'
                          AND CONVERT(DATETIME, S.SV_HFEC, 120) >= CONVERT(DATETIME, :fi_b, 120)
                          AND CONVERT(DATETIME, S.SV_HFEC, 120) <= CONVERT(DATETIME, :ff_b, 120)
                        )
                      )

                UNION ALL

                -- Vacaciones confirmadas (VAC)
                SELECT 1 AS src
                FROM VAC V
                WHERE V.VAC_OPE = :usuario_v
                  AND (
                        (
                          CONVERT(date, V.VAC_FINI) <> '1900-01-01'
                          AND CONVERT(DATETIME, V.VAC_FINI, 120) <= CONVERT(DATETIME, :ff_a2, 120)
                          AND CONVERT(DATETIME, V.VAC_FFIN, 120) >= CONVERT(DATETIME, :fi_a2, 120)
                        )
                        OR
                        (
                          CONVERT(date, V.VAC_FINI) = '1900-01-01'
                          AND CONVERT(DATETIME, V.VAC_HFEC, 120) >= CONVERT(DATETIME, :fi_b2, 120)
                          AND CONVERT(DATETIME, V.VAC_HFEC, 120) <= CONVERT(DATETIME, :ff_b2, 120)
                        )
                      )
            ) X
        ";

        $stOverlap = $this->db->prepare($sqlOverlap);
        $stOverlap->bindParam(':usuario',   $usuario);
        $stOverlap->bindParam(':fi_a',      $fiStr);
        $stOverlap->bindParam(':ff_a',      $ffStr);
        $stOverlap->bindParam(':fi_b',      $fiStr);
        $stOverlap->bindParam(':ff_b',      $ffStr);

        $stOverlap->bindParam(':usuario_v', $usuario);
        $stOverlap->bindParam(':fi_a2',     $fiStr);
        $stOverlap->bindParam(':ff_a2',     $ffStr);
        $stOverlap->bindParam(':fi_b2',     $fiStr);
        $stOverlap->bindParam(':ff_b2',     $ffStr);

        $stOverlap->execute();
        $over = $stOverlap->fetch(PDO::FETCH_ASSOC);

        if ((int)($over['total'] ?? 0) > 0) {
            return Response::json([
                'success' => false,
                'message' => 'Ya existe una solicitud o vacación confirmada en este rango de fechas.'
            ], 400);
        }

        /* =====================================================================
         * 4) CONTROL DE CUPO POR DEPARTAMENTO
         * ===================================================================== */

        // 4.1) Obtener departamento del operario y máximo de solape
        $sqlDep = "
            SELECT D.DEP_ID, D.DEP_SOLAPE_MAX_VAC
            FROM PER P
            INNER JOIN DEP D ON D.DEP_ID = P.PER_DEP
            WHERE P.PER_NUM = :usuario_dep
        ";
        $stDep = $this->db->prepare($sqlDep);
        $stDep->bindParam(':usuario_dep', $usuario);
        $stDep->execute();
        $depRow = $stDep->fetch(PDO::FETCH_ASSOC);

        if ($depRow) {
            $depId  = (int)$depRow['DEP_ID'];

            // Si es NULL, aplicamos tu regla: resto máximo 2
            $depMax = ($depRow['DEP_SOLAPE_MAX_VAC'] !== null)
                ? (int)$depRow['DEP_SOLAPE_MAX_VAC']
                : 2;

            // Si depMax <= 0, no tiene sentido aplicar tope
            if ($depMax > 0) {
                $sqlDepOverlap = "
                    SELECT COUNT(DISTINCT OPE) AS total
                    FROM (
                        -- Solicitudes en SOL_VAC
                        SELECT S.SV_OPE AS OPE
                        FROM SOL_VAC S
                        INNER JOIN PER P1 ON P1.PER_NUM = S.SV_OPE
                        WHERE P1.PER_DEP = :depId_sv
                          AND S.SV_EST IN (1,2,3,4)
                          AND (
                                (
                                  CONVERT(date, S.SV_FINI) <> '1900-01-01'
                                  AND CONVERT(DATETIME, S.SV_FINI, 120) <= CONVERT(DATETIME, :ff_a_dep, 120)
                                  AND CONVERT(DATETIME, S.SV_FFIN, 120) >= CONVERT(DATETIME, :fi_a_dep, 120)
                                )
                                OR
                                (
                                  CONVERT(date, S.SV_FINI) = '1900-01-01'
                                  AND CONVERT(DATETIME, S.SV_HFEC, 120) >= CONVERT(DATETIME, :fi_b_dep, 120)
                                  AND CONVERT(DATETIME, S.SV_HFEC, 120) <= CONVERT(DATETIME, :ff_b_dep, 120)
                                )
                              )

                        UNION

                        -- Vacaciones confirmadas en VAC
                        SELECT V.VAC_OPE AS OPE
                        FROM VAC V
                        INNER JOIN PER P2 ON P2.PER_NUM = V.VAC_OPE
                        WHERE P2.PER_DEP = :depId_vac
                          AND (
                                (
                                  CONVERT(date, V.VAC_FINI) <> '1900-01-01'
                                  AND CONVERT(DATETIME, V.VAC_FINI, 120) <= CONVERT(DATETIME, :ff_c_dep, 120)
                                  AND CONVERT(DATETIME, V.VAC_FFIN, 120) >= CONVERT(DATETIME, :fi_c_dep, 120)
                                )
                                OR
                                (
                                  CONVERT(date, V.VAC_FINI) = '1900-01-01'
                                  AND CONVERT(DATETIME, V.VAC_HFEC, 120) >= CONVERT(DATETIME, :fi_d_dep, 120)
                                  AND CONVERT(DATETIME, V.VAC_HFEC, 120) <= CONVERT(DATETIME, :ff_d_dep, 120)
                                )
                              )
                    ) X
                ";

                $stDepOverlap = $this->db->prepare($sqlDepOverlap);

                $stDepOverlap->bindParam(':depId_sv',  $depId, PDO::PARAM_INT);
                $stDepOverlap->bindParam(':depId_vac', $depId, PDO::PARAM_INT);

                $stDepOverlap->bindParam(':fi_a_dep', $fiStr);
                $stDepOverlap->bindParam(':ff_a_dep', $ffStr);
                $stDepOverlap->bindParam(':fi_b_dep', $fiStr);
                $stDepOverlap->bindParam(':ff_b_dep', $ffStr);

                $stDepOverlap->bindParam(':fi_c_dep', $fiStr);
                $stDepOverlap->bindParam(':ff_c_dep', $ffStr);
                $stDepOverlap->bindParam(':fi_d_dep', $fiStr);
                $stDepOverlap->bindParam(':ff_d_dep', $ffStr);

                $stDepOverlap->execute();
                $depOver = $stDepOverlap->fetch(PDO::FETCH_ASSOC);
                $totalDepto = (int)($depOver['total'] ?? 0);

                // Si ya hay depMax personas, añadir una más rompería el cupo
                if ($totalDepto >= $depMax) {
                    return Response::json([
                        'success' => false,
                        'message' => 'Para esta fecha ya está cogido el cupo máximo. Por favor, hable con su encargado y con administración.'
                    ], 400);
                }
            }
        }

        /* =====================================================================
         * 5) GENERAR SV_ID (AAAA + correlativo)
         * ===================================================================== */
        $stmtId = $this->db->prepare("SELECT MAX(SV_ID) AS last_id FROM SOL_VAC");
        $stmtId->execute();
        $lastId   = $stmtId->fetch(PDO::FETCH_ASSOC)['last_id'] ?? '00000000';
        $lastFour = (int)substr($lastId, -4);
        $newFour  = str_pad($lastFour + 1, 4, '0', STR_PAD_LEFT);
        $newId    = $currentYear . $newFour;

        /* =====================================================================
         * 6) INSERT SEGÚN TIPO DE SOLICITUD
         * ===================================================================== */
        if ($data['tipo_solicitud'] === 'completa') {
            // Días naturales y laborables (cliente los manda ya calculados)
            $diasNaturales  = ($fechaFin->diff($fechaInicio)->days + 1);
            $diasLaborables = (int)($data['dias_solicitados'] ?? 0);

            $sqlInsert = "
                INSERT INTO SOL_VAC
                  (SV_ID, SV_OPE, SV_FINI, SV_FFIN, SV_FEC, SV_DIAS, SV_LAB, SV_HOR, SV_EST, SV_USU, SV_EMP, SV_HFEC)
                VALUES
                  (:newId, :usuario,
                   CONVERT(DATETIME, :fi_ins, 120),
                   CONVERT(DATETIME, :ff_ins, 120),
                   CONVERT(DATETIME, :fec_solo, 120),
                   :dias_nat, :dias_lab, 0, 4, 1, 0, NULL)
            ";

            $stIns = $this->db->prepare($sqlInsert);
            $stIns->bindParam(':newId',    $newId);
            $stIns->bindParam(':usuario',  $usuario);
            $stIns->bindParam(':fi_ins',   $fiStr);
            $stIns->bindParam(':ff_ins',   $ffStr);
            $stIns->bindParam(':fec_solo', $svFecSoloFecha);
            $stIns->bindValue(':dias_nat', $diasNaturales, PDO::PARAM_INT);
            $stIns->bindValue(':dias_lab', $diasLaborables, PDO::PARAM_INT);

        } else {
            // Parcial: se guarda en horas y la fecha real en SV_HFEC
            $horasParciales = (float)($data['horas_parciales'] ?? 0);

            $sqlInsert = "
                INSERT INTO SOL_VAC
                  (SV_ID, SV_OPE, SV_FINI, SV_FFIN, SV_FEC, SV_DIAS, SV_LAB, SV_HOR, SV_EST, SV_USU, SV_EMP, SV_HFEC)
                VALUES
                  (:newId, :usuario,
                   CONVERT(DATETIME, '1900-01-01 00:00:00', 120),
                   CONVERT(DATETIME, '1900-01-01 00:00:00', 120),
                   CONVERT(DATETIME, :fec_solo, 120),
                   0, 0, :horas_parc, 4, 1, 0,
                   CONVERT(DATETIME, :hfec_ins, 120))
            ";

            $stIns = $this->db->prepare($sqlInsert);
            $stIns->bindParam(':newId',      $newId);
            $stIns->bindParam(':usuario',    $usuario);
            $stIns->bindParam(':fec_solo',   $svFecSoloFecha);
            $stIns->bindValue(':horas_parc', $horasParciales);
            $stIns->bindParam(':hfec_ins',   $hfecStr);
        }

        if ($stIns->execute()) {
            return Response::json(['success' => true, 'message' => 'Solicitud de vacaciones enviada exitosamente'], 200);
        }

        $err = $stIns->errorInfo();
        return Response::json([
            'success' => false,
            'message' => 'Error al procesar la solicitud',
            'debug'   => $err
        ], 500);

    } catch (\PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}










    public function getCountDiasEnfermedad($data) {
    // Validación del token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token esperado
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    try {
        $query = "
            SELECT SUM(VAC_DIAS) AS Total
            FROM VAC
            WHERE VAC_OPE = :usuario  -- El operario
            AND VAC_TIP = 2  -- Tipo de licencia
            AND YEAR(VAC_FINI) = YEAR(GETDATE());  -- Solo en el año actual
        ";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        return Response::json(['success' => true, 'data' => $result], 200);
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}


public function checkSolapamientosLicencias($data) {
    // Validación del token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token esperado
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    try {
        // Diferenciar entre vacaciones y enfermedad
        if ($data['tipo_licencia'] == 1) { // Vacaciones
            // Comprobación de solapamientos en SOL_VAC y VAC para vacaciones
            $querySolVac = "
                SELECT COUNT(*) AS Total
                FROM SOL_VAC
                WHERE VAC_OPE = :usuario
                AND (
                    (VAC_FINI <= CONVERT(DATETIME, :fecha_fin, 120)
                    AND VAC_FFIN >= CONVERT(DATETIME, :fecha_inicio, 120))
                )
                AND VAC_TIP = 1
                AND YEAR(VAC_FINI) = YEAR(GETDATE());
            ";

            $queryVac = "
                SELECT COUNT(*) AS Total
                FROM VAC
                WHERE VAC_OPE = :usuario
                AND (
                    (VAC_FINI <= CONVERT(DATETIME, :fecha_fin, 120)
                    AND VAC_FFIN >= CONVERT(DATETIME, :fecha_inicio, 120))
                )
                AND VAC_TIP = 1
                AND YEAR(VAC_FINI) = YEAR(GETDATE());
            ";

            $stmtSolVac = $this->db->prepare($querySolVac);
            $stmtSolVac->bindParam(':usuario', $data['usuario']);
            $stmtSolVac->bindParam(':fecha_inicio', $data['fecha_inicio']);
            $stmtSolVac->bindParam(':fecha_fin', $data['fecha_fin']);
            $stmtSolVac->execute();
            $resultSolVac = $stmtSolVac->fetch(PDO::FETCH_ASSOC);

            $stmtVac = $this->db->prepare($queryVac);
            $stmtVac->bindParam(':usuario', $data['usuario']);
            $stmtVac->bindParam(':fecha_inicio', $data['fecha_inicio']);
            $stmtVac->bindParam(':fecha_fin', $data['fecha_fin']);
            $stmtVac->execute();
            $resultVac = $stmtVac->fetch(PDO::FETCH_ASSOC);

            if ($resultSolVac['Total'] > 0 || $resultVac['Total'] > 0) {
                return Response::json(['success' => false, 'message' => 'Ya existe una solicitud de vacaciones en el rango de fechas especificado.'], 400);
            }

        } elseif ($data['tipo_licencia'] == 2) { // Enfermedad
            // Si es enfermedad, no solapamos con vacaciones
            $queryVac = "
                SELECT COUNT(*) AS Total
                FROM VAC
                WHERE VAC_OPE = :usuario
                AND (
                    (VAC_FINI <= CONVERT(DATETIME, :fecha_fin, 120)
                    AND VAC_FFIN >= CONVERT(DATETIME, :fecha_inicio, 120))
                )
                AND VAC_TIP = 2
                AND YEAR(VAC_FINI) = YEAR(GETDATE());
            ";

            $stmtVac = $this->db->prepare($queryVac);
            $stmtVac->bindParam(':usuario', $data['usuario']);
            $stmtVac->bindParam(':fecha_inicio', $data['fecha_inicio']);
            $stmtVac->bindParam(':fecha_fin', $data['fecha_fin']);
            $stmtVac->execute();
            $resultVac = $stmtVac->fetch(PDO::FETCH_ASSOC);

            if ($resultVac['Total'] > 0) {
                return Response::json(['success' => false, 'message' => 'Ya existe una licencia de enfermedad en el rango de fechas especificado.'], 400);
            }
        }

        // No hay solapamientos
        return Response::json(['success' => true, 'message' => 'No hay solapamientos en el rango de fechas especificado.'], 200);

    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}

    public function getLicenciasCronologicas($data) {
    // Validación del token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token esperado
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    try {
        $query = "
            SELECT * 
            FROM VAC 
            WHERE VAC_OPE = :usuario  -- El operario
            AND VAC_TIP <> 1  -- Excluir vacaciones
            --AND YEAR(VAC_FSOL) = YEAR(GETDATE())  -- Solo en el año actual
            ORDER BY VAC_FINI DESC;  -- Orden cronológico por fecha de inicio (más reciente primero)
        ";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

        return Response::json(['success' => true, 'data' => $result], 200);
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}

 public function getConfirmedLicens($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Validación de entrada
    if (!isset($data['usuario'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado']);
        exit;
    }

    if (!is_string($data['usuario'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Formato de usuario incorrecto']);
        exit;
    }

    // Declaración preparada para evitar inyecciones SQL
   $query = "
    SELECT
        p.PER_CTR,
        v.VAC_ID,
        v.VAC_OBS,
        v.VAC_TIP,
        vt.VT_NOM AS Tipo_Licencia,  -- Nombre del tipo de licencia desde la tabla VAC_TIP
        v.VAC_OPE,
        CASE
            WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC  -- Si hay horas, la fecha de inicio es la misma que la fecha en horas (VAC_HFEC)
            ELSE v.VAC_FINI                     -- Si no hay horas, se toma la fecha de inicio normal
        END AS Fecha_Inicio,  -- Fecha de inicio dependiendo de si es por horas o días
        CASE
            WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC  -- Si hay horas, la fecha de fin es la misma que la fecha en horas (VAC_HFEC)
            ELSE v.VAC_FFIN                     -- Si no hay horas, se toma la fecha de fin normal
        END AS Fecha_Fin,     -- Fecha de fin dependiendo de si es por horas o días
        (COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS Dias_Laborables  -- Sumar días laborables y convertir horas a días
       
    FROM
        VAC v
    LEFT JOIN
        PER p ON v.VAC_OPE = p.PER_NUM
    LEFT JOIN
        VAC_TIP vt ON v.VAC_TIP = vt.VT_ID  -- Unión con la tabla VAC_TIP para obtener el nombre del tipo de licencia
    WHERE
        p.PER_NUM = :usuario   -- Aquí se filtra por el usuario que está en sesión
        AND v.VAC_TIP <> 1  -- Excluir vacaciones de tipo 1 (vacaciones)
    ORDER BY 
        v.VAC_FINI DESC;  -- Orden cronológico descendente por la fecha de inicio
";

    try {
        // Ejecutar la consulta
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);

        // Devolver los resultados como JSON
        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'data' => $vacations]);
    } catch (PDOException $e) {
        // Devolver un mensaje de error si ocurre una excepción
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}



public function guardarLicencia($data) {
    // Validación del token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    $currentYear = date('Y');
    $fechaInicio = new DateTime($data['fecha_inicio']);
    $fechaFin = new DateTime($data['fecha_fin']);
    $fechaInicioFormatted = $fechaInicio->format('Y-m-d H:i:s');
    $fechaFinFormatted = $fechaFin->format('Y-m-d H:i:s');

    try {
        // Comprobar si ya existe un registro en el rango de fechas
        $queryCheck = "
            SELECT COUNT(*) AS total 
            FROM VAC
            WHERE VAC_OPE = :usuario 
            AND (
                CONVERT(DATETIME, VAC_FINI, 120) <= CONVERT(DATETIME, :fecha_fin, 120) 
                AND CONVERT(DATETIME, VAC_FFIN, 120) >= CONVERT(DATETIME, :fecha_inicio, 120)
            )";
        $stmtCheck = $this->db->prepare($queryCheck);
        $stmtCheck->bindParam(':usuario', $data['usuario']);
        $stmtCheck->bindParam(':fecha_inicio', $fechaInicioFormatted);
        $stmtCheck->bindParam(':fecha_fin', $fechaFinFormatted);
        $stmtCheck->execute();
        $checkResult = $stmtCheck->fetch(PDO::FETCH_ASSOC);

        if ($checkResult['total'] > 0) {
            return Response::json(['success' => false, 'message' => 'Ya existe un registro para ese rango de fechas.'], 400);
        }
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }

    if ($fechaInicio->format('Y') !== $currentYear || $fechaFin->format('Y') !== $currentYear) {
        return Response::json(['success' => false, 'message' => 'Las fechas deben estar dentro del año en curso.'], 400);
    }

    // Cálculo de días asignados y días disfrutados para verificar si tiene suficientes días de vacaciones
    if ($data['tipo_licencia'] == 1) {
        $queryDiasAsignados = "
            SELECT 
                CAST(23 * (PC_HOR / 40.0) * 
                    CASE WHEN YEAR(PC_FINI) = YEAR(GETDATE()) 
                         THEN DATEDIFF(DAY, PC_FINI, DATEFROMPARTS(YEAR(GETDATE()), 12, 31)) / 365.0 
                         ELSE 1 END 
                AS DECIMAL(10, 2)) AS Dias_Asignados
            FROM LIST_PERSONAL_CONTRATO_ULTIMO
            WHERE PC_OPE = :usuario";
        
        $stmtAsignados = $this->db->prepare($queryDiasAsignados);
        $stmtAsignados->bindParam(':usuario', $data['usuario']);
        $stmtAsignados->execute();
        $diasAsignados = $stmtAsignados->fetch(PDO::FETCH_ASSOC);
        $diasAsignadosTotal = round(floatval($diasAsignados['Dias_Asignados'] ?? 0));

        $queryDiasDisfrutados = "
            SELECT SUM(COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS Dias_Disfrutados
            FROM VAC v
            LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
            WHERE p.PER_NUM = :usuario AND v.VAC_TIP = 1 AND YEAR(v.VAC_FFIN) = YEAR(GETDATE())";
        
        $stmtDisfrutados = $this->db->prepare($queryDiasDisfrutados);
        $stmtDisfrutados->bindParam(':usuario', $data['usuario']);
        $stmtDisfrutados->execute();
        $diasDisfrutados = $stmtDisfrutados->fetch(PDO::FETCH_ASSOC);
        $diasDisfrutadosTotal = round(floatval($diasDisfrutados['Dias_Disfrutados'] ?? 0));

        $diasRestantes = $diasAsignadosTotal - $diasDisfrutadosTotal;
        $diasSolicitados = $fechaFin->diff($fechaInicio)->days + 1;
        if ($diasSolicitados > $diasRestantes) {
            return Response::json(['success' => false, 'message' => 'No tienes suficientes días de vacaciones disponibles.'], 400);
        }
    }

    // Calcular días laborales excluyendo fines de semana y festivos
    $queryCentroTrabajo = "SELECT PER_CTR FROM PER WHERE PER_NUM = :usuario";
    $stmtCentroTrabajo = $this->db->prepare($queryCentroTrabajo);
    $stmtCentroTrabajo->bindParam(':usuario', $data['usuario']);
    $stmtCentroTrabajo->execute();
    $centroTrabajo = $stmtCentroTrabajo->fetch(PDO::FETCH_ASSOC)['PER_CTR'];

    $queryFestivos = "
        SELECT CONVERT(VARCHAR, CL_FEC, 23) AS Dia_Festivo
        FROM CAL_LAB 
        WHERE YEAR(CL_FEC) = :year
        AND CL_FES = 1
        AND (CL_CTR IS NULL OR CL_CTR = :centroTrabajo)";
    $stmtFestivos = $this->db->prepare($queryFestivos);
    $stmtFestivos->bindParam(':year', $currentYear);
    $stmtFestivos->bindParam(':centroTrabajo', $centroTrabajo);
    $stmtFestivos->execute();
    $festivos = $stmtFestivos->fetchAll(PDO::FETCH_COLUMN);


    // Calcular días naturales y laborables
    $diasNaturales = $fechaFin->diff($fechaInicio)->days + 1;
    $diasLaborables = 0;
    $diasLaborables = 0;
    $fechaActual = clone $fechaInicio;
    while ($fechaActual <= $fechaFin) {
        if ($fechaActual->format('N') < 6 && !in_array($fechaActual->format('Y-m-d'), $festivos)) {
            $diasLaborables++;
        }
        $fechaActual->modify('+1 day');
    }

    // Procesar la solicitud e inserción de licencia
    try {
        $query = "SELECT MAX(VAC_ID) AS last_id FROM VAC";
        $stmt = $this->db->prepare($query);
        $stmt->execute();
        $lastId = $stmt->fetch(PDO::FETCH_ASSOC)['last_id'];
        $lastFiveDigits = (int)substr($lastId, -5);
        $newFiveDigits = str_pad($lastFiveDigits + 1, 5, '0', STR_PAD_LEFT);
        $newId = date('Y') . $newFiveDigits;

        if ($data['tipo_jornada'] === 'parcial') {
            $fechaPeticionFormatted = date('Y-m-d H:i:s'); // Inicialización de $fechaPeticionFormatted
            $query = "
                INSERT INTO VAC (VAC_ID, VAC_OPE, VAC_TIP, VAC_FINI, VAC_FFIN, VAC_DIAS, VAC_LAB, VAC_FSOL, VAC_OBS, VAC_USU, VAC_HOR, VAC_HFEC)
                VALUES (:newId, :usuario, :tipo_licencia, CONVERT(DATETIME, :fecha_inicio, 120), CONVERT(DATETIME, :fecha_fin, 120), 0, 0, GETDATE(), :observaciones, 1, :horas, CONVERT(DATETIME, :hora_fecha, 120))
            ";
            $stmt = $this->db->prepare($query);
            $stmt->bindParam(':newId', $newId);
            $stmt->bindParam(':usuario', $data['usuario']);
            $stmt->bindParam(':tipo_licencia', $data['tipo_licencia']);
            $stmt->bindParam(':fecha_inicio', $fechaInicioFormatted);
            $stmt->bindParam(':fecha_fin', $fechaFinFormatted);
            $stmt->bindParam(':observaciones', $data['observaciones']);
            $stmt->bindParam(':horas', $data['horas_solicitadas']);
            $stmt->bindParam(':hora_fecha', $fechaPeticionFormatted);

        } else {
            $query = "
                INSERT INTO VAC (VAC_ID, VAC_OPE, VAC_TIP, VAC_FINI, VAC_FFIN, VAC_DIAS, VAC_LAB, VAC_FSOL, VAC_OBS, VAC_USU)
                VALUES (:newId, :usuario, :tipo_licencia, CONVERT(DATETIME, :fecha_inicio, 120), CONVERT(DATETIME, :fecha_fin, 120), :dias_naturales, :dias_laborables, GETDATE(), :observaciones, 1)
            ";
            $stmt = $this->db->prepare($query);
            $stmt->bindParam(':newId', $newId);
            $stmt->bindParam(':usuario', $data['usuario']);
            $stmt->bindParam(':tipo_licencia', $data['tipo_licencia']);
            $stmt->bindParam(':fecha_inicio', $fechaInicioFormatted);
            $stmt->bindParam(':fecha_fin', $fechaFinFormatted);
            $stmt->bindParam(':dias_naturales', $diasNaturales);
            $stmt->bindParam(':dias_laborables', $diasLaborables);
            $stmt->bindParam(':observaciones', $data['observaciones']);
        }

        $stmt->execute();
        return Response::json(['success' => true, 'message' => 'Licencia guardada con éxito.'], 200);
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}



public function comprobarVacacionesPorFecha($data) {
    // Validación del token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validación de los datos de entrada
    if (!isset($data['usuario']) || !isset($data['fecha_inicio']) || !isset($data['fecha_fin'])) {
        return Response::json(['success' => false, 'message' => 'Datos incompletos.'], 400);
    }

    $fechaInicio = new DateTime($data['fecha_inicio']);
    $fechaFin = new DateTime($data['fecha_fin']);
    $fechaInicioFormatted = $fechaInicio->format('Y-m-d H:i:s');
    $fechaFinFormatted = $fechaFin->format('Y-m-d H:i:s');

    try {
        // Comprobar si ya existe un registro en el rango de fechas
        $queryCheck = "
            SELECT COUNT(*) AS total 
            FROM VAC
            WHERE VAC_OPE = :usuario 
            AND (
                CONVERT(DATETIME, VAC_FINI, 120) <= CONVERT(DATETIME, :fecha_fin, 120) 
                AND CONVERT(DATETIME, VAC_FFIN, 120) >= CONVERT(DATETIME, :fecha_inicio, 120)
            )";
        $stmtCheck = $this->db->prepare($queryCheck);
        $stmtCheck->bindParam(':usuario', $data['usuario']);
        $stmtCheck->bindParam(':fecha_inicio', $fechaInicioFormatted);
        $stmtCheck->bindParam(':fecha_fin', $fechaFinFormatted);
        $stmtCheck->execute();
        $checkResult = $stmtCheck->fetch(PDO::FETCH_ASSOC);

        if ($checkResult['total'] > 0) {
            return Response::json(['success' => false, 'message' => 'Ya existe un registro para ese rango de fechas.'], 400);
        } else {
            return Response::json(['success' => true, 'message' => 'No existen registros en este rango de fechas.'], 200);
        }
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}






    //Metodos Administrador
    public function listUsers($data)
{
     $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token esperado

    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Obtener todos los usuarios de la tabla PER
    $query = "SELECT * FROM PER WHERE PER_EST = 1";
    $stmt = $this->db->prepare($query);
    $stmt->execute();

    $users = $stmt->fetchAll(PDO::FETCH_ASSOC);

    if ($users) {
        return Response::json(['success' => true, 'data' => $users], 200);
    } else {
        return Response::json(['success' => false, 'message' => 'No se encontraron usuarios'], 404);
    }
}


public function getUsuariosGrupo($data)
{
    $tokenEsperado = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';

    if (!isset($data['token']) || $data['token'] !== $tokenEsperado) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    if (empty($data['grupo_id'])) {
        return Response::json(['success' => false, 'message' => 'Falta grupo_id'], 400);
    }

    try {
        $grupoId = intval($data['grupo_id']);

        $query = "SELECT PER_NUM, PER_NOM, PER_APE, PER_PAR_HAB FROM PER WHERE PER_EST = 1 AND PER_PAR_HAB = :grupo_id";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':grupo_id', $grupoId, PDO::PARAM_INT);
        $stmt->execute();

        $usuarios = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if ($usuarios) {
            return Response::json(['success' => true, 'usuarios' => $usuarios], 200);
        } else {
            return Response::json(['success' => false, 'message' => 'No se encontraron usuarios en el grupo'], 404);
        }

    } catch (\Exception $e) {
        return Response::json(['success' => false, 'message' => 'Error interno: ' . $e->getMessage()], 500);
    }
}



public function getUserByPerNum($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validación de entrada
    if (!isset($data['per_num'])) {
        return Response::json(['success' => false, 'message' => 'PER_NUM no especificado'], 400);
    }

    if (!is_numeric($data['per_num'])) {
        return Response::json(['success' => false, 'message' => 'Formato de PER_NUM incorrecto'], 400);
    }

    // Declaración preparada para evitar inyecciones SQL
    $query = "SELECT * FROM PER WHERE PER_NUM = :per_num";
    $stmt = $this->db->prepare($query);
    $stmt->bindParam(':per_num', $data['per_num'], PDO::PARAM_INT);
    $stmt->execute();

    $user = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($user) {
        // Si se encuentra el usuario, devolver los datos
        return Response::json(['success' => true, 'data' => $user], 200);
    } else {
        // Si el usuario no se encuentra
        return Response::json(['success' => false, 'message' => 'Usuario no encontrado'], 404);
    }
}

public function getUserByPerCodGes($data) {
    // Validar token
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if ($data['token'] !== $token) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validar entrada
    if (!isset($data['per_cod_ges'])) {
        return Response::json(['success' => false, 'message' => 'PER_COD_GES no especificado'], 400);
    }

    if (!is_numeric($data['per_cod_ges'])) {
        return Response::json(['success' => false, 'message' => 'Formato de PER_COD_GES incorrecto'], 400);
    }

    // Consulta a la base de datos
    $query = "SELECT * FROM PER WHERE PER_COD_GES = :per_cod_ges";
    $stmt = $this->db->prepare($query);
    $stmt->bindParam(':per_cod_ges', $data['per_cod_ges'], PDO::PARAM_INT);
    $stmt->execute();

    $user = $stmt->fetch(PDO::FETCH_ASSOC);

    if ($user) {
        return Response::json(['success' => true, 'data' => $user], 200);
    } else {
        return Response::json(['success' => false, 'message' => 'Usuario no encontrado'], 404);
    }
}




public function getRequestedVacationsPerNum($data)
{
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if (($data['token'] ?? '') !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']); exit;
    }
    if (!isset($data['usuario']) || !is_string($data['usuario'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']); exit;
    }

    $query = "
    WITH Base AS (
        SELECT
            sv.SV_ID,
            sv.SV_OPE,
            sv.SV_EST,
            CAST(sv.SV_FINI AS date) AS SV_FINI,
            CAST(sv.SV_FFIN AS date) AS SV_FFIN,
            CAST(sv.SV_HFEC AS date) AS SV_HFEC,
            COALESCE(sv.SV_LAB, 0.0) AS SV_LAB,
            COALESCE(sv.SV_HOR, 0.0) AS SV_HOR,
            CASE 
                WHEN CAST(sv.SV_FINI AS date) = DATEFROMPARTS(1900,1,1) THEN CAST(sv.SV_HFEC AS date)
                ELSE CAST(sv.SV_FINI AS date)
            END AS FechaInicioNorm,
            CASE 
                WHEN CAST(sv.SV_FFIN AS date) = DATEFROMPARTS(1900,1,1) THEN CAST(sv.SV_HFEC AS date)
                ELSE CAST(sv.SV_FFIN AS date)
            END AS FechaFinNorm
        FROM SOL_VAC sv
        JOIN PER p ON sv.SV_OPE = p.PER_NUM
        WHERE p.PER_NUM = :usuario
          AND sv.SV_EST IN (1,4)  -- 1=pendiente, 4=web pendiente (ajusta según tus estados)
    )
    SELECT
        b.SV_ID            AS VAC_ID,
        b.SV_OPE           AS VAC_OPE,
        b.FechaInicioNorm  AS VAC_FINI,
        b.FechaFinNorm     AS VAC_FFIN,
        CAST(
            CASE 
              WHEN b.SV_FINI = DATEFROMPARTS(1900,1,1)
                THEN b.SV_HOR / CASE WHEN MONTH(b.FechaInicioNorm) IN (7,8) THEN 7.0 ELSE 8.0 END
              ELSE b.SV_LAB
            END
        AS DECIMAL(10,2))   AS Dias_Solicitados,
        CAST(b.SV_HOR AS DECIMAL(10,2)) AS Horas_Solicitadas,
        est.SVE_DES         AS Estado
    FROM Base b
    JOIN SOL_VAC_EST est ON b.SV_EST = est.SVE_ID
    WHERE YEAR(b.FechaInicioNorm) IN (YEAR(GETDATE()), YEAR(GETDATE())+1)
    ORDER BY b.FechaInicioNorm DESC;
    ";

    try {
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':usuario', $data['usuario']);
        $stmt->execute();
        $vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);

        header('Content-Type: application/json');
        echo json_encode(['success' => true, 'data' => $vacations]);
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}




public function getConfirmedVacationsPerNum($data) {
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    header('Content-Type: application/json');

    if (!isset($data['token']) || $data['token'] !== $token) {
        echo json_encode(['success' => false, 'message' => 'Token inválido']); return;
    }
    if (!isset($data['usuario']) || !is_string($data['usuario'])) {
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado o formato incorrecto']); return;
    }

    $queryVacations = "
;WITH Q AS (
    SELECT
        p.PER_CTR,
        v.VAC_ID,
        v.VAC_OPE,
        v.VAC_FSOL,
        v.VAC_FINI,
        v.VAC_FFIN,
        v.VAC_HFEC,
        COALESCE(v.VAC_LAB,0.0) AS VAC_LAB,
        COALESCE(v.VAC_HOR,0.0) AS VAC_HOR,
        CASE
            WHEN COALESCE(v.VAC_HOR,0) > 0 AND v.VAC_HFEC IS NOT NULL
                 THEN CAST(v.VAC_HFEC AS date)
            ELSE CAST(v.VAC_FINI AS date)
        END AS FechaReal
    FROM VAC v
    LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
    WHERE p.PER_NUM = :usuario
      AND v.VAC_TIP IN (1,3)
      AND (COALESCE(v.VAC_LAB,0) > 0 OR COALESCE(v.VAC_HOR,0) > 0)
),
/* Horas/día según el contrato vigente en la FechaReal (si no, 8.0) */
QH AS (
    SELECT
        Q.*,
        COALESCE(NULLIF(ch.HorasDia,0), 8.0) AS HorasDiaBase
    FROM Q
    OUTER APPLY (
        SELECT TOP (1)
               CAST(NULLIF(c.[Nº Horas],0)/5.0 AS DECIMAL(18,6)) AS HorasDia
        FROM LIST_PERSONAL_CONTRATOS c
        WHERE c.Operario = Q.VAC_OPE
          AND Q.FechaReal >= CAST(c.[Fecha Ini] AS date)
          AND (c.[Fecha Fin] IS NULL OR Q.FechaReal < DATEADD(day,1, CAST(c.[Fecha Fin] AS date)))
        ORDER BY c.[Fecha Ini] DESC
    ) ch
),
/* Días enteros = VAC_LAB; horas→días: jul/ago=7.0, resto=HorasDiaBase */
Conv AS (
    SELECT
        QH.*,
        CAST(QH.VAC_LAB AS DECIMAL(18,6)) AS DiasEnteros,
        CAST(
          CASE WHEN QH.VAC_HOR > 0
               THEN QH.VAC_HOR / (CASE WHEN MONTH(QH.FechaReal) IN (7,8) THEN 7.0 ELSE QH.HorasDiaBase END)
               ELSE 0.0
          END AS DECIMAL(18,6)
        ) AS DiasEqHoras
    FROM QH
),
G AS (
    SELECT
        PER_CTR,
        VAC_ID,
        VAC_OPE,
        MIN(VAC_FSOL) AS Fecha_Sol,
        MIN(FechaReal) AS Fecha_Inicio,
        MAX(COALESCE(VAC_FFIN, FechaReal)) AS Fecha_Fin,
        CAST(SUM(DiasEnteros)   AS DECIMAL(18,6)) AS Dias_Laborables,
        CAST(SUM(VAC_HOR)       AS DECIMAL(18,6)) AS Horas,
        CAST(SUM(DiasEqHoras)   AS DECIMAL(18,6)) AS Horas_Convertidas,
        CAST(SUM(DiasEnteros + DiasEqHoras) AS DECIMAL(18,6)) AS Total_Dias_Disfrutados,
        CASE WHEN MAX(COALESCE(VAC_HFEC, VAC_FFIN)) < GETDATE()
             THEN 'Disfrutadas' ELSE 'Confirmadas (Pendientes)' END AS Estado,
        YEAR(COALESCE(MIN(VAC_FSOL), MIN(FechaReal))) AS Anio_Sol
    FROM Conv
    GROUP BY PER_CTR, VAC_ID, VAC_OPE
)
SELECT
    G.*,
    CAST(SUM(G.Total_Dias_Disfrutados) OVER (PARTITION BY G.Anio_Sol) AS DECIMAL(18,6)) AS Total_Dias_Disfrutados_Anio,
    CAST(SUM(G.Total_Dias_Disfrutados) OVER ()                    AS DECIMAL(18,6)) AS Total_Dias_Disfrutados_Usuario
FROM G
ORDER BY G.Fecha_Inicio DESC;
";

    // Años para el selector (por FSOL con fallback)
    $queryYears = "
        SELECT DISTINCT YEAR(COALESCE(v.VAC_FSOL, v.VAC_FINI, v.VAC_HFEC)) AS Year
        FROM VAC v
        LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
        WHERE p.PER_NUM = :usuario
          AND v.VAC_TIP IN (1,3)
          AND (COALESCE(v.VAC_LAB,0) > 0 OR COALESCE(v.VAC_HOR,0) > 0)
        ORDER BY Year DESC;
    ";

    try {
        $stmtVacations = $this->db->prepare($queryVacations);
        $stmtVacations->bindParam(':usuario', $data['usuario']);
        $stmtVacations->execute();
        $vacations = $stmtVacations->fetchAll(PDO::FETCH_ASSOC);

        // Redondeo de presentación
        foreach ($vacations as &$r) {
            foreach (['Dias_Laborables','Horas','Horas_Convertidas','Total_Dias_Disfrutados','Total_Dias_Disfrutados_Anio','Total_Dias_Disfrutados_Usuario'] as $k) {
                if (isset($r[$k])) $r[$k] = (float)round($r[$k], 6);
            }
        }

        $stmtYears = $this->db->prepare($queryYears);
        $stmtYears->bindParam(':usuario', $data['usuario']);
        $stmtYears->execute();
        $years = $stmtYears->fetchAll(PDO::FETCH_COLUMN);

        echo json_encode([
            'success' => true,
            'data' => [
                'vacations' => $vacations,
                'years'     => $years
            ]
        ]);
    } catch (PDOException $e) {
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}




    public function getUserByAdmin($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        return response()->json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validación de entrada
    if (!isset($data['per_num'])) {
        return response()->json(['success' => false, 'message' => 'PER_NUM no especificado'], 400);
    }

    if (!is_numeric($data['per_num'])) {
        return response()->json(['success' => false, 'message' => 'Formato de PER_NUM incorrecto'], 400);
    }

    try {
        // Declaración preparada para evitar inyecciones SQL
        $query = "SELECT PER_ADM_WEB FROM PER WHERE PER_NUM = :per_num";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':per_num', $data['per_num'], PDO::PARAM_INT);
        $stmt->execute();

        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            // Si se encuentra el usuario, devolver los datos
            return response()->json(['success' => true, 'data' => $user], 200);
        } else {
            // Si el usuario no se encuentra
            return response()->json(['success' => false, 'message' => 'Usuario no encontrado'], 404);
        }
    } catch (PDOException $e) {
        // Manejo de errores en la consulta SQL
        return response()->json(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()], 500);
    }
}




public function getOperarioDatosConversacion($data) {
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if ($data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    if (!isset($data['per_num'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'PER_NUM no especificado']);
        exit;
    }

    if (!is_numeric($data['per_num'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Formato de PER_NUM incorrecto']);
        exit;
    }

    try {
        $query = "SELECT * FROM PER WHERE PER_NUM = :per_num";
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':per_num', $data['per_num'], PDO::PARAM_INT);
        $stmt->execute();

        $user = $stmt->fetch(PDO::FETCH_ASSOC);

        if ($user) {
            header('Content-Type: application/json');
            echo json_encode(['success' => true, 'data' => $user]);
            exit;
        } else {
            header('Content-Type: application/json');
            echo json_encode(['success' => false, 'message' => 'Usuario no encontrado']);
            exit;
        }
    } catch (PDOException $e) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
        exit;
    }
}



    

    public function getConfirmedLicensAdmin($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Validación de entrada
    if (!isset($data['per_num'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Usuario no especificado']);
        exit;
    }

    if (!is_string($data['per_num'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Formato de usuario incorrecto']);
        exit;
    }

    // Consulta principal para obtener las licencias confirmadas
    $queryLicenses = "
        SELECT
            p.PER_CTR,
            v.VAC_ID,
            v.VAC_OBS,
            v.VAC_TIP,
            vt.VT_NOM AS Tipo_Licencia,
            v.VAC_OPE,
            CASE
                WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC
                ELSE v.VAC_FINI
            END AS Fecha_Inicio,
            CASE
                WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC
                ELSE v.VAC_FFIN
            END AS Fecha_Fin,
            (COALESCE(v.VAC_LAB, 0) + COALESCE(v.VAC_HOR, 0) / 8.0) AS Días_Laborables
        FROM
            VAC v
        LEFT JOIN
            PER p ON v.VAC_OPE = p.PER_NUM
        LEFT JOIN
            VAC_TIP vt ON v.VAC_TIP = vt.VT_ID
        WHERE
            p.PER_NUM = :per_num
            AND v.VAC_TIP <> 1  -- Excluir las licencias de vacaciones (VAC_TIP 1)
        ORDER BY 
            Fecha_Inicio DESC
    ";

    // Consulta para obtener los años únicos de las fechas de inicio de licencias confirmadas
    $queryYears = "
        SELECT DISTINCT YEAR(
            CASE
                WHEN v.VAC_HOR > 0 THEN v.VAC_HFEC
                ELSE v.VAC_FINI
            END
        ) AS Year
        FROM VAC v
        LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
        WHERE p.PER_NUM = :per_num
        AND v.VAC_TIP <> 1  -- Excluir las licencias de vacaciones
        ORDER BY Year DESC
    ";

    try {
        // Ejecutar la consulta de licencias confirmadas
        $stmtLicenses = $this->db->prepare($queryLicenses);
        $stmtLicenses->bindParam(':per_num', $data['per_num']);
        $stmtLicenses->execute();
        $licenses = $stmtLicenses->fetchAll(PDO::FETCH_ASSOC);

        // Ejecutar la consulta de años únicos
        $stmtYears = $this->db->prepare($queryYears);
        $stmtYears->bindParam(':per_num', $data['per_num']);
        $stmtYears->execute();
        $years = $stmtYears->fetchAll(PDO::FETCH_COLUMN);

        // Devolver los resultados como JSON
        header('Content-Type: application/json');
        echo json_encode([
            'success' => true,
            'data' => [
                'licenses' => $licenses,
                'years' => $years
            ]
        ]);
    } catch (PDOException $e) {
        // Manejar errores y devolver mensaje de error en JSON
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}


public function deleteLicense($data) {
    // Validación del token de autenticación
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';  // Token API esperado
    if ($data['token'] !== $token) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Token inválido']);
        exit;
    }

    // Validación de entrada: verificar que se haya proporcionado un ID de licencia
    if (!isset($data['id'])) {
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'ID de licencia no especificado']);
        exit;
    }

    $idLicencia = $data['id'];

    // Consulta SQL para eliminar la licencia
    $query = "
        DELETE FROM VAC
        WHERE VAC_ID = :id
    ";

    try {
        // Preparar y ejecutar la consulta
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':id', $idLicencia, PDO::PARAM_STR);
        $stmt->execute();

        // Verificar si se eliminó alguna fila
        if ($stmt->rowCount() > 0) {
            header('Content-Type: application/json');
            echo json_encode(['success' => true, 'message' => 'Licencia eliminada con éxito']);
        } else {
            // Si no se eliminó ninguna fila, es posible que el ID no exista
            header('Content-Type: application/json');
            echo json_encode(['success' => false, 'message' => 'Licencia no encontrada']);
        }
    } catch (PDOException $e) {
        // Manejar errores de base de datos
        header('Content-Type: application/json');
        echo json_encode(['success' => false, 'message' => 'Error al eliminar la licencia: ' . $e->getMessage()]);
    }
}


public function getHorasComplementarias($data)
{
    $expectedToken = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if (!isset($data['token']) || $data['token'] !== $expectedToken) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    if (!isset($data['per_num']) || empty($data['per_num']) ||
        !isset($data['año']) || empty($data['año']) ||
        !isset($data['mes']) || empty($data['mes'])) {
        return Response::json(['success' => false, 'message' => 'Faltan parámetros obligatorios.'], 400);
    }

    $per_num = (int) $data['per_num'];
    $año = (int) $data['año'];
    $mes = (int) $data['mes'];

$query = "
    SELECT 
        CONVERT(VARCHAR, PAR_FEC, 23) AS PAR_FEC,  -- Fecha
        COALESCE(CAST(SUM(PD_NOR) AS FLOAT), 0) AS HNOR,
        COALESCE(CAST(SUM(PD_EXT) AS FLOAT), 0) AS HEXT, 
        -- Equivalencia: si mes = 7 u 8 → factor 1.0, resto → factor 1.5
        COALESCE(CAST(SUM(
            CASE 
                WHEN MONTH(PAR_FEC) IN (7,8) THEN PD_EXT * 1.0
                ELSE PD_EXT * 1.5
            END
        ) AS FLOAT), 0) AS HEXT_EQUIV,
        COALESCE(CAST(SUM(PD_FES) AS FLOAT), 0) AS HFES, 
        COALESCE(CAST(SUM(PD_NOC) AS FLOAT), 0) AS HNOC, 
        COALESCE(CAST(SUM(PD_SAB) AS FLOAT), 0) AS HSAB,
        CASE 
            WHEN ISNULL(PAR_REV_EXT, 0) = 1 THEN 'Sí'
            ELSE 'No'
        END AS Revisadas
    FROM PAR 
    INNER JOIN PAR_DET ON PAR_ID = PD_PAR 
    WHERE YEAR(PAR_FEC) = :anio 
      AND MONTH(PAR_FEC) = :mes	  
      AND PD_OPE = :per_num
    GROUP BY 
        PAR_FEC, 
        CASE 
            WHEN ISNULL(PAR_REV_EXT, 0) = 1 THEN 'Sí'
            ELSE 'No'
        END
    ORDER BY PAR_FEC;
";





    try {
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':anio', $año, PDO::PARAM_INT);
        $stmt->bindParam(':mes', $mes, PDO::PARAM_INT);
        $stmt->bindParam(':per_num', $per_num, PDO::PARAM_INT);
        $stmt->execute();
        
        $horas = $stmt->fetchAll(PDO::FETCH_ASSOC);
if (!$horas) {
    return Response::json(['success' => true, 'data' => []], 200);
}

        return Response::json(['success' => true, 'data' => $horas], 200);
    } catch (PDOException $e) {
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}







 public function getLicenseDetails($data)
{
    // Validar el token de autenticación
    $expectedToken = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if ($data['token'] !== $expectedToken) {
        return Response::json(['success' => false, 'message' => 'Token inválido'], 403);
    }

    // Validar el ID de licencia
    if (!isset($data['id']) || empty($data['id'])) {
        return Response::json(['success' => false, 'message' => 'ID de licencia no proporcionado.'], 400);
    }

    // Preparar la consulta para obtener los detalles de la licencia
    $query = "
        SELECT 
            v.VAC_ID,
            v.VAC_OPE AS usuario_id,
            v.VAC_TIP AS tipo_licencia,
            v.VAC_FINI AS fecha_inicio,
            v.VAC_FFIN AS fecha_fin,
            v.VAC_OBS,
            p.PER_NUM,
            p.PER_NOM,
            p.PER_APE,
            p.PER_DNI
        FROM VAC v
        LEFT JOIN PER p ON v.VAC_OPE = p.PER_NUM
        WHERE v.VAC_ID = :id
    ";

    try {
        // Ejecutar la consulta
        $stmt = $this->db->prepare($query);
        $stmt->bindParam(':id', $data['id'], PDO::PARAM_INT);
        $stmt->execute();
        $licenseDetails = $stmt->fetch(PDO::FETCH_ASSOC);

        // Verificar si se encontró la licencia
        if (!$licenseDetails) {
            return Response::json(['success' => false, 'message' => 'Licencia no encontrada.'], 404);
        }

        // Formatear los datos antes de devolverlos
        $formattedData = [
            'VAC_ID' => $licenseDetails['VAC_ID'],
            'usuario' => [
                'PER_NUM' => $licenseDetails['PER_NUM'],
                'PER_NOM' => $licenseDetails['PER_NOM'],
                'PER_APE' => $licenseDetails['PER_APE'],
                'PER_DNI' => $licenseDetails['PER_DNI'],
            ],
            'tipo_licencia' => $licenseDetails['tipo_licencia'],
            'fecha_inicio' => $licenseDetails['fecha_inicio'],
            'fecha_fin' => $licenseDetails['fecha_fin'],
            'VAC_OBS' => $licenseDetails['VAC_OBS']
        ];

        return Response::json(['success' => true, 'data' => $formattedData], 200);
    } catch (PDOException $e) {
        // Manejar el error de la base de datos
        return Response::json(['success' => false, 'message' => 'Error en la base de datos: ' . $e->getMessage()], 500);
    }
}



public function getVacationSummaryAdmin($data) {
    // --- Auth ---
    $token = 'dc7b1f0bdfb29e1c42a067c11998096e908a64450fcd32d120eb8f2fc9272313';
    if (($data['token'] ?? '') !== $token) {
        return json_encode(['success' => false, 'message' => 'Token inválido']);
    }

    // --- Validación ---
    if (empty($data['per_num']) || !is_string($data['per_num']) ||
        !isset($data['year']) || !is_numeric($data['year'])) {
        return json_encode(['success' => false, 'message' => 'Usuario o año no especificado o formato incorrecto']);
    }

    $per      = $data['per_num'];
    $year     = (int)$data['year'];
    $nextYear = $year + 1;

    try {
        /* ====================== 1) DÍAS ASIGNADOS ====================== */
    $queryDiasAsignados = "
WITH Contracts AS (
  SELECT
    [Operario]                AS PC_OPE,
    CAST([Fecha Ini] AS date) AS PC_FINI,
    CAST([Fecha Fin] AS date) AS PC_FFIN,
    LTRIM(RTRIM(UPPER(COALESCE([Tipo],N'')))) AS PC_TIPO
  FROM [LIST_PERSONAL_CONTRATOS]
  WHERE [Operario] = :usuario
),
Bounds AS (
  SELECT
    DATEFROMPARTS(YEAR(GETDATE()),1,1)  AS YStart,
    DATEFROMPARTS(YEAR(GETDATE()),12,31) AS YEnd
),
InYear AS (             -- contratos que tocan el año
  SELECT c.*, b.YStart, b.YEnd
  FROM Contracts c
  CROSS JOIN Bounds b
  WHERE (c.PC_FINI IS NULL OR c.PC_FINI <= b.YEnd)
    AND (c.PC_FFIN IS NULL OR c.PC_FFIN >= b.YStart)
),
Effective AS (          -- recorte al año
  SELECT
    LTRIM(RTRIM(UPPER(PC_TIPO))) AS PC_TIPO,
    CASE WHEN PC_FINI IS NULL OR PC_FINI < YStart THEN YStart ELSE PC_FINI END AS EffectiveStart,
    CASE WHEN PC_FFIN IS NULL OR PC_FFIN > YEnd   THEN YEnd   ELSE PC_FFIN END AS EffectiveEnd
  FROM InYear
),
NonBeca AS (            -- solo NO BECARIO y rangos válidos
  SELECT *
  FROM Effective
  WHERE PC_TIPO <> N'BECARIO'
    AND EffectiveEnd >= EffectiveStart
),
Meses AS (              -- meses devengo por cada tramo
  SELECT
    CASE
      WHEN DAY(EffectiveEnd) >= DAY(EffectiveStart)
        THEN DATEDIFF(MONTH, EffectiveStart, EffectiveEnd) + 1
      ELSE DATEDIFF(MONTH, EffectiveStart, EffectiveEnd)
    END AS MesesDevengo
  FROM NonBeca
)
SELECT CAST(
  (23.0/12.0) * COALESCE((SELECT SUM(MesesDevengo) FROM Meses), 0)
AS DECIMAL(10,2)) AS Dias_Asignados;

";
        $stmtAsignados = $this->db->prepare($queryDiasAsignados);
        $stmtAsignados->bindParam(':per_num', $per);
        $stmtAsignados->bindParam(':year', $year, PDO::PARAM_INT);
        $stmtAsignados->execute();
        $diasAsignados = $stmtAsignados->fetch(PDO::FETCH_ASSOC) ?: ['Dias_Asignados' => 0];

        /* ====================== 2) DÍAS DISFRUTADOS ====================== */
        // MISMA lógica que usuario: contrato que cubre la fecha; fin NULL también cubre.
        $queryDiasDisfrutados = "
;WITH Q AS (
    SELECT
        v.VAC_ID, v.VAC_OPE, v.VAC_FSOL, v.VAC_FINI, v.VAC_FFIN, v.VAC_HFEC,
        COALESCE(v.VAC_LAB,0.0) AS VAC_LAB,
        COALESCE(v.VAC_HOR,0.0) AS VAC_HOR,
        CASE
            WHEN COALESCE(v.VAC_HOR,0) > 0 AND v.VAC_HFEC IS NOT NULL
                 THEN CAST(v.VAC_HFEC AS date)
            ELSE CAST(v.VAC_FINI AS date)
        END AS FechaReal
    FROM VAC v
    WHERE v.VAC_OPE = :per_num
      AND YEAR(v.VAC_FSOL) = :year
      AND v.VAC_TIP IN (1,3)
      AND (COALESCE(v.VAC_LAB,0) > 0 OR COALESCE(v.VAC_HOR,0) > 0)
),
QH AS (
    SELECT
        Q.*,
        COALESCE(NULLIF(ch.HorasDia,0), 8.0) AS HorasDiaBase
    FROM Q
    OUTER APPLY (
        SELECT TOP (1)
               CAST(NULLIF(c.[Nº Horas],0)/5.0 AS DECIMAL(18,6)) AS HorasDia
        FROM LIST_PERSONAL_CONTRATOS c
        WHERE c.Operario = Q.VAC_OPE
          AND Q.FechaReal >= CAST(c.[Fecha Ini] AS date)
          AND (c.[Fecha Fin] IS NULL OR Q.FechaReal < DATEADD(day,1, CAST(c.[Fecha Fin] AS date)))
        ORDER BY c.[Fecha Ini] DESC
    ) ch
),
Conv AS (
    SELECT
        QH.VAC_LAB,
        CASE
            WHEN QH.VAC_HOR > 0 THEN
               QH.VAC_HOR /
               (CASE
                   WHEN MONTH(QH.FechaReal) IN (7,8) AND ABS(QH.HorasDiaBase-8.0) < 0.01
                        THEN 7.0
                   ELSE QH.HorasDiaBase
                END)
            ELSE 0.0
        END AS DiasEqHoras
    FROM QH
)
SELECT
  CAST(
    ROUND(COALESCE(SUM(Conv.VAC_LAB),0) + COALESCE(SUM(Conv.DiasEqHoras),0), 2)
  AS DECIMAL(10,2)) AS Dias_Disfrutados;
";
        $stmtDisfrutados = $this->db->prepare($queryDiasDisfrutados);
        $stmtDisfrutados->bindParam(':per_num', $per);
        $stmtDisfrutados->bindParam(':year', $year, PDO::PARAM_INT);
        $stmtDisfrutados->execute();
        $diasDisfrutados = $stmtDisfrutados->fetch(PDO::FETCH_ASSOC) ?: ['Dias_Disfrutados' => 0];

        /* ====================== 3) DÍAS PENDIENTES ====================== */
        // (Admin mantenemos ventana hasta 15/01 y divisor genérico 7 en jul/ago, 8 resto)
        $queryDiasPendientes = "
WITH Base AS (
  SELECT
    COALESCE(sv.SV_LAB,0) AS SV_LAB,
    COALESCE(sv.SV_HOR,0) AS SV_HOR,
    CAST(CASE WHEN CONVERT(date, sv.SV_FINI) = '1900-01-01' THEN sv.SV_HFEC ELSE sv.SV_FINI END AS date) AS FechaIni,
    CAST(CASE WHEN CONVERT(date, sv.SV_FFIN) = '1900-01-01' THEN sv.SV_HFEC ELSE sv.SV_FFIN END AS date) AS FechaFin
  FROM SOL_VAC sv
  LEFT JOIN PER p ON sv.SV_OPE = p.PER_NUM
  WHERE p.PER_NUM = :per_num
    AND sv.SV_EST IN (1,4)
)
SELECT CAST(
  COALESCE(SUM(
    SV_LAB +
    CASE WHEN SV_HOR > 0
         THEN SV_HOR / (CASE WHEN MONTH(FechaIni) IN (7,8) THEN 7.0 ELSE 8.0 END)
         ELSE 0 END
  ),0)
AS DECIMAL(10,2)) AS Dias_Pendientes
FROM Base
WHERE FechaFin >= DATEFROMPARTS(:year, 1, 1)
  AND FechaFin <= DATEFROMPARTS(:next_year, 1, 15);
";
        $stmtPendientes = $this->db->prepare($queryDiasPendientes);
        $stmtPendientes->bindParam(':per_num', $per);
        $stmtPendientes->bindParam(':year', $year, PDO::PARAM_INT);
        $stmtPendientes->bindParam(':next_year', $nextYear, PDO::PARAM_INT);
        $stmtPendientes->execute();
        $diasPendientes = $stmtPendientes->fetch(PDO::FETCH_ASSOC) ?: ['Dias_Pendientes' => 0];

        /* ====================== 4) Totales & salida ====================== */
        $asig  = (float)($diasAsignados['Dias_Asignados']   ?? 0);
        $disfr = (float)($diasDisfrutados['Dias_Disfrutados'] ?? 0);
        $pend  = (float)($diasPendientes['Dias_Pendientes']  ?? 0);

        // reglas de redondeo para admin
        $asig  = $this->redondearDiasAdmin($asig);
        $disfr = round($disfr, 1);
        $pend  = round($pend, 1);
        $rest  = round($asig - $disfr - $pend, 1);

        return json_encode([
            'success' => true,
            'data' => [
                'Dias_Asignados'   => number_format($asig, 1),
                'Dias_Disfrutados' => number_format($disfr, 1),
                'Dias_Pendientes'  => number_format($pend, 1),
                'Dias_Restantes'   => number_format($rest, 1),
            ]
        ]);
    } catch (PDOException $e) {
        return json_encode(['success' => false, 'message' => 'Error en la consulta: ' . $e->getMessage()]);
    }
}




// Función para redondear los días asignados
private function redondearDiasAdmin($dias) {
    $parteEntera = floor($dias);
    $parteDecimal = $dias - $parteEntera;

    return ($parteDecimal >= 0.5) ? ceil($dias) : floor($dias);
}








}








 












