const bcrypt = require('bcryptjs');
const jwt = require('../services/jwt');
const Usuario = require('../models/usuario');
const Area = require('../models/area');
const Cargo = require('../models/cargo');
const Sistema = require('../models/sistema');
const Rol = require('../models/rol');
const fs = require('fs');
const { Op, where } = require("sequelize");
const Usuario_Rol = require('../models/usuario_rol');
const moment = require('moment-timezone');
const Canton = require('../models/canton');
const Provincia = require('../models/provincia');
const Capacitacion = require('../models/capacitacion');
const Estudio = require('../models/estudio');
const LlamadoAtencion = require('../models/llamado_atencion');
const Carga_Familiar = require('../models/carga_familiar');
const Historial_Empresa = require('../models/historial_empresa');
const Licencia = require('../models/licencia');
const Experiencia_Laboral = require('../models/experiencia_laboral');
const Idioma = require('../models/idioma');
const LiberacionHSE = require('../models/liberacionHSE');
const VacunaUsuario = require('../models/vacunaUsuario');
const TipoVacuna = require('../models/tipoVacuna');
const TipoCertificacionHabilitante = require('../models/tipoCertificacionHabilitante');
const UsuarioCertificacionHabilitante = require('../models/usuarioCertificacionHabilitante');
const EvaluacionDesempeno = require('../models/evaluacion_desempeno');
const path = require('path');
const toUpper = (val) => (typeof val === 'string' && val) ? val.toUpperCase().trim() : val;

const UPLOADS_FOTOS_DIR = path.join(__dirname, '../uploads/fotos');

const helperImg = (filePath, filename) => {
    return fs.promises.copyFile(filePath, path.join(UPLOADS_FOTOS_DIR, filename));
}

// Función para verificar y crear directorios si no existen
const verificarYCrearDirectorio = (ruta) => {
    if (!fs.existsSync(ruta)) {
        fs.mkdirSync(ruta, { recursive: true });
    }
}

// Función para verificar y crear TODAS las carpetas de uploads del sistema
const verificarTodasLasCarpetasUploads = () => {
    const carpetas = [
        './uploads',
        './uploads/fotos',
        './uploads/evidenciaPermisos',
        './uploads/CI',
        './uploads/cargasFamiliares',
        './uploads/contratos',
        './uploads/capacitaciones',
        './uploads/experienciaLaboral',
        './uploads/documentos',
        './uploads/hse',
        './uploads/HSE',
        './uploads/evaluaciones'
    ];

    carpetas.forEach(carpeta => {
        verificarYCrearDirectorio(carpeta);
    });
}

// Función para eliminar archivos de forma segura (verifica existencia antes de eliminar)
const eliminarArchivoSeguro = (ruta) => {
    if (ruta && fs.existsSync(ruta)) {
        fs.unlinkSync(ruta);
        return true;
    }
    return false;
}

// Función para calcular edad a partir de fecha de nacimiento
const calcularEdad = (fechaNacimiento) => {
    if (!fechaNacimiento) return null;

    const hoy = new Date();
    const nacimiento = new Date(fechaNacimiento);
    let edad = hoy.getFullYear() - nacimiento.getFullYear();
    const mes = hoy.getMonth() - nacimiento.getMonth();

    if (mes < 0 || (mes === 0 && hoy.getDate() < nacimiento.getDate())) {
        edad--;
    }

    return edad;
}

async function autenticarUsuario(req, res) {

    try {
        let params = req.body;
        console.log(params)
        const usuario = await Usuario.findOne({
            where: {
                ESTADO: 1,
                USUARIO: params.USUARIO
            },
            include: [
                {
                    model: Usuario_Rol,
                    as: 'USUARIO_ROL',
                    include: [
                        {
                            model: Rol
                        }
                    ]
                },
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false, // This ensures it doesn't filter out users without a history
                    where: {
                        ESTADO: true
                    },
                    include: [
                        {
                            model: Cargo,
                            include: [{ model: Area }]
                        }
                    ]
                }
            ]
        });
        if (!usuario) {
            res.status(402).send({ message: 'El Usuario no existe' });
        } else {
            if (params.getHash) {
                res.status(200).send({ token: jwt.createToken(usuario) });
            } else {
                let result = bcrypt.compareSync(params.CONTRASENIA, usuario.CONTRASENIA);
                if (result) {
                    res.status(200).send({
                        data: usuario
                    });
                } else {
                    res.status(402).send({ message: 'Error al ingresar, contraseña incorrecta.' });
                }

            }
        }
    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function obtenerAreas(req, res) {

    try {
        let areasObtenidas = await Area.findAll({ where: { ESTADO: 1 } });

        if (areasObtenidas.length > 0) {
            res.status(200).send({
                data: areasObtenidas,
                message: "Areas cargadas correctamente"
            });
        } else {
            res.status(402).send({
                message: 'No existen areas registradas en la base de datos'
            });
        }
    } catch (err) {
        res.status(500).send({
            message: 'error:' + err
        });
    }
}


async function obtenerCargos(req, res) {

    try {

        let cargosObtenidos = await Cargo.findAll({ where: { ESTADO: 1, ID_AREA: req.params.id } });

        if (cargosObtenidos.length > 0) {
            res.status(200).send({
                data: cargosObtenidos,
                message: "Cargos cargados correctamente"
            });
        } else {
            res.status(402).send({
                message: 'No existen cargos registrados en la base de datos'
            });
        }
    } catch (err) {
        res.status(500).send({
            message: 'error:' + err
        });
    }
}



async function obtenerSistemas(req, res) {

    try {
        let sistemasObtenidos = await Sistema.findAll({ where: { ESTADO: 1 } });

        if (sistemasObtenidos.length > 0) {
            res.status(200).send({
                data: sistemasObtenidos,
                message: "Sistemas cargados correctamente"
            });
        } else {
            res.status(402).send({
                message: 'No existen sistemas registrados en la base de datos'
            });
        }
    } catch (err) {
        res.status(500).send({
            message: 'error:' + err
        });
    }
}


async function obtenerRoles(req, res) {

    try {


        let rolesObtenidos = await Rol.findAll({ where: { ESTADO: 1, ID_SISTEMA: req.params.id } });

        if (rolesObtenidos.length > 0) {
            res.status(200).send({
                data: rolesObtenidos,
                message: "Roles cargados correctamente"
            });
        } else {
            res.status(402).send({
                message: 'No existen roles registrados en la base de datos'
            });
        }
    } catch (err) {
        console.log(err)
        res.status(500).send({
            message: 'error:' + err
        });
    }
}

async function registrarUsuario(req, res) {
    try {
        // Verificar y crear TODAS las carpetas de uploads
        verificarTodasLasCarpetasUploads();

        let usuarioEntrante = JSON.parse(req.body.usuario)
        usuarioEntrante.USUARIO = usuarioEntrante.USUARIO.trim()
        usuarioEntrante.CORREO = usuarioEntrante.CORREO.trim()
        if (usuarioEntrante.CORREO_EMPRESARIAL) {
            usuarioEntrante.CORREO_EMPRESARIAL = usuarioEntrante.CORREO_EMPRESARIAL.trim()
        }
        if (req.file) {
            await helperImg(req.file.path, `resize-${req.file.filename}`, 800, 1000);
            eliminarArchivoSeguro(req.file.path);
        }
        const estadoValido = { ESTADO: { [Op.in]: [0, 1] } };
        const identificacionBuscar = String(usuarioEntrante.IDENTIFICACION || '').trim().toUpperCase();
        const correoBuscar         = String(usuarioEntrante.CORREO || '').trim().toLowerCase();
        const usuarioBuscar        = String(usuarioEntrante.USUARIO || '').trim();
        let usuarioEncontrado  = await Usuario.findOne({ where: { IDENTIFICACION: identificacionBuscar, ...estadoValido } });
        let usuarioEncontrado2 = await Usuario.findOne({ where: { CORREO: correoBuscar, ...estadoValido } });
        let usuarioEncontrado3 = await Usuario.findOne({ where: { USUARIO: usuarioBuscar, ...estadoValido } });
        let usuarioEncontrado4 = null;
        if (usuarioEntrante.CORREO_EMPRESARIAL) {
            usuarioEncontrado4 = await Usuario.findOne({
                where: { CORREO_EMPRESARIAL: usuarioEntrante.CORREO_EMPRESARIAL, ...estadoValido }
            });
        }
        if (usuarioEncontrado || usuarioEncontrado2 || usuarioEncontrado3 || usuarioEncontrado4) {
            if (req.file && req.file.filename) {
                eliminarArchivoSeguro(path.join(UPLOADS_FOTOS_DIR, `resize-${req.file.filename}`));
            }
            let campoDuplicado = usuarioEncontrado  ? `La cédula ${identificacionBuscar}`
                               : usuarioEncontrado2 ? `El correo ${correoBuscar}`
                               : usuarioEncontrado3 ? `El usuario ${usuarioBuscar}`
                               : 'El correo empresarial';
            res.status(402).send({
                message: `${campoDuplicado} ya fue registrado anteriormente`
            });
        } else {

            // Filtrar roles válidos antes de guardar el usuario
            const rolesValidos = (usuarioEntrante.USUARIO_ROL || []).filter(ur => ur.ID_ROL && String(ur.ID_ROL).trim() !== '');
            if (rolesValidos.length === 0) {
                if (req.file && req.file.filename) {
                    eliminarArchivoSeguro(path.join(UPLOADS_FOTOS_DIR, `resize-${req.file.filename}`));
                }
                return res.status(400).send({ message: 'Debe asignar al menos un rol al usuario' });
            }

            let usuario = Usuario.build();

            usuario.USUARIO = usuarioEntrante.USUARIO;
            usuario.NOMBRES = toUpper(usuarioEntrante.NOMBRES);
            usuario.APELLIDOS = toUpper(usuarioEntrante.APELLIDOS);
            usuario.IDENTIFICACION = toUpper(usuarioEntrante.IDENTIFICACION);
            usuario.CORREO = usuarioEntrante.CORREO;
            usuario.CORREO_EMPRESARIAL = usuarioEntrante.CORREO_EMPRESARIAL || null;
            usuario.CELULAR = usuarioEntrante.CELULAR;
            usuario.CONTRASENIA = await bcrypt.hash(usuarioEntrante.CONTRASENIA, 10);
            usuario.FECHA_INGRESO = usuarioEntrante.FECHA_INGRESO;
            usuario.FECHA_SALIDA = usuarioEntrante.FECHA_SALIDA;
            usuario.FECHA_REGISTRO = moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')
            usuario.SALARIO = usuarioEntrante.SALARIO;
            usuario.OBSERVACION = toUpper(usuarioEntrante.OBSERVACION);
            usuario.ESTADO = 1;
            usuario.FOTO = req.file ? `uploads/fotos/resize-${req.file.filename}` : null;

            // Calcular edad automáticamente desde fecha de nacimiento
            if (usuarioEntrante.FECHA_NACIMIENTO) {
                usuario.EDAD = calcularEdad(usuarioEntrante.FECHA_NACIMIENTO);
            }

            let usuarioGuardado = await usuario.save();

            for (let ur of rolesValidos) {
                let usuario_rol = Usuario_Rol.build();
                usuario_rol.ID_ROL = ur.ID_ROL
                usuario_rol.ID_USUARIO = usuarioGuardado.ID_USUARIO
                usuario_rol.DESDE = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate()
                usuario_rol.ESTADO = 1
                await usuario_rol.save();
            }

            if (usuarioGuardado) {
                res.status(200).send({
                    message: 'Registrado exitosamente',
                    data: usuarioGuardado
                });
            } else {
                if (req.file && req.file.filename) {
                    eliminarArchivoSeguro(path.join(UPLOADS_FOTOS_DIR, `resize-${req.file.filename}`));
                }
                res.status(402).send({
                    message: 'No se ha podido registrar sus datos intenta nuevamente'
                });
            }
        }
    } catch (e) {
        console.log(e)
        if (req.file && req.file.filename) {
            eliminarArchivoSeguro(path.join(UPLOADS_FOTOS_DIR, `resize-${req.file.filename}`));
        }
        res.status(500).send({
            message: e.message || e.name,
            detail: e.code || ''
        });
    }
}



async function obtenerUsuarios(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let estado = req.body.estado;
        let mul = limit * offset
        let usuariosEncontrados;
        if (mul == 0) { mul = offset }

        // Construir condición de estado dinámicamente
        let estadoCondicion;
        if (estado !== null && estado !== undefined) {
            // Filtrar por estado específico (0 o 1)
            estadoCondicion = { ESTADO: estado };
        } else {
            // Mostrar todos (activos e inactivos)
            estadoCondicion = {
                [Op.or]: [
                    { ESTADO: 1 },
                    { ESTADO: 0 }
                ]
            };
        }

        usuariosEncontrados = await Usuario.findAll({
            where: {
                [Op.and]: [
                    estadoCondicion,
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_USUARIO', 'DESC']]
        });
        res.status(200).send({
            data: usuariosEncontrados
        });

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function contarTotalUsuarios(req, res) {
    try {
        let buscar = req.body.palabra;
        let estado = req.body.estado;
        let contadorUsuariosEncontrados;

        // Construir condición de estado dinámicamente
        let estadoCondicion;
        if (estado !== null && estado !== undefined) {
            // Filtrar por estado específico (0 o 1)
            estadoCondicion = { ESTADO: estado };
        } else {
            // Mostrar todos (activos e inactivos)
            estadoCondicion = {
                [Op.or]: [
                    { ESTADO: 1 },
                    { ESTADO: 0 }
                ]
            };
        }

        contadorUsuariosEncontrados = await Usuario.count({
            where: {
                [Op.and]: [
                    estadoCondicion,
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
        });

        res.status(200).send({
            data: contadorUsuariosEncontrados
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}



async function obtenerUsuario(req, res) {
    try {
        const usuarioEncontrado = await Usuario.findOne({
            where: { ID_USUARIO: req.params.id },
            include: [
                {
                    model: Canton,
                    required: false,
                    include: [
                        {
                            model: Provincia,
                            as: 'PROVINCIA',
                            required: false
                        }
                    ]
                },
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false,
                    include: [
                        {
                            model: Cargo,
                            include: [
                                {
                                    model: Area
                                }
                            ]
                        }
                    ],
                    where: { ESTADO: true }
                },
                {
                    model: Usuario_Rol,
                    as: 'USUARIO_ROL',
                    include: [
                        {
                            model: Rol
                        }
                    ],
                    where: { ESTADO: 1 }
                }
            ]
        });

        if (usuarioEncontrado.USUARIO_ROL) {
            res.status(200).send({
                data: usuarioEncontrado,
            });
        } else {
            res.status(402).send({
                message: 'No existe usuario'
            });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function actualizarUsuario(req, res) {
    try {
        let usuario = JSON.parse(req.body.usuario);
        usuario.USUARIO = usuario.USUARIO.trim()
        usuario.CORREO = usuario.CORREO.trim()
        if (usuario.CORREO_EMPRESARIAL) {
            usuario.CORREO_EMPRESARIAL = usuario.CORREO_EMPRESARIAL.trim()
        }
        let usuarioEncontrado = await Usuario.findOne({ where: { CORREO: usuario.CORREO } });
        let usuarioEncontrado2 = await Usuario.findOne({ where: { IDENTIFICACION: usuario.IDENTIFICACION } });
        let usuarioEncontrado3 = await Usuario.findOne({ where: { USUARIO: usuario.USUARIO } });
        let usuarioEncontrado4 = null;
        if (usuario.CORREO_EMPRESARIAL) {
            usuarioEncontrado4 = await Usuario.findOne({ 
                where: { CORREO_EMPRESARIAL: usuario.CORREO_EMPRESARIAL } 
            });
        }
        if (usuarioEncontrado && (usuarioEncontrado.ID_USUARIO != usuarioEncontrado.ID_USUARIO)) {
            if (req.file) {
                eliminarArchivoSeguro(req.file.path);
            }
            res.status(402).send({
                message: 'El correo electrónico ya está vinculado a una cuenta'
            });
        } else if (usuarioEncontrado2 && (usuarioEncontrado2.ID_USUARIO != usuario.ID_USUARIO)) {
            if (req.file) {
                eliminarArchivoSeguro(req.file.path);
            }
            res.status(402).send({
                message: 'La identificación ya está vinculado a una cuenta'
            });

        } else if (usuarioEncontrado3 && (usuarioEncontrado3.ID_USUARIO != usuario.ID_USUARIO)) {

            if (req.file) {
                eliminarArchivoSeguro(req.file.path);
            }
            res.status(402).send({
                message: 'El usuario ya está vinculado a una cuenta'
            });

        } else if (usuarioEncontrado4 && (usuarioEncontrado4.ID_USUARIO != usuario.ID_USUARIO)) {
            if (req.file) {
                eliminarArchivoSeguro(req.file.path);
            }
            res.status(402).send({
                message: 'El correo empresarial ya está vinculado a otra cuenta'
            });
        } else {

            if (req.file) {
                await helperImg(req.file.path, `resize-${req.file.filename}`, 800, 1000);
                eliminarArchivoSeguro(req.file.path);
                eliminarArchivoSeguro(usuario.FOTO);
                usuario.FOTO = `uploads/fotos/resize-${req.file.filename}`
            }

            usuarioPorActualizar = {

                USUARIO: usuario.USUARIO,
                NOMBRES: toUpper(usuario.NOMBRES),
                APELLIDOS: toUpper(usuario.APELLIDOS),
                IDENTIFICACION: toUpper(usuario.IDENTIFICACION),
                CORREO: usuario.CORREO,
                CORREO_EMPRESARIAL: usuario.CORREO_EMPRESARIAL || null,
                FECHA_INGRESO: usuario.FECHA_INGRESO,
                FECHA_SALIDA: usuario.FECHA_SALIDA,
                OBSERVACION: toUpper(usuario.OBSERVACION),
                SALARIO: usuario.SALARIO,
                FOTO: usuario.FOTO,

                // Matrices
                ENCUENTRA_EMPLEO: usuario.ENCUENTRA_EMPLEO || null,

                // Calcular edad automáticamente desde fecha de nacimiento
                EDAD: usuario.FECHA_NACIMIENTO ? calcularEdad(usuario.FECHA_NACIMIENTO) : null
            }

            let usuarioActualizado = await Usuario.update(usuarioPorActualizar, { where: { ID_USUARIO: req.params.id } });


            //////
            await Usuario_Rol.destroy({ where: { ID_USUARIO: req.params.id } });
            for (let ur of usuario.USUARIO_ROL) {

                let usuario_rol = Usuario_Rol.build();
                usuario_rol.ID_ROL = ur.ID_ROL
                usuario_rol.ID_USUARIO = usuario.ID_USUARIO
                usuario_rol.DESDE = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate()
                usuario_rol.ESTADO = 1
                let usuarioRolGuardado = await usuario_rol.save();


            }




            if (usuarioActualizado) {
                res.status(200).send({
                    message: 'Transaccion realizada exitosamente',
                });
            } else {
                if (req.file) {
                    eliminarArchivoSeguro(path.join(UPLOADS_FOTOS_DIR, `resize-${req.file.filename}`));
                }
                res.status(402).send({
                    message: 'No se ha podido actualziar el usuario'
                });
            }
        }
    } catch (e) {
        if (req.file && req.file.filename) {
            eliminarArchivoSeguro(path.join(UPLOADS_FOTOS_DIR, `resize-${req.file.filename}`));
        }
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function eliminarRol(req, res) {
    try {
        let usuarioRolEliminado = await Usuario_Rol.destroy({ where: { ID_USUARIO_ROL: req.params.idUsuarioRol } });
        if (usuarioRolEliminado > 0) {
            return res.status(200).send({
                message: "Rol eliminado exitosamente",
            });
        } else {
            return res.status(404).send({
                message: "No se encontró el registro",
            });
        }
    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}


async function actualizarEstadoUsuario(req, res) {
    try {

        let usuarioActualizado = await Usuario.update({ ESTADO: req.params.estado }, { where: { ID_USUARIO: req.params.id } });

        if (usuarioActualizado) {
            res.status(200).send({ message: 'Estado actualizado' });
        } else {
            res.status(402).send({ message: 'No se ha podido actualizar el estado' });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}


async function actualizarContrasenia(req, res) {
    try {

        let usuario = await Usuario.findOne({ where: { ID_USUARIO: req.params.id } });

        let result = bcrypt.compareSync(req.body.CONTRASENIA_ANTERIOR, usuario.CONTRASENIA);
        if (result) {

            let contraniaNueva = await bcrypt.hash(req.body.CONTRASENIA, 10);

            let usuarioActualizado = await Usuario.update({ CONTRASENIA: contraniaNueva }, { where: { ID_USUARIO: req.params.id } });
            if (usuarioActualizado) {
                res.status(200).send({ message: 'Contraseña actualizada' });
            } else {
                res.status(402).send({ message: 'No se ha podido actualizar la contraseña' });
            }

        } else {
            res.status(402).send({ message: 'La contrasenia anterior no coincide' });
        }



    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}



async function recuperarContrasenia(req, res) {
    try {
        console.log("asdasd", req.body.CONTRASENIA)

        let contraniaNueva = await bcrypt.hash(req.body.CONTRASENIA, 10);

        let usuarioActualizado = await Usuario.update({ CONTRASENIA: contraniaNueva }, { where: { ID_USUARIO: req.params.id } });
        if (usuarioActualizado) {
            res.status(200).send({ message: 'Contraseña actualizada' });
        } else {
            res.status(402).send({ message: 'No se ha podido actualizar la contraseña' });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


// mi usuario

async function obtenerMiUsuario(req, res) {
    try {
        const usuarioEncontrado = await Usuario.findOne({
            where: { ID_USUARIO: req.params.id },
            include: [
                { model: Canton },
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false,
                    include: [
                        {
                            model: Cargo,
                            include: [{ model: Area }]
                        }
                    ],
                    where: { ESTADO: true }
                },
                {
                    model: Usuario_Rol,
                    as: 'USUARIO_ROL',
                    include: [
                        {
                            model: Rol,
                            include: [{ model: Sistema }]
                        }
                    ],
                    where: { ESTADO: 1 }
                }
            ]
        });

        if (!usuarioEncontrado) {
            return res.status(404).send({
                message: 'No existe usuario'
            });
        }
        const usuario = usuarioEncontrado.toJSON();

        res.status(200).send({
            data: usuario
        });

    } catch (e) {
        console.error(e);
        res.status(500).send({
            message: e.name
        });
    }
}


async function actualizarMisDatosPersonales(req, res) {
    try {
        // Verificar y crear TODAS las carpetas de uploads
        verificarTodasLasCarpetasUploads();

        let params = JSON.parse(req.body.usuario);

        console.log(params)
        let usuarioPorActualizarMisDatosPersonales = {
            NACIONALIDAD: toUpper(params.NACIONALIDAD),
            FECHA_NACIMIENTO: params.FECHA_NACIMIENTO,
            ACERCA_DE_TI: toUpper(params.ACERCA_DE_TI),
            ESTADO_CIVIL: toUpper(params.ESTADO_CIVIL),
            TIPO_SANGRE: toUpper(params.TIPO_SANGRE),
            SEXO: toUpper(params.SEXO),
            DIRECCION: toUpper(params.DIRECCION),
            ID_CANTON: params.ID_CANTON,
            CODIGO_POSTAL: params.CODIGO_POSTAL,
            TELEFONO_DOMICILIO: params.TELEFONO_DOMICILIO,
            CELULAR: params.CELULAR || null,
            CONTACTO: toUpper(params.CONTACTO),
            TELEFONO_CONTACTO: params.TELEFONO_CONTACTO,
            CELULAR_CONTACTO: params.CELULAR_CONTACTO,

            // Datos bancarios
            BANCO: toUpper(params.BANCO) || null,
            TIPO_CUENTA: toUpper(params.TIPO_CUENTA) || null,
            NUMERO_CUENTA: params.NUMERO_CUENTA || null,

            // Lugar de nacimiento y residencia
            LUGAR_NACIMIENTO: toUpper(params.LUGAR_NACIMIENTO) || null,
            LUGAR_RESIDENCIA: toUpper(params.LUGAR_RESIDENCIA) || null,

            // Parentesco contacto emergencia
            PARENTESCO: toUpper(params.PARENTESCO) || null,

            // Calcular edad automáticamente desde fecha de nacimiento
            EDAD: params.FECHA_NACIMIENTO ? calcularEdad(params.FECHA_NACIMIENTO) : null,
            CONVIVE_PAREJA: params.CONVIVE_PAREJA,
            CARGAS_FAMILIARES_RDEP: params.CARGAS_FAMILIARES_RDEP,
            CARGAS_HIJOS: params.CARGAS_HIJOS,
        }

        if (req.file) {
            usuarioPorActualizarMisDatosPersonales.ARCHIVO_CI = `uploads/CI/${req.file.filename}`;
        }

        let usuarioActualizado = await Usuario.update(usuarioPorActualizarMisDatosPersonales, { where: { ID_USUARIO: req.params.id } });


        if (usuarioActualizado) {
            res.status(200).send({
                message: 'Transaccion realizada exitosamente',
            });
        } else {
            eliminarArchivoSeguro(`uploads/CI/${req.file.filename}`);
            res.status(402).send({
                message: 'No se ha podido actualziar el usuario'
            });
        }

    } catch (e) {
        if (req.file) {
            eliminarArchivoSeguro(`uploads/CI/${req.file.filename}`);
        }
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}

///////// cpacitacion

async function registrarCapacitacion(req, res) {
    try {
        let params = JSON.parse(req.body.capacitacion)

        let capacitacion = Capacitacion.build();
        capacitacion.ID_USUARIO = params.ID_USUARIO;
        capacitacion.PAIS = toUpper(params.PAIS);
        capacitacion.TIPO_EVENTO = toUpper(params.TIPO_EVENTO);
        capacitacion.CERTIFICACION = toUpper(params.CERTIFICACION);
        capacitacion.AREA = toUpper(params.AREA);
        capacitacion.EVENTO = toUpper(params.EVENTO);
        capacitacion.AUSPICIANTE = toUpper(params.AUSPICIANTE);
        capacitacion.DURACION = params.DURACION;
        capacitacion.FECHA_INICIO = params.FECHA_INICIO;
        capacitacion.FECHA_FIN = params.FECHA_FIN;
        capacitacion.ESTUDIOS_EN_CURSO = params.ESTUDIOS_EN_CURSO ?? false;
        capacitacion.RIESGOS_LABORALES_CONSTRUCCION = params.RIESGOS_LABORALES_CONSTRUCCION ?? false;
        capacitacion.RIESGOS_LABORALES_ELECTRICOS = params.RIESGOS_LABORALES_ELECTRICOS ?? false;
        capacitacion.ESTADO = ['PROGRAMADA', 'REALIZADA'].includes(params.ESTADO) ? params.ESTADO : 'REALIZADA';

        capacitacion.FECHA_REGISTRO = moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')
        if (req.file && req.file.filename) {
            capacitacion.ARCHIVO_CAPACITACION = `uploads/capacitaciones/${req.file.filename}`;
        }
        console.log("fecha de registro", capacitacion.FECHA_REGISTRO)

        let capacitacionGuardada = await capacitacion.save();
        if (capacitacionGuardada) {
            res.status(200).send({
                message: 'Registrado exitosamente',
                data: capacitacionGuardada
            });
        } else {
            if (req.file && req.file.filename) {
                eliminarArchivoSeguro(`uploads/capacitaciones/${req.file.filename}`);
            }
            res.status(402).send({
                message: 'No se ha podido registrar sus datos intenta nuevamente'
            });
        }

    } catch (e) {
        if (req.file && req.file.filename) {
            eliminarArchivoSeguro(`uploads/capacitaciones/${req.file.filename}`);
        }
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}



async function obtenerCapacitaciones(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let mul = limit * offset
        let capacitacionesEncontradas;
        if (mul == 0) { mul = offset }
        capacitacionesEncontradas = await Capacitacion.findAll({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { EVENTO: { [Op.substring]: buscar } },
                            { AUSPICIANTE: { [Op.substring]: buscar } },

                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_CAPACITACION', 'DESC']]
        });
        res.status(200).send({
            data: capacitacionesEncontradas
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function contarTotalCapacitaciones(req, res) {
    try {
        let buscar = req.body.palabra;
        let contadorCapacitacionesEncontradas;
        // if (buscar != '') {
        contadorCapacitacionesEncontradas = await Capacitacion.count({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { EVENTO: { [Op.substring]: buscar } },
                            { AUSPICIANTE: { [Op.substring]: buscar } },
                        ]
                    }
                ]
            },
        });
        //  } else {

        //    contadorCapacitacionesEncontradas = await Usuario.count({ where: {ID_USUARIO:req.params.id} });
        //  }
        res.status(200).send({
            data: contadorCapacitacionesEncontradas
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}



async function obtenerCapacitacion(req, res) {
    try {
        const capacitacionEncontrada = await Capacitacion.findOne({
            where: { ID_CAPACITACION: req.params.id },
        });
        if (capacitacionEncontrada) {
            res.status(200).send({
                data: capacitacionEncontrada,
            });
        } else {
            res.status(402).send({
                message: 'No existe usuario'
            });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function actualizarCapacitacion(req, res) {
    try {
        let params = JSON.parse(req.body.capacitacion); 
        let capacitacionPorActualizar = {
            PAIS: toUpper(params.PAIS),
            TIPO_EVENTO: toUpper(params.TIPO_EVENTO),
            CERTIFICACION: toUpper(params.CERTIFICACION),
            AREA: toUpper(params.AREA),
            EVENTO: toUpper(params.EVENTO),
            AUSPICIANTE: toUpper(params.AUSPICIANTE),
            DURACION: params.DURACION,
            FECHA_INICIO: params.FECHA_INICIO,
            FECHA_FIN: params.FECHA_FIN,
            ESTUDIOS_EN_CURSO: params.ESTUDIOS_EN_CURSO ?? false,
            RIESGOS_LABORALES_CONSTRUCCION: params.RIESGOS_LABORALES_CONSTRUCCION ?? false,
            RIESGOS_LABORALES_ELECTRICOS: params.RIESGOS_LABORALES_ELECTRICOS ?? false,
            ESTADO: ['PROGRAMADA', 'REALIZADA'].includes(params.ESTADO) ? params.ESTADO : 'REALIZADA',
            FECHA_REGISTRO: moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')
        }

        if (req.file) {
            verificarYCrearDirectorio('./uploads/capacitaciones');
            eliminarArchivoSeguro(params.ARCHIVO_CAPACITACION);
            capacitacionPorActualizar.ARCHIVO_CAPACITACION = `uploads/capacitaciones/${req.file.filename}`;
        }

        let capacitacionActualizada = await Capacitacion.update(capacitacionPorActualizar, { where: { ID_CAPACITACION: req.params.id } });

        if (capacitacionActualizada) {
            res.status(200).send({
                message: 'Transacción realizada exitosamente',
            });
        } else {
            if (req.file) {
                eliminarArchivoSeguro(`uploads/capacitaciones/${req.file.filename}`);
            }
            res.status(402).send({
                message: 'No se ha podido actualizar la capacitación'
            });
        }

    } catch (e) {
        if (req.file) {
            eliminarArchivoSeguro(`uploads/capacitaciones/${req.file.filename}`);
        }
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}




async function eliminarCapacitacion(req, res) {
    try {
        // buscar la capacitacion para eliminar primero su archivo
        const carga = await Capacitacion.findOne({ where: { ID_CAPACITACION: req.params.id } });

        // Eliminar el archivo
        eliminarArchivoSeguro(carga.ARCHIVO_CAPACITACION);
        
        const capacitacionEliminada = await Capacitacion.destroy({ where: { ID_CAPACITACION: req.params.id } });

        if (capacitacionEliminada) {
            res.status(200).send({
                message: 'Transacción realizada exitosamente',
            });
        } else {
            res.status(404).send({
                message: 'No se encontró la capacitación a eliminar',
            });
        }
    } catch (e) {
        console.error(e);
        res.status(500).send({
            message: 'Ocurrió un error en el servidor',
            error: error.message
        });
    }
}

// estudios 


async function registrarEstudio(req, res) {
    try {
        let params = req.body
        let estudio = Estudio.build();
        estudio.ID_USUARIO = params.ID_USUARIO;
        estudio.TITULO = toUpper(params.TITULO);
        estudio.INSTITUCION = toUpper(params.INSTITUCION);
        estudio.FECHA_INICIO = params.FECHA_INICIO;
        estudio.FECHA_FIN = params.FECHA_FIN;
        estudio.FECHA_GRADUACION = params.FECHA_GRADUACION;
        estudio.AREA_ESTUDIO = toUpper(params.AREA_ESTUDIO);
        estudio.NIVEL = toUpper(params.NIVEL);
        estudio.GRADO = toUpper(params.GRADO);
        estudio.ANIOS_ESTUDIO = params.ANIOS_ESTUDIO;
        estudio.REGISTRO_SENESCYT = toUpper(params.REGISTRO_SENESCYT) ?? null;
        estudio.FECHA_REGISTRO = moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss');


        let estudioGuardado = await estudio.save();
        if (estudioGuardado) {
            res.status(200).send({
                message: 'Registrado exitosamente',
                data: estudioGuardado
            });
        } else {

            res.status(402).send({
                message: 'No se ha podido registrar sus datos intenta nuevamente'
            });
        }

    } catch (e) {
        console.log(e)

        res.status(500).send({
            message: e.name
        });
    }
}


async function obtenerEstudios(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let mul = limit * offset
        let estudiosEncontrados;
        if (mul == 0) { mul = offset }
        estudiosEncontrados = await Estudio.findAll({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { TITULO: { [Op.substring]: buscar } },
                            { INSTITUCION: { [Op.substring]: buscar } },

                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_ESTUDIO', 'DESC']]
        });
        res.status(200).send({
            data: estudiosEncontrados
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function contarTotalEstudios(req, res) {
    try {
        let buscar = req.body.palabra;
        let contadorEstudiosEncontrados;
        contadorEstudiosEncontrados = await Estudio.count({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { TITULO: { [Op.substring]: buscar } },
                            { INSTITUCION: { [Op.substring]: buscar } },
                        ]
                    }
                ]
            },
        });

        res.status(200).send({
            data: contadorEstudiosEncontrados
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function obtenerEstudio(req, res) {
    try {
        const estudioEncontrado = await Estudio.findOne({
            where: { ID_ESTUDIO: req.params.id },
        });
        if (estudioEncontrado) {
            res.status(200).send({
                data: estudioEncontrado,
            });
        } else {
            res.status(402).send({
                message: 'No existe usuario'
            });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}



async function actualizarEstudio(req, res) {
    try {
        let params = req.body;
        let estudioPorActualizar = {
            TITULO: toUpper(params.TITULO),
            INSTITUCION: toUpper(params.INSTITUCION),
            FECHA_INICIO: params.FECHA_INICIO,
            FECHA_FIN: params.FECHA_FIN,
            FECHA_GRADUACION: params.FECHA_GRADUACION,
            AREA_ESTUDIO: toUpper(params.AREA_ESTUDIO),
            NIVEL: toUpper(params.NIVEL),
            GRADO: toUpper(params.GRADO),
            ANIOS_ESTUDIO: params.ANIOS_ESTUDIO,
            REGISTRO_SENESCYT: toUpper(params.REGISTRO_SENESCYT) ?? null,
            FECHA_REGISTRO: moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')
        }

        let estudioActualizado = await Estudio.update(estudioPorActualizar, { where: { ID_ESTUDIO: req.params.id } });


        if (estudioActualizado) {
            res.status(200).send({
                message: 'Transaccion realizada exitosamente',
            });
        } else {

            res.status(402).send({
                message: 'No se ha podido actualziar el usuario'
            });
        }

    } catch (e) {

        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}


async function eliminarEstudio(req, res) {
    try {
        const estudioEliminado = await Estudio.destroy({ where: { ID_ESTUDIO: req.params.id } });

        if (estudioEliminado) {
            res.status(200).send({
                message: 'Transacción realizada exitosamente',
            });
        } else {
            res.status(404).send({
                message: 'No se encontró la capacitación a eliminar',
            });
        }
    } catch (error) {
        console.error(error);
        res.status(500).send({
            message: 'Ocurrió un error en el servidor',
            error: error.message
        });
    }
}


// CARGAS FAMILIARES

async function registrarCargaFamiliar(req, res) {
    try {
        let params = JSON.parse(req.body.cargaFamiliar)
        let carga = Carga_Familiar.build();
        carga.ID_USUARIO = params.ID_USUARIO;
        carga.NOMBRE_CARGA_FAMILIAR = toUpper(params.NOMBRE_CARGA_FAMILIAR);
        carga.IDENTIFICACION_CARGA_FAMILIAR = toUpper(params.IDENTIFICACION_CARGA_FAMILIAR);
        carga.TIPO_PARENTESCO = toUpper(params.TIPO_PARENTESCO);
        carga.ARCHIVO_CI_CARGA_FAMILIAR = `uploads/cargasFamiliares/${req.file.filename}`;
        carga.FECHA_REGISTRO = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate()
        carga.FECHA_CARGA = params.FECHA_CARGA
        carga.FECHA_NACIMIENTO = params.FECHA_NACIMIENTO

        let cargaGuardado = await carga.save();
        if (cargaGuardado) {
            res.status(200).send({
                message: 'Registrado exitosamente',
                data: cargaGuardado
            });
        } else {
            eliminarArchivoSeguro(`uploads/cargasFamiliares/${req.file.filename}`);
            res.status(402).send({
                message: 'No se ha podido registrar sus datos intenta nuevamente'
            });
        }

    } catch (e) {
        eliminarArchivoSeguro(`uploads/cargasFamiliares/${req.file.filename}`);
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function obtenerCargasFamiliares(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let mul = limit * offset
        let cargasEncontradas;
        if (mul == 0) { mul = offset }
        cargasEncontradas = await Carga_Familiar.findAll({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { NOMBRE_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                            { IDENTIFICACION_CARGA_FAMILIAR: { [Op.substring]: buscar } },

                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_CARGA_FAMILIAR', 'DESC']]
        });
        res.status(200).send({
            data: cargasEncontradas
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function contarTotalCargasFamiliares(req, res) {
    try {
        let buscar = req.body.palabra;
        let contadorCargasFamiliaresEncontradas;
        contadorCargasFamiliaresEncontradas = await Carga_Familiar.count({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { NOMBRE_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                            { IDENTIFICACION_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                        ]
                    }
                ]
            },
        });

        res.status(200).send({
            data: contadorCargasFamiliaresEncontradas
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function obtenerCargaFamiliar(req, res) {
    try {
        const cargaEncontrada = await Carga_Familiar.findOne({
            where: { ID_CARGA_FAMILIAR: req.params.id },
        });
        if (cargaEncontrada) {
            res.status(200).send({
                data: cargaEncontrada,
            });
        } else {
            res.status(402).send({
                message: 'No existe carga familiar'
            });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}



async function actualizarCargaFamiliar(req, res) {
    try {
        let params = JSON.parse(req.body.cargaFamiliar);
        let cargaPorActualizar = {
            NOMBRE_CARGA_FAMILIAR: toUpper(params.NOMBRE_CARGA_FAMILIAR),
            IDENTIFICACION_CARGA_FAMILIAR: toUpper(params.IDENTIFICACION_CARGA_FAMILIAR),
            TIPO_PARENTESCO: toUpper(params.TIPO_PARENTESCO),
            FECHA_REGISTRO: moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate(),
            FECHA_CARGA: params.FECHA_CARGA,
            FECHA_NACIMIENTO: params.FECHA_NACIMIENTO,
        }


        if (req.file) {
            eliminarArchivoSeguro(params.ARCHIVO_CI_CARGA_FAMILIAR);
            cargaPorActualizar.ARCHIVO_CI_CARGA_FAMILIAR = `uploads/cargasFamiliares/${req.file.filename}`;
        }

        let cargaActualizada = await Carga_Familiar.update(cargaPorActualizar, { where: { ID_CARGA_FAMILIAR: req.params.id } });


        if (cargaActualizada) {
            res.status(200).send({
                message: 'Transaccion realizada exitosamente',
            });
        } else {
            if (req.file) {
                eliminarArchivoSeguro(`uploads/cargasFamiliares/${req.file.filename}`);
            }
            res.status(402).send({
                message: 'No se ha podido actualziar el usuario'
            });
        }

    } catch (e) {
        if (req.file) {
            eliminarArchivoSeguro(`uploads/cargasFamiliares/${req.file.filename}`);
        }
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}

async function eliminarCargaFamiliar(req, res) {

    const carga = await Carga_Familiar.findOne({ where: { ID_CARGA_FAMILIAR: req.params.id } });

    // Eliminar el archivo vinculado si existe
    eliminarArchivoSeguro(carga.ARCHIVO_CI_CARGA_FAMILIAR);

    try {
        const cargaEliminada = await Carga_Familiar.destroy({ where: { ID_CARGA_FAMILIAR: req.params.id } });

        if (cargaEliminada) {
            res.status(200).send({
                message: 'Transacción realizada exitosamente',
            });
        } else {
            res.status(404).send({
                message: 'No se encontró la capacitación a eliminar',
            });
        }
    } catch (error) {
        console.error(error);
        res.status(500).send({
            message: 'Ocurrió un error en el servidor',
            error: error.message
        });
    }
}


// REPORTE DE HIJOS

async function obtenerHijosFamiliares(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let limit = req.body.tamanioLote || 10;
        let offset = req.body.numeroPagina || 0;
        let mul = limit * offset;
        if (mul == 0) { mul = offset; }
        let filtroEdad = req.body.filtroEdad || 'todos';
        let edadLimite = req.body.edadLimite || 18;

        let hijosEncontrados = await Carga_Familiar.findAll({
            where: {
                TIPO_PARENTESCO: { [Op.in]: ['Hijo', 'Hija'] },
                [Op.or]: [
                    { NOMBRE_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                    { IDENTIFICACION_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                ]
            },
            include: [{
                model: Usuario,
                attributes: ['ID_USUARIO', 'NOMBRES', 'APELLIDOS', 'IDENTIFICACION'],
            }],
            offset: mul,
            limit: limit,
            order: [['ID_CARGA_FAMILIAR', 'DESC']],
            subQuery: false
        });

        // Filtrar por edad si se requiere
        if (filtroEdad !== 'todos') {
            const hoy = new Date();
            hijosEncontrados = hijosEncontrados.filter(hijo => {
                if (!hijo.FECHA_NACIMIENTO) return false;
                const nacimiento = new Date(hijo.FECHA_NACIMIENTO);
                let edad = hoy.getFullYear() - nacimiento.getFullYear();
                const m = hoy.getMonth() - nacimiento.getMonth();
                if (m < 0 || (m === 0 && hoy.getDate() < nacimiento.getDate())) edad--;
                if (filtroEdad === 'mayores') return edad >= edadLimite;
                if (filtroEdad === 'menores') return edad < edadLimite;
                return true;
            });
        }

        res.status(200).send({
            data: hijosEncontrados
        });
    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}

async function contarTotalHijosFamiliares(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let filtroEdad = req.body.filtroEdad || 'todos';
        let edadLimite = req.body.edadLimite || 18;

        if (filtroEdad === 'todos') {
            let total = await Carga_Familiar.count({
                where: {
                    TIPO_PARENTESCO: { [Op.in]: ['Hijo', 'Hija'] },
                    [Op.or]: [
                        { NOMBRE_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                        { IDENTIFICACION_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                    ]
                },
            });
            res.status(200).send({ data: total });
        } else {
            // Para filtro por edad, necesitamos traer todos y filtrar
            let todos = await Carga_Familiar.findAll({
                where: {
                    TIPO_PARENTESCO: { [Op.in]: ['Hijo', 'Hija'] },
                    FECHA_NACIMIENTO: { [Op.ne]: null },
                    [Op.or]: [
                        { NOMBRE_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                        { IDENTIFICACION_CARGA_FAMILIAR: { [Op.substring]: buscar } },
                    ]
                },
                attributes: ['FECHA_NACIMIENTO']
            });
            const hoy = new Date();
            let total = todos.filter(hijo => {
                const nacimiento = new Date(hijo.FECHA_NACIMIENTO);
                let edad = hoy.getFullYear() - nacimiento.getFullYear();
                const m = hoy.getMonth() - nacimiento.getMonth();
                if (m < 0 || (m === 0 && hoy.getDate() < nacimiento.getDate())) edad--;
                if (filtroEdad === 'mayores') return edad >= edadLimite;
                if (filtroEdad === 'menores') return edad < edadLimite;
                return true;
            }).length;
            res.status(200).send({ data: total });
        }
    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}


// admisnitrador
async function obtenerTodaInformacionUsuario(req, res) {
  try {
    const usuarioEncontrado = await Usuario.findOne({
      where: { ID_USUARIO: req.params.id },
      include: [
        {
          model: Canton,
          required: false,
          include: [
            {
              model: Provincia,
              as: 'PROVINCIA',
              required: false
            }
          ]
        },
        {
          model: Licencia,
          as: 'LICENCIA',
          required: false,
          where: { ESTADO: 1 },
        },
        {
          model: VacunaUsuario , 
          as: 'VACUNAS',
          required: false
        },
        {
          model: LiberacionHSE,
          as: 'LIBERACIONES_HSE',
          required: false,
          where: { ESTADO: true }
        },
        {
          model: UsuarioCertificacionHabilitante,
          as: 'CERTIFICACIONES_HABILITANTES',
          required: false,
          where: { ESTADO: true },
          include: [
            {
              model: TipoCertificacionHabilitante,
              required: false
            }
          ]
        },
        {
          model: Historial_Empresa,
          as: 'HISTORIAL_EMPRESA',
          required: false,           
          where: { ESTADO: true },    
          include: [
            {
              model: Cargo,
              required: false,
              include: [{ model: Area, required: false }],
            },
          ],
        },
        {
          model: Usuario_Rol,
          as: 'USUARIO_ROL',
          required: false,            
          where: { ESTADO: 1 },       
          include: [
            {
              model: Rol,
              required: false,
              include: [{ model: Sistema, required: false }],
            },
          ],
        },
        {
          model: Estudio,
          as: 'ESTUDIO',
          required: false,
        },
        {
          model: Capacitacion,
          as: 'CAPACITACION',
          required: false,
        },
        {
          model: Experiencia_Laboral,
          as: 'EXPERIENCIA_LABORAL',
          required: false,
        },
      ],
    });

    if (!usuarioEncontrado) {
      return res.status(404).send({ message: 'Usuario no encontrado' });
    }

    return res.status(200).send({ data: usuarioEncontrado });
  } catch (e) {
    console.error(e);
    return res.status(500).send({
      message: e?.message || e?.name || 'Error interno',
    });
  }
}



// lamados de atencion


async function registrarLlamadoAtencion(req, res) {
    try {
        let params = req.body

        let llamadoAtencion = LlamadoAtencion.build();
        llamadoAtencion.ID_USUARIO = params.ID_USUARIO;
        llamadoAtencion.ASUNTO = toUpper(params.ASUNTO);
        llamadoAtencion.CONTENIDO = toUpper(params.CONTENIDO);
        llamadoAtencion.FECHA = params.FECHA;
        llamadoAtencion.EMITIDO_POR = toUpper(params.EMITIDO_POR);
        llamadoAtencion.RECIBIDO = false;
        llamadoAtencion.FECHA_REGISTRO = moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')

        let llamadoAtencionGuardado = await llamadoAtencion.save();
        if (llamadoAtencionGuardado) {
            res.status(200).send({
                message: 'Registrado exitosamente',
                data: llamadoAtencionGuardado
            });
        } else {

            res.status(402).send({
                message: 'No se ha podido registrar, intenta nuevamente'
            });
        }

    } catch (e) {
        console.log(e)

        res.status(500).send({
            message: e.name
        });
    }
}


async function obtenerLlamadosAtencion(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let mul = limit * offset
        let LlamadosAtencionEncontrados;
        if (mul == 0) { mul = offset }
        LlamadosAtencionEncontrados = await LlamadoAtencion.findAll({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { ASUNTO: { [Op.substring]: buscar } },
                            { CONTENIDO: { [Op.substring]: buscar } },

                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_LLAMADO_ATENCION', 'DESC']]
        });
        res.status(200).send({
            data: LlamadosAtencionEncontrados
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function contarTotalLlamadosAtencion(req, res) {
    try {
        let buscar = req.body.palabra;
        let contadorLlamadosAtencion;
        contadorLlamadosAtencion = await LlamadoAtencion.count({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { ASUNTO: { [Op.substring]: buscar } },
                            { CONTENIDO: { [Op.substring]: buscar } },
                        ]
                    }
                ]
            },
        });

        res.status(200).send({
            data: contadorLlamadosAtencion
        });


    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function obtenerLlamadoAtencion(req, res) {
    try {
        const llamadoAtencionEncontrado = await LlamadoAtencion.findOne({
            where: { ID_LLAMADO_ATENCION: req.params.id },
        });
        if (llamadoAtencionEncontrado) {
            res.status(200).send({
                data: llamadoAtencionEncontrado,
            });
        } else {
            res.status(402).send({
                message: 'No existe usuario'
            });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}


async function actualizarLlamadoAtencion(req, res) {
    try {
        let params = req.body;
        let llamadoAtencionPorActualizar = {
            ASUNTO: toUpper(params.ASUNTO),
            CONTENIDO: toUpper(params.CONTENIDO),
            FECHA: params.FECHAO,
            EMITIDO_POR: toUpper(params.EMITIDO_POR),
            FECHA_REGISTRO: moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')
        }

        let LlamadoAtencionActualizado = await LlamadoAtencion.update(llamadoAtencionPorActualizar, { where: { ID_LLAMADO_ATENCION: req.params.id } });


        if (LlamadoAtencionActualizado) {
            res.status(200).send({
                message: 'Transaccion realizada exitosamente',
            });
        } else {

            res.status(402).send({
                message: 'No se ha podido actualziar el usuario'
            });
        }

    } catch (e) {

        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}


async function actualizarEstadoLlamadoAtencion(req, res) {
    try {


        let llamadoAtencionActualizado = await LlamadoAtencion.update({ RECIBIDO: req.params.estado }, { where: { ID_LLAMADO_ATENCION: req.params.id } });

        if (llamadoAtencionActualizado) {
            res.status(200).send({ message: 'Estado actualizado' });
        } else {
            res.status(402).send({ message: 'No se ha podido actualizar el estado' });
        }

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }

}

// historial empresa

async function registrarHistorialEmpresa(req, res) {
    try {
        let params = JSON.parse(req.body.historialEmpresa);

        // Actualizar el estado de todos los historiales del usuario a false
        await Historial_Empresa.update(
            { ESTADO: false },
            { where: { ID_USUARIO: params.ID_USUARIO } }
        );

        // Crear y guardar el nuevo historial de empresak
        let historialEmpresa = Historial_Empresa.build();
        historialEmpresa.ID_USUARIO = params.ID_USUARIO;
        historialEmpresa.TIPO_INGRESO = toUpper(params.TIPO_INGRESO);
        historialEmpresa.FECHA_INGRESO = params.FECHA_INGRESO;
        historialEmpresa.FECHA_SALIDA = params.FECHA_SALIDA || null;
        historialEmpresa.SALARIO = params.SALARIO;
        historialEmpresa.ID_CARGO = params.ID_CARGO;
        historialEmpresa.MOTIVO_SALIDA = toUpper(params.MOTIVO_SALIDA) || null;
        historialEmpresa.TIPO_SALIDA = params.TIPO_SALIDA || null;
        historialEmpresa.OBSERVACION_SALIDA = toUpper(params.OBSERVACION_SALIDA) || null;
        historialEmpresa.OBSERVACION = toUpper(params.OBSERVACION) || null;
        historialEmpresa.CODIGO_CONTRATO = toUpper(params.CODIGO_CONTRATO) || null;
        historialEmpresa.CODIGO_HASH = params.CODIGO_HASH || null;
        historialEmpresa.INGRESO_SOFIA = params.INGRESO_SOFIA || false;
        historialEmpresa.ACTA_FINIQUITO = params.ACTA_FINIQUITO || false;
        historialEmpresa.ESTADO = true;
        historialEmpresa.FECHA_REGISTRO = moment().tz('America/Guayaquil').toDate();

        // Información contractual
        historialEmpresa.TIPO_CONTRATO = toUpper(params.TIPO_CONTRATO) || null;
        historialEmpresa.CODIGO_SECTORIAL = toUpper(params.CODIGO_SECTORIAL) || null;
        historialEmpresa.CORROBORACION = toUpper(params.CORROBORACION) || null;
        historialEmpresa.CARGO_IESS = toUpper(params.CARGO_IESS) || null;
        historialEmpresa.SOLICITUD_FONDOS_RESERVA = params.SOLICITUD_FONDOS_RESERVA || null;
        historialEmpresa.VENCIMIENTO_FONDOS_RESERVA = params.VENCIMIENTO_FONDOS_RESERVA || null;

        // Beneficios corporativos
        historialEmpresa.BENEFICIO_HOSPEDAJE_ALIMENTACION = params.BENEFICIO_HOSPEDAJE_ALIMENTACION || false;
        historialEmpresa.BENEFICIO_TARJETA_TIA = params.BENEFICIO_TARJETA_TIA || false;
        historialEmpresa.MONTO_TARJETA_TIA = params.MONTO_TARJETA_TIA || null;

        // EPP - Tallas
        historialEmpresa.TALLA_BOTAS = params.TALLA_BOTAS || null;
        historialEmpresa.TALLA_OVEROL = params.TALLA_OVEROL || null;
        historialEmpresa.TALLA_JEANS_CAMISA = params.TALLA_JEANS_CAMISA || null;
        historialEmpresa.TALLA_JEANS_PANTALON = params.TALLA_JEANS_PANTALON || null;

        // Declaraciones PCA-P-PC010
        historialEmpresa.DECLARACION_JURAMENTADA = params.DECLARACION_JURAMENTADA || false;
        historialEmpresa.RESIDENTES_AMAZONICOS = params.RESIDENTES_AMAZONICOS || false;

        // Bonos
        historialEmpresa.BONO_EXTRA = params.BONO_EXTRA || null;
        historialEmpresa.BONO_CAMPO = params.BONO_CAMPO || null;
        if (req.files && req.files['archivoContrato'] && req.files['archivoContrato'][0]) {
            historialEmpresa.ARCHIVO_CONTRATO = `uploads/contratos/${req.files['archivoContrato'][0].filename}`;
        }
        if (req.files && req.files['archivoActaFiniquito'] && req.files['archivoActaFiniquito'][0]) {
            historialEmpresa.ARCHIVO_ACTA_FINIQUITO = `uploads/contratos/${req.files['archivoActaFiniquito'][0].filename}`;
        }

        let historialEmpresaGuardado = await historialEmpresa.save();
        if (historialEmpresaGuardado) {
            res.status(200).send({
                message: 'Historial de empresa registrado exitosamente',
                data: historialEmpresaGuardado
            });
        } else {
            if (req.files && req.files['archivoContrato']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoContrato'][0].filename}`);
            if (req.files && req.files['archivoActaFiniquito']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoActaFiniquito'][0].filename}`);
            res.status(402).send({
                message: 'No se ha podido registrar el historial de empresa, intenta nuevamente'
            });
        }
    } catch (e) {
        if (req.files && req.files['archivoContrato']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoContrato'][0].filename}`);
        if (req.files && req.files['archivoActaFiniquito']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoActaFiniquito'][0].filename}`);
        console.log(e);
        res.status(500).send({
            message: 'Error en el servidor: ' + e.name
        });
    }
}


async function obtenerHistorialesEmpresa(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let limit = req.body.tamanioLote || 10;
        let offset = req.body.numeroPagina || 0;
        let mul = limit * offset;
        if (mul === 0) mul = offset;

        let historialesEmpresaEncontrados = await Historial_Empresa.findAll({
            where: {
                [Op.and]: [
                    { ID_USUARIO: req.params.id },
                    {
                        [Op.or]: [
                            { OBSERVACION: { [Op.substring]: buscar } },
                            { OBSERVACION: null }
                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_HISTORIAL_EMPRESA', 'DESC']],
            include: [
                {
                    model: Cargo,
                    include: [
                        {
                            model: Area
                        }
                    ]
                }
            ]
        });

        res.status(200).send({
            data: historialesEmpresaEncontrados
        });
    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: 'Error en el servidor: ' + e.name
        });
    }
}

async function contarTotalHistorialesEmpresa(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let contadorHistorialesEmpresa = await Historial_Empresa.count({
            where: {
                [Op.and]: [
                    { ID_USUARIO: req.params.id },
                    {
                        [Op.or]: [
                            { OBSERVACION: { [Op.substring]: buscar } },
                            { OBSERVACION: null }
                        ]
                    }
                ]
            }
        });

        res.status(200).send({
            data: contadorHistorialesEmpresa
        });
    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: 'Error en el servidor: ' + e.name
        });
    }
}

async function obtenerHistorialEmpresa(req, res) {
    try {
        const historialEmpresaEncontrado = await Historial_Empresa.findOne({
            where: { ID_HISTORIAL_EMPRESA: req.params.id },
            include: [
                {
                    model: Cargo,
                    include: [
                        {
                            model: Area
                        }
                    ]
                }
            ]
        });

        if (historialEmpresaEncontrado) {
            res.status(200).send({
                data: historialEmpresaEncontrado
            });
        } else {
            res.status(404).send({
                message: 'No se encontró el historial de empresa'
            });
        }
    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: 'Error en el servidor: ' + e.name
        });
    }
}

async function actualizarHistorialEmpresa(req, res) {
    try {
        let params = JSON.parse(req.body.historialEmpresa);

        let historialActual = await Historial_Empresa.findOne({
            where: { ID_HISTORIAL_EMPRESA: req.params.id }
        });
        let historialEmpresaPorActualizar = {
            TIPO_INGRESO: toUpper(params.TIPO_INGRESO),
            FECHA_INGRESO: params.FECHA_INGRESO,
            FECHA_SALIDA: params.FECHA_SALIDA || null,
            SALARIO: params.SALARIO,
            ID_CARGO: params.ID_CARGO,
            OBSERVACION: toUpper(params.OBSERVACION) || null,
            MOTIVO_SALIDA: toUpper(params.MOTIVO_SALIDA) || null,
            TIPO_SALIDA: params.TIPO_SALIDA || null,
            OBSERVACION_SALIDA: toUpper(params.OBSERVACION_SALIDA) || null,
            ESTADO: params.FECHA_SALIDA ? false : true,
            CODIGO_CONTRATO: toUpper(params.CODIGO_CONTRATO) || null,
            CODIGO_HASH: params.CODIGO_HASH || null,
            INGRESO_SOFIA: params.INGRESO_SOFIA || false,
            ACTA_FINIQUITO: params.ACTA_FINIQUITO || false,
            FECHA_REGISTRO: moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss'),

            // Información contractual
            TIPO_CONTRATO: toUpper(params.TIPO_CONTRATO) || null,
            CODIGO_SECTORIAL: toUpper(params.CODIGO_SECTORIAL) || null,
            CORROBORACION: toUpper(params.CORROBORACION) || null,
            CARGO_IESS: toUpper(params.CARGO_IESS) || null,
            SOLICITUD_FONDOS_RESERVA: params.SOLICITUD_FONDOS_RESERVA || null,
            VENCIMIENTO_FONDOS_RESERVA: params.VENCIMIENTO_FONDOS_RESERVA || null,

            // Beneficios corporativos
            BENEFICIO_HOSPEDAJE_ALIMENTACION: params.BENEFICIO_HOSPEDAJE_ALIMENTACION || false,
            BENEFICIO_TARJETA_TIA: params.BENEFICIO_TARJETA_TIA || false,
            MONTO_TARJETA_TIA: params.MONTO_TARJETA_TIA || null,

            // EPP - Tallas
            TALLA_BOTAS: params.TALLA_BOTAS || null,
            TALLA_OVEROL: params.TALLA_OVEROL || null,
            TALLA_JEANS_CAMISA: params.TALLA_JEANS_CAMISA || null,
            TALLA_JEANS_PANTALON: params.TALLA_JEANS_PANTALON || null,

            // Declaraciones PCA-P-PC010
            DECLARACION_JURAMENTADA: params.DECLARACION_JURAMENTADA || false,
            RESIDENTES_AMAZONICOS: params.RESIDENTES_AMAZONICOS || false,

            // Bonos
            BONO_EXTRA: params.BONO_EXTRA || null,
            BONO_CAMPO: params.BONO_CAMPO || null,
        }

        // Archivo contrato
        if (req.files && req.files['archivoContrato'] && req.files['archivoContrato'][0]) {
            if (historialActual.ARCHIVO_CONTRATO && fs.existsSync(historialActual.ARCHIVO_CONTRATO)) {
                eliminarArchivoSeguro(historialActual.ARCHIVO_CONTRATO);
            }
            historialEmpresaPorActualizar.ARCHIVO_CONTRATO = `uploads/contratos/${req.files['archivoContrato'][0].filename}`;
        } else if (params.ARCHIVO_CONTRATO === '') {
            if (historialActual.ARCHIVO_CONTRATO && fs.existsSync(historialActual.ARCHIVO_CONTRATO)) {
                eliminarArchivoSeguro(historialActual.ARCHIVO_CONTRATO);
            }
            historialEmpresaPorActualizar.ARCHIVO_CONTRATO = null;
        }

        // Archivo acta de finiquito
        if (req.files && req.files['archivoActaFiniquito'] && req.files['archivoActaFiniquito'][0]) {
            if (historialActual.ARCHIVO_ACTA_FINIQUITO && fs.existsSync(historialActual.ARCHIVO_ACTA_FINIQUITO)) {
                eliminarArchivoSeguro(historialActual.ARCHIVO_ACTA_FINIQUITO);
            }
            historialEmpresaPorActualizar.ARCHIVO_ACTA_FINIQUITO = `uploads/contratos/${req.files['archivoActaFiniquito'][0].filename}`;
        } else if (params.ARCHIVO_ACTA_FINIQUITO === '') {
            if (historialActual.ARCHIVO_ACTA_FINIQUITO && fs.existsSync(historialActual.ARCHIVO_ACTA_FINIQUITO)) {
                eliminarArchivoSeguro(historialActual.ARCHIVO_ACTA_FINIQUITO);
            }
            historialEmpresaPorActualizar.ARCHIVO_ACTA_FINIQUITO = null;
        }

        let historialEmpresaActualizado = await Historial_Empresa.update(historialEmpresaPorActualizar, {
            where: { ID_HISTORIAL_EMPRESA: req.params.id }
        });

        if (historialEmpresaActualizado) {
            res.status(200).send({
                message: 'Historial de empresa actualizado exitosamente'
            });
        } else {
            if (req.files && req.files['archivoContrato']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoContrato'][0].filename}`);
            if (req.files && req.files['archivoActaFiniquito']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoActaFiniquito'][0].filename}`);
            res.status(404).send({
                message: 'No se encontró el historial de empresa para actualizar'
            });
        }
    } catch (e) {
        if (req.files && req.files['archivoContrato']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoContrato'][0].filename}`);
        if (req.files && req.files['archivoActaFiniquito']) eliminarArchivoSeguro(`uploads/contratos/${req.files['archivoActaFiniquito'][0].filename}`);
        console.log(e);
        res.status(500).send({
            message: 'Error en el servidor: ' + e.name
        });
    }
}


async function eliminarHistorialEmpresa(req, res) {
    try {
        // Obtener el historial a eliminar
        const historialEmpresa = await Historial_Empresa.findOne({
            where: { ID_HISTORIAL_EMPRESA: req.params.id }
        });

        if (!historialEmpresa) {
            return res.status(404).send({
                message: 'No se encontró el historial de empresa para eliminar'
            });
        }

        if (historialEmpresa.ARCHIVO_CONTRATO) {

            eliminarArchivoSeguro(historialEmpresa.ARCHIVO_CONTRATO);
        }
        // Eliminar el historial
        const historialEmpresaEliminado = await Historial_Empresa.destroy({
            where: { ID_HISTORIAL_EMPRESA: req.params.id }
        });

        if (historialEmpresaEliminado) {
            // Verificar si el historial eliminado era el más reciente
            const historiales = await Historial_Empresa.findAll({
                where: { ID_USUARIO: historialEmpresa.ID_USUARIO },
                order: [['ID_HISTORIAL_EMPRESA', 'DESC']]
            });

            if (historiales.length > 0) {
                // Actualizar el estado del historial más reciente (anterior al eliminado) a true
                await Historial_Empresa.update(
                    { ESTADO: true },
                    { where: { ID_HISTORIAL_EMPRESA: historiales[0].ID_HISTORIAL_EMPRESA } }
                );
            }

            res.status(200).send({
                message: 'Historial de empresa eliminado exitosamente'
            });
        } else {
            res.status(404).send({
                message: 'No se encontró el historial de empresa para eliminar'
            });
        }
    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: 'Error en el servidor: ' + e.name
        });
    }
}
async function actualizarInformacionHSE(req, res) {
  try {
    // parseo de body
    let entidadActualizarInformacionHSE;
    let vLicencias;
    let vLiberaciones;
    let vVacunas;

    entidadActualizarInformacionHSE =
      typeof req.body.entidadActualizarInformacionHSE === 'string'
        ? JSON.parse(req.body.entidadActualizarInformacionHSE)
        : req.body.entidadActualizarInformacionHSE;

    vLicencias =
      typeof req.body.vLicencias === 'string'
        ? JSON.parse(req.body.vLicencias || '[]')
        : (req.body.vLicencias || []);

    vLiberaciones =
      typeof req.body.vLiberaciones === 'string'
        ? JSON.parse(req.body.vLiberaciones || '[]')
        : (req.body.vLiberaciones || []);

    vVacunas =
      typeof req.body.vVacunas === 'string'
        ? JSON.parse(req.body.vVacunas || '[]')
        : (req.body.vVacunas || []);

    let vCertificaciones =
      typeof req.body.vCertificaciones === 'string'
        ? JSON.parse(req.body.vCertificaciones || '[]')
        : (req.body.vCertificaciones || []);

    let dataUsuario = { ...entidadActualizarInformacionHSE };

    const usuarioBD = await Usuario.findOne({
      where: { ID_USUARIO: req.params.id }
    });

    // manejo de evidencias hse usuario
    if (req.files && req.files['archivoManejoDefensivo'] && req.files['archivoManejoDefensivo'][0]) {
      const f = req.files['archivoManejoDefensivo'][0];

      eliminarArchivoSeguro(usuarioBD?.MANEJO_DEFENSIVO_EVIDENCIA);
      dataUsuario.MANEJO_DEFENSIVO_EVIDENCIA = f.path;

    } else if (!entidadActualizarInformacionHSE.MANEJO_DEFENSIVO &&
      usuarioBD?.MANEJO_DEFENSIVO_EVIDENCIA) {

      eliminarArchivoSeguro(usuarioBD.MANEJO_DEFENSIVO_EVIDENCIA);
      dataUsuario.MANEJO_DEFENSIVO_EVIDENCIA = null;

    } else if (entidadActualizarInformacionHSE._eliminarEvidenciaManejo &&
      usuarioBD?.MANEJO_DEFENSIVO_EVIDENCIA) {

      eliminarArchivoSeguro(usuarioBD.MANEJO_DEFENSIVO_EVIDENCIA);
      dataUsuario.MANEJO_DEFENSIVO_EVIDENCIA = null;
    }

    if (req.files && req.files['archivoCertificadoManejo'] && req.files['archivoCertificadoManejo'][0]) {
      const f = req.files['archivoCertificadoManejo'][0];

      eliminarArchivoSeguro(usuarioBD?.CERTIFICADO_MANEJO_EVIDENCIA);
      dataUsuario.CERTIFICADO_MANEJO_EVIDENCIA = f.path;

    } else if (!entidadActualizarInformacionHSE.CERTIFICADO_MANEJO_EMPRESA &&
      usuarioBD?.CERTIFICADO_MANEJO_EVIDENCIA) {

      eliminarArchivoSeguro(usuarioBD.CERTIFICADO_MANEJO_EVIDENCIA);
      dataUsuario.CERTIFICADO_MANEJO_EVIDENCIA = null;

    } else if (entidadActualizarInformacionHSE._eliminarEvidenciaCertificado &&
      usuarioBD?.CERTIFICADO_MANEJO_EVIDENCIA) {

      eliminarArchivoSeguro(usuarioBD.CERTIFICADO_MANEJO_EVIDENCIA);
      dataUsuario.CERTIFICADO_MANEJO_EVIDENCIA = null;
    }

    // actualizar usuario
    const usuarioActualizado = await Usuario.update(dataUsuario, {
      where: { ID_USUARIO: req.params.id }
    });

    // licencias hse
    const licenciasActuales = await Licencia.findAll({
      where: { ID_USUARIO: req.params.id }
    });

    const licenciasMap = {};
    licenciasActuales.forEach(l => { licenciasMap[l.ID_LICENCIA] = l; });

    const archivosLicencias = (req.files && req.files['archivosLicencias'])
      ? req.files['archivosLicencias']
      : [];

    let idxArchivoLic = 0;

    if (entidadActualizarInformacionHSE.CERTIFICADO_MANEJO_EMPRESA) {
      const nuevasLicencias = [];
      const licenciasActualizar = [];

      vLicencias.forEach((licenciaEntrante) => {
        let archivoLic = null;

        if (licenciaEntrante._tieneArchivoNuevo && archivosLicencias[idxArchivoLic]) {
          archivoLic = archivosLicencias[idxArchivoLic];
          idxArchivoLic++;
        }

        if (licenciaEntrante.ID_LICENCIA == 0) {
          const nueva = {
            TIPO_LICENCIA: toUpper(licenciaEntrante.TIPO_LICENCIA),
            ID_USUARIO: req.params.id,
            FECHA_CADUCIDAD: licenciaEntrante.FECHA_CADUCIDAD,
            ESTADO: true,
            PUNTOS: licenciaEntrante.PUNTOS ?? 30,
            EVIDENCIA: archivoLic ? archivoLic.path : null
          };
          nuevasLicencias.push(nueva);

        } else if (licenciaEntrante.ID_LICENCIA > 0) {
          licenciaEntrante.ESTADO = true;
          const licenciaActual = licenciasMap[licenciaEntrante.ID_LICENCIA];

          if (archivoLic) {
            eliminarArchivoSeguro(licenciaActual?.EVIDENCIA);
            licenciaEntrante.EVIDENCIA = archivoLic.path;

          } else if (licenciaEntrante._eliminarEvidencia) {
            eliminarArchivoSeguro(licenciaActual?.EVIDENCIA);
            licenciaEntrante.EVIDENCIA = null;

          } else if (licenciaActual) {
            licenciaEntrante.EVIDENCIA = licenciaActual.EVIDENCIA;
          }

          delete licenciaEntrante._tieneArchivoNuevo;
          delete licenciaEntrante._eliminarEvidencia;

          licenciasActualizar.push(licenciaEntrante);
        }
      });

      if (nuevasLicencias.length > 0) {
        await Licencia.bulkCreate(nuevasLicencias);
      }

      if (licenciasActualizar.length > 0) {
        await Promise.all(
          licenciasActualizar.map(l =>
            Licencia.update(l, {
              where: { ID_LICENCIA: l.ID_LICENCIA }
            })
          )
        );
      }

      // Eliminar licencias que ya no están en la lista
      const idsEntrantes = vLicencias
        .filter(l => l.ID_LICENCIA > 0)
        .map(l => l.ID_LICENCIA);

      const licenciasAEliminar = licenciasActuales.filter(
        l => !idsEntrantes.includes(l.ID_LICENCIA)
      );

      for (let lic of licenciasAEliminar) {
        eliminarArchivoSeguro(lic.EVIDENCIA);
      }

      if (licenciasAEliminar.length > 0) {
        await Licencia.destroy({
          where: {
            ID_USUARIO: req.params.id,
            ID_LICENCIA: { [Op.in]: licenciasAEliminar.map(l => l.ID_LICENCIA) }
          }
        });
      }
    } else if (vLicencias.some(l => l.ID_LICENCIA > 0)) {
      // Si no tiene certificado pero hay licencias existentes, eliminar las que no están
      const idsEntrantes = vLicencias
        .filter(l => l.ID_LICENCIA > 0)
        .map(l => l.ID_LICENCIA);

      const aEliminar = licenciasActuales.filter(
        l => !idsEntrantes.includes(l.ID_LICENCIA)
      );

      for (let lic of aEliminar) {
        eliminarArchivoSeguro(lic.EVIDENCIA);
      }

      if (aEliminar.length > 0) {
        await Licencia.destroy({
          where: {
            ID_USUARIO: req.params.id,
            ID_LICENCIA: { [Op.in]: aEliminar.map(l => l.ID_LICENCIA) }
          }
        });
      }
    }

    // liberaciones hse
    const liberacionesActuales = await LiberacionHSE.findAll({
      where: { ID_USUARIO: req.params.id }
    });

    const liberacionesMap = {};
    liberacionesActuales.forEach(l => { liberacionesMap[l.ID_LIBERACION] = l; });

    const archivosLiberaciones = (req.files && req.files['archivosLiberaciones'])
      ? req.files['archivosLiberaciones']
      : [];

    let idxArchivoLib = 0;

    const nuevasLiberaciones = [];
    const liberacionesActualizar = [];

    vLiberaciones.forEach((liberacionEntrante) => {
      let archivoLib = null;
      const tipoLib = toUpper(String(liberacionEntrante.TIPO_LIBERACION || ''));
      const esNEST = tipoLib === 'NEST';

      if (liberacionEntrante._tieneArchivoNuevo && archivosLiberaciones[idxArchivoLib]) {
        archivoLib = archivosLiberaciones[idxArchivoLib];
        idxArchivoLib++;
      }

      if (liberacionEntrante.ID_LIBERACION == 0) {
        const nueva = {
          TIPO_LIBERACION: tipoLib,
          ID_USUARIO: req.params.id,
          FECHA_EXPIRACION: esNEST ? null : liberacionEntrante.FECHA_EXPIRACION,
          FECHA_NEST: esNEST ? (liberacionEntrante.FECHA_NEST || null) : null,
          QUEST: esNEST ? (liberacionEntrante.QUEST || null) : null,
          INSTRUCTORES: esNEST ? (Array.isArray(liberacionEntrante.INSTRUCTORES) ? liberacionEntrante.INSTRUCTORES : []) : null,
          FECHA_VIGENCIA: liberacionEntrante.FECHA_VIGENCIA || null,
          ESTADO: true,
          EVIDENCIA: esNEST ? null : (archivoLib ? archivoLib.path : null)
        };
        nuevasLiberaciones.push(nueva);

      } else if (liberacionEntrante.ID_LIBERACION > 0) {
        const liberacionActual = liberacionesMap[liberacionEntrante.ID_LIBERACION];

        if (esNEST) {
          // NEST no usa evidencia PDF: limpiar si existía
          eliminarArchivoSeguro(liberacionActual?.EVIDENCIA);
          liberacionEntrante.EVIDENCIA = null;
          liberacionEntrante.FECHA_EXPIRACION = null;

        } else if (archivoLib) {
          eliminarArchivoSeguro(liberacionActual?.EVIDENCIA);
          liberacionEntrante.EVIDENCIA = archivoLib.path;

        } else if (liberacionEntrante._eliminarEvidencia) {
          eliminarArchivoSeguro(liberacionActual?.EVIDENCIA);
          liberacionEntrante.EVIDENCIA = null;

        } else if (liberacionActual) {
          liberacionEntrante.EVIDENCIA = liberacionActual.EVIDENCIA;
        }

        delete liberacionEntrante._tieneArchivoNuevo;
        delete liberacionEntrante._eliminarEvidencia;

        liberacionesActualizar.push(liberacionEntrante);
      }
    });

    if (nuevasLiberaciones.length > 0) {
      await LiberacionHSE.bulkCreate(nuevasLiberaciones);
    }

    if (liberacionesActualizar.length > 0) {
      await Promise.all(
        liberacionesActualizar.map(l => {
          const tipoL = toUpper(String(l.TIPO_LIBERACION || ''));
          const esN = tipoL === 'NEST';
          const updateData = {
            TIPO_LIBERACION: tipoL,
            FECHA_EXPIRACION: esN ? null : (l.FECHA_EXPIRACION || null),
            FECHA_NEST: esN ? (l.FECHA_NEST || null) : null,
            QUEST: esN ? (l.QUEST || null) : null,
            INSTRUCTORES: esN ? (Array.isArray(l.INSTRUCTORES) ? l.INSTRUCTORES : []) : null,
            FECHA_VIGENCIA: l.FECHA_VIGENCIA || null,
            ESTADO: true,
            EVIDENCIA: l.EVIDENCIA || null
          };
          return LiberacionHSE.update(updateData, {
            where: { ID_LIBERACION: l.ID_LIBERACION }
          });
        })
      );
    }

    if (vLiberaciones.length === 0) {
      for (let liberacionActual of liberacionesActuales) {
        eliminarArchivoSeguro(liberacionActual.EVIDENCIA);
      }
      await LiberacionHSE.destroy({ where: { ID_USUARIO: req.params.id } });

    } else if (vLiberaciones.some(l => l.ID_LIBERACION > 0)) {
      const idsEntrantesLib = vLiberaciones
        .filter(l => l.ID_LIBERACION > 0)
        .map(l => l.ID_LIBERACION);

      const aEliminarLib = liberacionesActuales.filter(
        l => !idsEntrantesLib.includes(l.ID_LIBERACION)
      );

      const idsAEliminarLib = aEliminarLib.map(l => l.ID_LIBERACION);

      for (let lib of aEliminarLib) {
        eliminarArchivoSeguro(lib.EVIDENCIA);
      }

      if (idsAEliminarLib.length > 0) {
        await LiberacionHSE.destroy({
          where: {
            ID_USUARIO: req.params.id,
            ID_LIBERACION: { [Op.in]: idsAEliminarLib }
          }
        });
      }
    }

    // vacunas hse
    const vacunasActuales = await VacunaUsuario.findAll({
      where: { ID_USUARIO: req.params.id }
    });

    const nuevasVacunas = [];
    const vacunasActualizar = [];

    vVacunas.forEach((vacunaEntrante) => {
      if (vacunaEntrante.ID_VACUNA_USUARIO == 0) {
        nuevasVacunas.push({
          ID_USUARIO: req.params.id,
          ID_TIPO_VACUNA: vacunaEntrante.ID_TIPO_VACUNA,
          NUMERO_DOSIS: vacunaEntrante.NUMERO_DOSIS,
          FECHA_APLICACION: vacunaEntrante.FECHA_APLICACION,
          FECHA_PROXIMA_DOSIS: vacunaEntrante.FECHA_PROXIMA_DOSIS,
          ESTADO: 1
        });
      } else if (vacunaEntrante.ID_VACUNA_USUARIO > 0) {
        vacunasActualizar.push(vacunaEntrante);
      }
    });

    if (nuevasVacunas.length > 0) {
      await VacunaUsuario.bulkCreate(nuevasVacunas);
    }

    if (vacunasActualizar.length > 0) {
      await Promise.all(
        vacunasActualizar.map(v => {
          return VacunaUsuario.update(
            {
              ID_TIPO_VACUNA: v.ID_TIPO_VACUNA,
              NUMERO_DOSIS: v.NUMERO_DOSIS,
              FECHA_APLICACION: v.FECHA_APLICACION,
              FECHA_PROXIMA_DOSIS: v.FECHA_PROXIMA_DOSIS,
              ESTADO: v.ESTADO
            },
            { where: { ID_VACUNA_USUARIO: v.ID_VACUNA_USUARIO } }
          );
        })
      );
    }

    if (vVacunas.length === 0) {
      await VacunaUsuario.destroy({ where: { ID_USUARIO: req.params.id } });

    } else {
      const idsEntrantesVac = vVacunas
        .filter(v => v.ID_VACUNA_USUARIO > 0)
        .map(v => v.ID_VACUNA_USUARIO);

      if (idsEntrantesVac.length > 0) {
        const aEliminarVac = vacunasActuales.filter(
          v => !idsEntrantesVac.includes(v.ID_VACUNA_USUARIO)
        );

        const idsAEliminarVac = aEliminarVac.map(v => v.ID_VACUNA_USUARIO);

        if (idsAEliminarVac.length > 0) {
          await VacunaUsuario.destroy({
            where: {
              ID_USUARIO: req.params.id,
              ID_VACUNA_USUARIO: { [Op.in]: idsAEliminarVac }
            }
          });
        }
      }
    }

    // certificaciones habilitantes hse
    const certificacionesActuales = await UsuarioCertificacionHabilitante.findAll({
      where: { ID_USUARIO: req.params.id }
    });

    const certificacionesMap = {};
    certificacionesActuales.forEach(c => { certificacionesMap[c.ID_USUARIO_CERTIFICACION] = c; });

    const archivosCertificaciones = (req.files && req.files['archivosCertificaciones'])
      ? req.files['archivosCertificaciones']
      : [];

    let idxArchivoCert = 0;

    const nuevasCertificaciones = [];
    const certificacionesActualizar = [];

    vCertificaciones.forEach((certEntrante) => {
      let archivoCert = null;

      if (certEntrante._tieneArchivoNuevo && archivosCertificaciones[idxArchivoCert]) {
        archivoCert = archivosCertificaciones[idxArchivoCert];
        idxArchivoCert++;
      }

      if (certEntrante.ID_USUARIO_CERTIFICACION == 0) {
        // Solo crear certificaciones nuevas si están activas
        if (certEntrante.ESTADO) {
          nuevasCertificaciones.push({
            ID_USUARIO: req.params.id,
            ID_TIPO_CERTIFICACION: certEntrante.ID_TIPO_CERTIFICACION,
            FECHA_REGISTRO: moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate(),
            FECHA_VENCIMIENTO: certEntrante.FECHA_VENCIMIENTO ?? null,
            EVIDENCIA: archivoCert ? archivoCert.path : null,
            ESTADO: true
          });
        }
      } else if (certEntrante.ID_USUARIO_CERTIFICACION > 0) {
        const certActual = certificacionesMap[certEntrante.ID_USUARIO_CERTIFICACION];

        if (archivoCert) {
          eliminarArchivoSeguro(certActual?.EVIDENCIA);
          certEntrante.EVIDENCIA = archivoCert.path;

        } else if (certEntrante._eliminarEvidencia) {
          eliminarArchivoSeguro(certActual?.EVIDENCIA);
          certEntrante.EVIDENCIA = null;

        } else if (certActual) {
          certEntrante.EVIDENCIA = certActual.EVIDENCIA;
        }

        certificacionesActualizar.push(certEntrante);
      }
    });

    if (nuevasCertificaciones.length > 0) {
      await UsuarioCertificacionHabilitante.bulkCreate(nuevasCertificaciones);
    }

    if (certificacionesActualizar.length > 0) {
      await Promise.all(
        certificacionesActualizar.map(c => {
          return UsuarioCertificacionHabilitante.update(
            {
              ID_TIPO_CERTIFICACION: c.ID_TIPO_CERTIFICACION,
              EVIDENCIA: c.EVIDENCIA,
              ESTADO: c.ESTADO,
              FECHA_VENCIMIENTO: c.FECHA_VENCIMIENTO 
            },
            { where: { ID_USUARIO_CERTIFICACION: c.ID_USUARIO_CERTIFICACION } }
          );
        })
      );
    }

    if (vCertificaciones.length === 0) {
      certificacionesActuales.forEach(cert => {
        eliminarArchivoSeguro(cert.EVIDENCIA);
      });
      await UsuarioCertificacionHabilitante.destroy({ where: { ID_USUARIO: req.params.id } });

    } else {
      const idsEntrantesCert = vCertificaciones
        .filter(c => c.ID_USUARIO_CERTIFICACION > 0)
        .map(c => c.ID_USUARIO_CERTIFICACION);

      if (idsEntrantesCert.length > 0) {
        const aEliminarCert = certificacionesActuales.filter(
          c => !idsEntrantesCert.includes(c.ID_USUARIO_CERTIFICACION)
        );

        aEliminarCert.forEach(cert => {
          eliminarArchivoSeguro(cert.EVIDENCIA);
        });

        const idsAEliminarCert = aEliminarCert.map(c => c.ID_USUARIO_CERTIFICACION);

        if (idsAEliminarCert.length > 0) {
          await UsuarioCertificacionHabilitante.destroy({
            where: {
              ID_USUARIO: req.params.id,
              ID_USUARIO_CERTIFICACION: { [Op.in]: idsAEliminarCert }
            }
          });
        }
      }
    }

    if (usuarioActualizado) {
      return res.status(200).send({ message: 'Transaccion realizada exitosamente' });
    } else {
      return res.status(402).send({ message: 'No se ha podido actualizar el usuario' });
    }
  } catch (e) {
    return res.status(500).send({ message: e.name });
  }
}


// Función para obtener el catálogo de tipos de vacunas
async function listarTiposVacunas(req, res) {
  try {
    const tiposVacunas = await TipoVacuna.findAll({
      where: { ESTADO: 1 },
      order: [['NOMBRE', 'ASC']]
    });

    return res.status(200).send(tiposVacunas);
  } catch (e) {
    console.log(e);
    return res.status(500).send({
      message: e.name
    });
  }
}

// Función para obtener el catálogo de tipos de certificaciones habilitantes
async function listarTiposCertificacionesHabilitantes(req, res) {
  try {
    const tiposCertificaciones = await TipoCertificacionHabilitante.findAll({
      where: { ESTADO: true },
      order: [['NOMBRE', 'ASC']]
    });

    return res.status(200).send(tiposCertificaciones);
  } catch (e) {
    console.log(e);
    return res.status(500).send({
      message: e.name
    });
  }
}
//experiencia laboral 
async function registrarExperienciaLaboral(req, res) {
    try {
        let params = JSON.parse(req.body.experienciaLaboral);
        let experiencia = Experiencia_Laboral.build();
        experiencia.ID_USUARIO = params.ID_USUARIO;
        experiencia.CARGO = toUpper(params.CARGO);
        experiencia.FUNCIONES = toUpper(params.FUNCIONES);
        experiencia.FECHA_INICIO = params.FECHA_INICIO;
        experiencia.FECHA_FIN = params.FECHA_FIN;
        
        if (req.file) {
            experiencia.ARCHIVO_DOCUMENTO = `uploads/experienciaLaboral/${req.file.filename}`;
        }
        
        experiencia.FECHA_REGISTRO = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate();

        let experienciaGuardada = await experiencia.save();
        if (experienciaGuardada) {
            res.status(200).send({
                message: 'Registrado exitosamente',
                data: experienciaGuardada
            });
        } else {
            if (req.file) {
                eliminarArchivoSeguro(`uploads/experienciaLaboral/${req.file.filename}`);
            }
            res.status(402).send({
                message: 'No se ha podido registrar sus datos intenta nuevamente'
            });
        }

    } catch (e) {
        if (req.file) {
            eliminarArchivoSeguro(`uploads/experienciaLaboral/${req.file.filename}`);
        }
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}

async function obtenerExperienciasLaborales(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let mul = limit * offset;
        let experienciasEncontradas;
        
        if (mul == 0) { mul = offset; }
        
        experienciasEncontradas = await Experiencia_Laboral.findAll({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { CARGO: { [Op.substring]: buscar } },
                            { FUNCIONES: { [Op.substring]: buscar } },
                        ]
                    }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['ID_EXPERIENCIA_LABORAL', 'DESC']]
        });
        
        res.status(200).send({
            data: experienciasEncontradas
        });

    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}

async function contarTotalExperienciasLaborales(req, res) {
    try {
        let buscar = req.body.palabra;
        let contadorExperienciasEncontradas;
        
        contadorExperienciasEncontradas = await Experiencia_Laboral.count({
            where: {
                [Op.and]: [
                    {
                        ID_USUARIO: req.params.id
                    },
                    {
                        [Op.or]: [
                            { CARGO: { [Op.substring]: buscar } },
                            { FUNCIONES: { [Op.substring]: buscar } },
                        ]
                    }
                ]
            },
        });

        res.status(200).send({
            data: contadorExperienciasEncontradas
        });

    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}

async function obtenerExperienciaLaboral(req, res) {
    try {
        const experienciaEncontrada = await Experiencia_Laboral.findOne({
            where: { ID_EXPERIENCIA_LABORAL: req.params.id },
        });
        
        if (experienciaEncontrada) {
            res.status(200).send({
                data: experienciaEncontrada,
            });
        } else {
            res.status(402).send({
                message: 'No existe experiencia laboral'
            });
        }

    } catch (e) {
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}

async function actualizarExperienciaLaboral(req, res) {
    try {
        let params = JSON.parse(req.body.experienciaLaboral);

        let experienciaActual = await Experiencia_Laboral.findOne({
            where: { ID_EXPERIENCIA_LABORAL: req.params.id }
        });
        let experienciaPorActualizar = {
            CARGO: toUpper(params.CARGO),
            FUNCIONES: toUpper(params.FUNCIONES),
            FECHA_INICIO: params.FECHA_INICIO,
            FECHA_FIN: params.FECHA_FIN,
            FECHA_REGISTRO: moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate()
        };

        if (req.file) {
        // Eliminar archivo anterior si existe
        if (experienciaActual.ARCHIVO_DOCUMENTO && fs.existsSync(experienciaActual.ARCHIVO_DOCUMENTO)) {
            eliminarArchivoSeguro(experienciaActual.ARCHIVO_DOCUMENTO);
        }
        experienciaPorActualizar.ARCHIVO_DOCUMENTO = `uploads/experienciaLaboral/${req.file.filename}`;
        } 
        // Si el usuario eliminó el archivo (viene como string vacío '')
        else if (params.ARCHIVO_DOCUMENTO === '') {
            // Eliminar el archivo físico si existe
            if (experienciaActual.ARCHIVO_DOCUMENTO && fs.existsSync(experienciaActual.ARCHIVO_DOCUMENTO)) {
                eliminarArchivoSeguro(experienciaActual.ARCHIVO_DOCUMENTO);
            }
            // Limpiar el campo en la base de datos
            experienciaPorActualizar.ARCHIVO_DOCUMENTO = null;
        }

        let experienciaActualizada = await Experiencia_Laboral.update(
            experienciaPorActualizar, 
            { where: { ID_EXPERIENCIA_LABORAL: req.params.id } }
        );

        if (experienciaActualizada) {
            res.status(200).send({
                message: 'Transacción realizada exitosamente',
            });
        } else {
            if (req.file) {
                eliminarArchivoSeguro(`uploads/experienciaLaboral/${req.file.filename}`);
            }
            res.status(402).send({
                message: 'No se ha podido actualizar la experiencia laboral'
            });
        }

    } catch (e) {
        if (req.file) {
            eliminarArchivoSeguro(`uploads/experienciaLaboral/${req.file.filename}`);
        }
        console.log(e);
        res.status(500).send({
            message: e.name
        });
    }
}

async function eliminarExperienciaLaboral(req, res) {
    try {
        const experiencia = await Experiencia_Laboral.findOne({ 
            where: { ID_EXPERIENCIA_LABORAL: req.params.id } 
        });

        if (!experiencia) {
            return res.status(404).send({
                message: 'No se encontró la experiencia laboral a eliminar',
            });
        }

        // Eliminar el archivo vinculado si existe
        eliminarArchivoSeguro(experiencia.ARCHIVO_DOCUMENTO);

        const experienciaEliminada = await Experiencia_Laboral.destroy({ 
            where: { ID_EXPERIENCIA_LABORAL: req.params.id } 
        });

        if (experienciaEliminada) {
            res.status(200).send({
                message: 'Transacción realizada exitosamente',
            });
        } else {
            res.status(404).send({
                message: 'No se encontró la experiencia laboral a eliminar',
            });
        }
    } catch (error) {
        console.error(error);
        res.status(500).send({
            message: 'Ocurrió un error en el servidor',
            error: error.message
        });
    }
}
//obtenerUsuariosPorJefeArea
async function obtenerUsuariosPorArea(req, res) {
    try {
        let buscar = req.body.palabra;
        let limit = req.body.tamanioLote;
        let offset = req.body.numeroPagina;
        let idArea = req.params.idArea;
        let mul = limit * offset;
        
        if (mul == 0) { mul = offset }
        
        const usuariosEncontrados = await Usuario.findAll({
            include: [{
                model: Historial_Empresa,
                as: 'HISTORIAL_EMPRESA',
                required: true,
                include: [{
                    model: Cargo,
                    required: true,
                    where: { ID_AREA: idArea }
                }]
            }],
            where: {
                [Op.and]: [
                    {
                        [Op.or]: [
                            { ESTADO: 1 },
                            { ESTADO: 0 }
                        ]
                    },
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            subQuery: false,
            distinct: true,
            offset: mul,
            limit: limit,
            order: [['ID_USUARIO', 'DESC']]
        });
        
        res.status(200).send({
            data: usuariosEncontrados
        });

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}

async function contarTotalUsuariosPorArea(req, res) {
    try {
        let buscar = req.body.palabra;
        let idArea = req.params.idArea;
        
        const contadorUsuariosEncontrados = await Usuario.count({
            include: [{
                model: Historial_Empresa,
                as: 'HISTORIAL_EMPRESA',
                required: true,
                include: [{
                    model: Cargo,
                    required: true,
                    where: { ID_AREA: idArea }
                }]
            }],
            where: {
                [Op.and]: [
                    {
                        [Op.or]: [
                            { ESTADO: 1 },
                            { ESTADO: 0 }
                        ]
                    },
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            distinct: true
        });

        res.status(200).send({
            data: contadorUsuariosEncontrados
        });

    } catch (e) {
        console.log(e)
        res.status(500).send({
            message: e.name
        });
    }
}
//IDIOMA
async function obtenerIdiomasUsuario(req, res) {
    try {
        const idiomasEncontrados = await Idioma.findAll({
            where: { ID_USUARIO: req.params.id },
            order: [['NOMBRE', 'ASC']]
        });

        res.status(200).json({
            ok: true,
            message: 'Idiomas obtenidos exitosamente',
            data: idiomasEncontrados
        });

    } catch (error) {
        console.log('Error al obtener idiomas:', error);
        res.status(500).json({
            ok: false,
            message: 'Error al obtener idiomas del usuario',
            error: error.message
        });
    }
}

// Obtener un idioma específico
async function obtenerIdiomaUsuario(req, res) {
    try {
        const idiomaEncontrado = await Idioma.findOne({
            where: { ID_IDIOMA: req.params.idIdioma }
        });

        if (!idiomaEncontrado) {
            return res.status(404).json({
                ok: false,
                message: 'Idioma no encontrado'
            });
        }

        res.status(200).json({
            ok: true,
            message: 'Idioma obtenido exitosamente',
            data: idiomaEncontrado
        });

    } catch (error) {
        console.log('Error al obtener idioma:', error);
        res.status(500).json({
            ok: false,
            message: 'Error al obtener idioma',
            error: error.message
        });
    }
}

// Registrar un nuevo idioma para el usuario
async function registrarIdiomaUsuario(req, res) {
    try {
        const params = req.body;

        // Validar que exista el usuario
        const usuario = await Usuario.findByPk(params.ID_USUARIO);
        if (!usuario) {
            return res.status(404).json({
                ok: false,
                message: 'Usuario no encontrado'
            });
        }

        // Validar que el idioma no esté vacío
        if (!params.NOMBRE || params.NOMBRE.trim() === '') {
            return res.status(400).json({
                ok: false,
                message: 'El idioma es requerido'
            });
        }

        // Validar que al menos tenga un nivel en alguna habilidad
        if (!params.NIVEL_COMPRENDE && !params.NIVEL_LEE && 
            !params.NIVEL_HABLA && !params.NIVEL_ESCRIBE) {
            return res.status(400).json({
                ok: false,
                message: 'Debe seleccionar al menos un nivel de habilidad'
            });
        }

        // Verificar si el idioma ya existe para este usuario
        const idiomaExistente = await Idioma.findOne({
            where: { 
                ID_USUARIO: params.ID_USUARIO,
                NOMBRE: params.NOMBRE
            }
        });

        if (idiomaExistente) {
            return res.status(400).json({
                ok: false,
                message: 'Este idioma ya está registrado para el usuario'
            });
        }

        // Crear el nuevo registro
        let idioma = Idioma.build();
        idioma.ID_USUARIO = params.ID_USUARIO;
        idioma.NOMBRE = params.NOMBRE;
        idioma.NIVEL_COMPRENDE = params.NIVEL_COMPRENDE || null;
        idioma.NIVEL_LEE = params.NIVEL_LEE || null;
        idioma.NIVEL_HABLA = params.NIVEL_HABLA || null;
        idioma.NIVEL_ESCRIBE = params.NIVEL_ESCRIBE || null;
        idioma.FECHA_REGISTRO = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate();
        idioma.FECHA_ACTUALIZACION = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate();

        const idiomaGuardado = await idioma.save();

        res.status(201).json({
            ok: true,
            message: 'Idioma registrado exitosamente',
            data: idiomaGuardado
        });

    } catch (error) {
        console.log('Error al registrar idioma:', error);
        res.status(500).json({
            ok: false,
            message: 'Error al registrar idioma del usuario',
            error: error.message
        });
    }
}

// Actualizar un idioma existente
async function actualizarIdiomaUsuario(req, res) {
    try {
        const idIdioma = req.params.idIdioma;
        const params = req.body;

        // Validar que exista el idioma
        const idioma = await Idioma.findByPk(idIdioma);
        if (!idioma) {
            return res.status(404).json({
                ok: false,
                message: 'Idioma no encontrado'
            });
        }

        // Validar que al menos tenga un nivel en alguna habilidad
        if (!params.NIVEL_COMPRENDE && !params.NIVEL_LEE && 
            !params.NIVEL_HABLA && !params.NIVEL_ESCRIBE) {
            return res.status(400).json({
                ok: false,
                message: 'Debe seleccionar al menos un nivel de habilidad'
            });
        }

        // Preparar datos para actualizar
        let idiomaPorActualizar = {
            NIVEL_COMPRENDE: params.NIVEL_COMPRENDE || null,
            NIVEL_LEE: params.NIVEL_LEE || null,
            NIVEL_HABLA: params.NIVEL_HABLA || null,
            NIVEL_ESCRIBE: params.NIVEL_ESCRIBE || null,
            FECHA_ACTUALIZACION: moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate()
        };

        // Actualizar el registro
        const idiomaActualizado = await Idioma.update(idiomaPorActualizar, {
            where: { ID_IDIOMA: idIdioma }
        });

        if (idiomaActualizado) {
            res.status(200).json({
                ok: true,
                message: 'Idioma actualizado exitosamente'
            });
        } else {
            res.status(400).json({
                ok: false,
                message: 'No se pudo actualizar el idioma'
            });
        }

    } catch (error) {
        console.log('Error al actualizar idioma:', error);
        res.status(500).json({
            ok: false,
            message: 'Error al actualizar idioma del usuario',
            error: error.message
        });
    }
}

// Eliminar un idioma
async function eliminarIdiomaUsuario(req, res) {
    try {
        const idIdioma = req.params.idIdioma;

        // Validar que exista el idioma
        const idioma = await Idioma.findByPk(idIdioma);
        if (!idioma) {
            return res.status(404).json({
                ok: false,
                message: 'Idioma no encontrado'
            });
        }

        // Eliminar el registro
        const idiomaEliminado = await Idioma.destroy({
            where: { ID_IDIOMA: idIdioma }
        });

        if (idiomaEliminado) {
            res.status(200).json({
                ok: true,
                message: 'Idioma eliminado exitosamente'
            });
        } else {
            res.status(404).json({
                ok: false,
                message: 'No se encontró el idioma a eliminar'
            });
        }

    } catch (error) {
        console.log('Error al eliminar idioma:', error);
        res.status(500).json({
            ok: false,
            message: 'Error al eliminar idioma del usuario',
            error: error.message
        });
    }
}

//LISTAR USUARIOS
async function obtenerUsuariosActivos(req, res) {
    try {
        const usuariosActivos = await Usuario.findAll({
            where: { 
                ESTADO: 1 
            },
            attributes: ['ID_USUARIO', 'NOMBRES', 'APELLIDOS'],
            order: [['APELLIDOS', 'ASC'], ['NOMBRES', 'ASC']]
        });

        const usuariosFormateados = usuariosActivos.map(usuario => ({
            ID_USUARIO: usuario.ID_USUARIO,
            NOMBRE_COMPLETO: `${usuario.NOMBRES} ${usuario.APELLIDOS}`,
            IDENTIFICACION: usuario.IDENTIFICACION
        }));

        res.status(200).send({
            data: usuariosFormateados
        });

    } catch (e) {
        console.log('Error obtenerUsuariosActivos:', e);
        res.status(500).send({
            message: e.name
        });
    }
}

// REPORTE OPTIMIZADO DE VACUNAS
async function obtenerReporteVacunas(req, res) {
    try {
        // Obtener todos los usuarios activos
        const usuarios = await Usuario.findAll({
            where: {
                [Op.and]: [
                    { ESTADO: { [Op.in]: [1, 2] } }
                ]
            },
            include: [
                {
                    model: VacunaUsuario,
                    as: 'VACUNAS',
                    required: false,
                    where: { ESTADO: true },
                    include: [
                        {
                            model: TipoVacuna,
                            required: false
                        }
                    ]
                }
            ],
            order: [['NOMBRES', 'ASC'], ['APELLIDOS', 'ASC']]
        });

        // Obtener todos los tipos de vacunas
        const tiposVacunas = await TipoVacuna.findAll({
            where: { ESTADO: true },
            order: [['ID_TIPO_VACUNA', 'ASC']]
        });

        const hoy = new Date();
        hoy.setHours(0, 0, 0, 0);

        // Procesar cada usuario
        const usuariosConEstado = usuarios.map(usuario => {
            const vacunasUsuario = usuario.VACUNAS || [];

            let tieneVacunasAplicadas = false;
            let tieneVacunasProximas = false; // 0-30 días
            let tieneVacunasVencidas = false;

            // Procesar cada tipo de vacuna
            tiposVacunas.forEach(tipoVacuna => {
                const vacunasTipo = vacunasUsuario.filter(v => v.ID_TIPO_VACUNA === tipoVacuna.ID_TIPO_VACUNA);

                // Verificar si tiene dosis aplicadas de este tipo
                const dosisAplicadas = vacunasTipo.filter(v => v.FECHA_APLICACION);

                if (dosisAplicadas.length > 0) {
                    tieneVacunasAplicadas = true;
                }

                // Verificar esquema completo vs incompleto
                const numeroDosisTipo = tipoVacuna.NUMERO_DOSIS || 0;
                const esquemaCompleto = dosisAplicadas.length >= numeroDosisTipo;

                if (dosisAplicadas.length > 0) {
                    // Tiene al menos una dosis aplicada

                    // Buscar la dosis más reciente con fecha próxima
                    let dosisConFechaProxima = dosisAplicadas
                        .filter(v => v.FECHA_PROXIMA_DOSIS)
                        .sort((a, b) => new Date(b.FECHA_APLICACION) - new Date(a.FECHA_APLICACION));

                    if (dosisConFechaProxima.length > 0) {
                        const ultimaDosis = dosisConFechaProxima[0];
                        const fechaProxima = new Date(ultimaDosis.FECHA_PROXIMA_DOSIS);
                        fechaProxima.setHours(0, 0, 0, 0);
                        const diff = fechaProxima.getTime() - hoy.getTime();
                        const dias = Math.ceil(diff / (1000 * 60 * 60 * 24));

                        if (dias < 0) {
                            // Tiene dosis vencida
                            tieneVacunasVencidas = true;
                        } else if (dias <= 30) {
                            // Tiene dosis próxima a vencer
                            tieneVacunasProximas = true;
                        }
                    }

                    // Si el esquema está incompleto, verificar si hay dosis pendientes vencidas
                    if (!esquemaCompleto && (tipoVacuna.ID_TIPO_VACUNA === 4 || tipoVacuna.ID_TIPO_VACUNA === 5)) {
                        // Para Hepatitis A y B (ID 4 y 5) que tienen esquemas con fechas recomendadas
                        const ultimaDosisAplicada = dosisAplicadas
                            .sort((a, b) => a.NUMERO_DOSIS - b.NUMERO_DOSIS)
                            [dosisAplicadas.length - 1];

                        if (ultimaDosisAplicada && ultimaDosisAplicada.FECHA_APLICACION) {
                            const fechaUltimaDosis = new Date(ultimaDosisAplicada.FECHA_APLICACION);

                            // Calcular fecha recomendada para la siguiente dosis
                            let mesesRecomendados = 0;
                            const siguienteDosis = ultimaDosisAplicada.NUMERO_DOSIS + 1;

                            if (tipoVacuna.ID_TIPO_VACUNA === 4) {
                                // Hepatitis B: 2da dosis (1 mes), 3ra dosis (6 meses), 4ta dosis (12 meses)
                                if (siguienteDosis === 2) mesesRecomendados = 1;
                                else if (siguienteDosis === 3) mesesRecomendados = 6;
                                else if (siguienteDosis === 4) mesesRecomendados = 12;
                            } else if (tipoVacuna.ID_TIPO_VACUNA === 5) {
                                // Hepatitis A: 2da dosis (1 mes), 3ra dosis (6 meses)
                                if (siguienteDosis === 2) mesesRecomendados = 1;
                                else if (siguienteDosis === 3) mesesRecomendados = 6;
                            }

                            if (mesesRecomendados > 0 && siguienteDosis <= numeroDosisTipo) {
                                const fechaRecomendada = new Date(fechaUltimaDosis);
                                fechaRecomendada.setMonth(fechaRecomendada.getMonth() + mesesRecomendados);
                                fechaRecomendada.setHours(0, 0, 0, 0);

                                const diff = fechaRecomendada.getTime() - hoy.getTime();
                                const dias = Math.ceil(diff / (1000 * 60 * 60 * 24));

                                if (dias < 0) {
                                    // La dosis recomendada está vencida
                                    tieneVacunasVencidas = true;
                                } else if (dias <= 30) {
                                    // La dosis recomendada está próxima
                                    tieneVacunasProximas = true;
                                }
                            }
                        }
                    }
                }
            });

            // Si no tiene ninguna vacuna aplicada, considerarlo como vencido
            if (!tieneVacunasAplicadas) {
                tieneVacunasVencidas = true;
            }

            return {
                ID_USUARIO: usuario.ID_USUARIO,
                IDENTIFICACION: usuario.IDENTIFICACION,
                NOMBRES: usuario.NOMBRES,
                APELLIDOS: usuario.APELLIDOS,
                TIENE_VACUNAS_APLICADAS: tieneVacunasAplicadas,
                TIENE_VACUNAS_PROXIMAS: tieneVacunasProximas,
                TIENE_VACUNAS_VENCIDAS: tieneVacunasVencidas
            };
        });

        res.status(200).send({
            data: usuariosConEstado
        });

    } catch (e) {
        console.log('Error obtenerReporteVacunas:', e);
        res.status(500).send({
            message: e.name || 'Error al obtener reporte de vacunas'
        });
    }
}

// Exportar usuarios completos para Excel
async function exportarUsuariosCompletos(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado;

        // Construir condición de estado dinámicamente
        let estadoCondicion;
        if (estado !== null && estado !== undefined) {
            estadoCondicion = { ESTADO: estado };
        } else {
            estadoCondicion = {
                [Op.or]: [
                    { ESTADO: 1 },
                    { ESTADO: 0 }
                ]
            };
        }

        const usuarios = await Usuario.findAll({
            where: {
                [Op.and]: [
                    estadoCondicion,
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            include: [
                {
                    model: Canton,
                    required: false,
                    include: [
                        {
                            model: Provincia,
                            as: 'PROVINCIA',
                            required: false
                        }
                    ]
                },
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false,
                    include: [
                        {
                            model: Cargo,
                            required: false,
                            include: [
                                {
                                    model: Area,
                                    required: false
                                }
                            ]
                        }
                    ]
                },
                {
                    model: Carga_Familiar,
                    as: 'CARGA_FAMILIAR',
                    required: false
                },
                {
                    model: Capacitacion,
                    as: 'CAPACITACION',   // o el alias exacto que definiste
                    required: false
                },
                {
                    model: Estudio,
                    as: 'ESTUDIO',
                    required: false
                },
                {
                    model: Licencia,
                    as: 'LICENCIA',
                    required: false,
                    where: {
                        ESTADO: true,
                        FECHA_CADUCIDAD: {
                        [Op.gte]: new Date()
                        }
                    },
                    limit: 1,
                    order: [['FECHA_CADUCIDAD', 'DESC']]
                }
            ],
            order: [['ID_USUARIO', 'DESC']]
        });

        res.status(200).send({
            data: usuarios
        });

    } catch (e) {
        console.log('Error exportarUsuariosCompletos:', e);
        res.status(500).send({
            message: e.name || 'Error al exportar usuarios'
        });
    }
}

// Obtener Avisos de Entrada IESS (usuarios con historial de ingreso reciente)
async function obtenerAvisosEntrada(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado || null;
        let anio = req.body.anio || new Date().getFullYear();
        let mes = req.body.mes || null;
        let numeroPagina = req.body.numeroPagina || 0;
        let tamanioLote = req.body.tamanioLote || 10;

        // Buscar condiciones para usuario
        let usuarioWhere = {};
        if (buscar) {
            usuarioWhere = {
                [Op.or]: [
                    { NOMBRES: { [Op.like]: `%${buscar}%` } },
                    { APELLIDOS: { [Op.like]: `%${buscar}%` } },
                    { IDENTIFICACION: { [Op.like]: `%${buscar}%` } }
                ]
            };
        }

        // Filtro por estado del usuario
        if (estado === 'OK') {
            usuarioWhere.ESTADO = 1;
        } else if (estado === 'PENDIENTE') {
            usuarioWhere.ESTADO = { [Op.ne]: 1 };
        }

        // Filtrar por año y mes
        let fechaIngresoFilter;
        if (anio && mes) {
            const mesPad = String(mes).padStart(2, '0');
            fechaIngresoFilter = { [Op.like]: `%${anio}-${mesPad}%` };
        } else {
            fechaIngresoFilter = { [Op.like]: `%${anio}%` };
        }

        // Obtener historiales de entrada del año especificado
        const historiales = await Historial_Empresa.findAll({
            where: {
                ESTADO: true,
                FECHA_INGRESO: fechaIngresoFilter
            },
            include: [
                {
                    model: Usuario,
                    as: 'USUARIO',
                    where: usuarioWhere,
                    required: true
                },
                {
                    model: Cargo,
                    required: false,
                    include: [{ model: Area, required: false }]
                }
            ],
            order: [['FECHA_INGRESO', 'DESC']],
            offset: numeroPagina * tamanioLote,
            limit: tamanioLote
        });

        // Obtener IDs de usuarios para buscar evaluaciones
        const usuarioIds = historiales.map(h => h.USUARIO?.ID_USUARIO).filter(Boolean);

        // Buscar evaluaciones de desempeno para estos usuarios
        let evaluaciones = [];
        if (usuarioIds.length > 0) {
            evaluaciones = await EvaluacionDesempeno.findAll({
                where: {
                    ID_USUARIO: { [Op.in]: usuarioIds }
                },
                order: [['FECHA_EVALUACION', 'ASC']]
            });
        }

        // Procesar datos para el formato de avisos de entrada
        const avisosEntrada = historiales.map((historial, index) => {
            const usuario = historial.USUARIO;
            const cargo = historial.CARGO;
            const area = cargo?.AREA;

            const esReingreso = historial.TIPO_INGRESO === 'REINGRESO' ? 'SI' : 'NO';

            // Buscar evaluaciones del usuario
            const evalUsuario = evaluaciones.filter(e => e.ID_USUARIO === usuario?.ID_USUARIO);

            // Evaluacion 85 dias (~3 meses): buscar evaluacion TRIMESTRAL cercana a ingreso+85 dias
            let evaluacion85 = '';
            let evaluacion355 = '';

            if (historial.FECHA_INGRESO && evalUsuario.length > 0) {
                const fechaIngreso = new Date(historial.FECHA_INGRESO);
                if (!isNaN(fechaIngreso.getTime())) {
                    const fecha85 = new Date(fechaIngreso);
                    fecha85.setDate(fecha85.getDate() + 85);
                    const fecha355 = new Date(fechaIngreso);
                    fecha355.setDate(fecha355.getDate() + 355);

                    // Buscar evaluacion cercana a 85 dias (tolerancia de 30 dias)
                    for (const ev of evalUsuario) {
                        const fechaEval = new Date(ev.FECHA_EVALUACION);
                        const diff85 = Math.abs(fechaEval - fecha85) / (1000 * 60 * 60 * 24);
                        const diff355 = Math.abs(fechaEval - fecha355) / (1000 * 60 * 60 * 24);

                        if (diff85 <= 30 && !evaluacion85) {
                            evaluacion85 = ev.CALIFICACION ? `${ev.CALIFICACION}` : '';
                        }
                        if (diff355 <= 30 && !evaluacion355) {
                            evaluacion355 = ev.CALIFICACION ? `${ev.CALIFICACION}` : '';
                        }
                    }
                }
            }

            return {
                numero: (numeroPagina * tamanioLote) + index + 1,
                cedula: usuario?.IDENTIFICACION || '',
                nombreApellido: `${usuario?.APELLIDOS || ''} ${usuario?.NOMBRES || ''}`.trim(),
                reingresoSiNo: esReingreso,
                codigoSectorial: usuario?.CODIGO_SECTORIAL || '',
                cargoIess: usuario?.CARGO_IESS || '',
                encuentraEmpleo: usuario?.ENCUENTRA_EMPLEO || '',
                procedencia: area?.DESCRIPCION || usuario?.LUGAR_RESIDENCIA || '',
                fechaEntrada: historial.FECHA_INGRESO || '',
                fechaSalida: historial.FECHA_SALIDA || '',
                sueldo: historial.SALARIO ? `$${historial.SALARIO}` : '',
                estado: usuario?.ESTADO === 1 ? 'OK' : 'PENDIENTE',
                realizado: usuario?.ESTADO === 1 ? 'CP' : '',
                contratoLegalizado: historial.ARCHIVO_CONTRATO ? 'SI' : 'NO',
                ingresoSofia: historial.INGRESO_SOFIA ? 'SI' : 'NO',
                fechaEvaluacion85Dias: calcularFechaEvaluacion(historial.FECHA_INGRESO, 85),
                evaluacion85: evaluacion85,
                fechaEvaluacion355Dias: calcularFechaEvaluacion(historial.FECHA_INGRESO, 355),
                evaluacion355: evaluacion355,
                novedad: historial.OBSERVACION || '',
                codigoContrato: historial.CODIGO_CONTRATO || '',
                codigoHash: historial.CODIGO_HASH || ''
            };
        });

        res.status(200).send({
            data: avisosEntrada
        });

    } catch (e) {
        console.log('Error obtenerAvisosEntrada:', e);
        res.status(500).send({
            message: e.message || 'Error al obtener avisos de entrada'
        });
    }
}

// Función auxiliar para calcular fecha de evaluación
function calcularFechaEvaluacion(fechaIngreso, dias) {
    if (!fechaIngreso) return '';
    try {
        const fecha = new Date(fechaIngreso);
        if (isNaN(fecha.getTime())) return '';
        fecha.setDate(fecha.getDate() + dias);
        return fecha.toLocaleDateString('es-EC');
    } catch (e) {
        return '';
    }
}

// Contar total de avisos de entrada
async function contarAvisosEntrada(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado || null;
        let anio = req.body.anio || new Date().getFullYear();
        let mes = req.body.mes || null;

        let usuarioWhere = {};
        if (buscar) {
            usuarioWhere = {
                [Op.or]: [
                    { NOMBRES: { [Op.like]: `%${buscar}%` } },
                    { APELLIDOS: { [Op.like]: `%${buscar}%` } },
                    { IDENTIFICACION: { [Op.like]: `%${buscar}%` } }
                ]
            };
        }

        if (estado === 'OK') {
            usuarioWhere.ESTADO = 1;
        } else if (estado === 'PENDIENTE') {
            usuarioWhere.ESTADO = { [Op.ne]: 1 };
        }

        // Filtrar por año y mes
        let fechaIngresoFilter;
        if (anio && mes) {
            const mesPad = String(mes).padStart(2, '0');
            fechaIngresoFilter = { [Op.like]: `%${anio}-${mesPad}%` };
        } else {
            fechaIngresoFilter = { [Op.like]: `%${anio}%` };
        }

        const total = await Historial_Empresa.count({
            where: {
                ESTADO: true,
                FECHA_INGRESO: fechaIngresoFilter
            },
            include: [
                {
                    model: Usuario,
                    as: 'USUARIO',
                    where: usuarioWhere,
                    required: true
                }
            ]
        });

        res.status(200).send({
            data: total
        });

    } catch (e) {
        console.log('Error contarAvisosEntrada:', e);
        res.status(500).send({
            message: e.message || 'Error al contar avisos de entrada'
        });
    }
}

// Obtener Avisos de Salida IESS
async function obtenerAvisosSalida(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado || null;
        let novedad = req.body.novedad;
        let anio = req.body.anio || new Date().getFullYear();
        let mes = req.body.mes || null;
        let numeroPagina = req.body.numeroPagina || 0;
        let tamanioLote = req.body.tamanioLote || 10;

        // Construir condiciones
        let whereHistorial = {
            FECHA_SALIDA: {
                [Op.and]: [
                    { [Op.ne]: null },
                    { [Op.ne]: '' }
                ]
            }
        };

        // Filtrar por año y mes si se especifica
        if (anio && mes) {
            const mesPad = String(mes).padStart(2, '0');
            whereHistorial.FECHA_SALIDA = {
                [Op.like]: `%${anio}-${mesPad}%`
            };
        } else if (anio) {
            whereHistorial.FECHA_SALIDA = {
                [Op.like]: `%${anio}%`
            };
        }

        if (novedad) {
            whereHistorial.MOTIVO_SALIDA = novedad;
        }

        // Filtro por estado (basado en ACTA_FINIQUITO)
        if (estado === 'OK') {
            whereHistorial.ACTA_FINIQUITO = 1;
        } else if (estado === 'PENDIENTE') {
            whereHistorial.ACTA_FINIQUITO = { [Op.or]: [0, null] };
        }

        let usuarioWhere = {};
        if (buscar) {
            usuarioWhere = {
                [Op.or]: [
                    { NOMBRES: { [Op.like]: `%${buscar}%` } },
                    { APELLIDOS: { [Op.like]: `%${buscar}%` } },
                    { IDENTIFICACION: { [Op.like]: `%${buscar}%` } }
                ]
            };
        }

        const historiales = await Historial_Empresa.findAll({
            where: whereHistorial,
            include: [
                {
                    model: Usuario,
                    as: 'USUARIO',
                    where: usuarioWhere,
                    required: true
                },
                {
                    model: Cargo,
                    required: false,
                    include: [{ model: Area, required: false }]
                }
            ],
            order: [['FECHA_SALIDA', 'DESC']],
            offset: numeroPagina * tamanioLote,
            limit: tamanioLote
        });

        // Procesar datos para el formato de avisos de salida
        const avisosSalida = historiales.map((historial, index) => {
            const usuario = historial.USUARIO;
            const cargo = historial.CARGO;
            const area = cargo?.AREA;

            return {
                numero: (numeroPagina * tamanioLote) + index + 1,
                cedula: usuario?.IDENTIFICACION || '',
                nombreApellido: `${usuario?.APELLIDOS || ''} ${usuario?.NOMBRES || ''}`.trim(),
                procedencia: area?.DESCRIPCION || '',
                cargo: cargo?.DESCRIPCION || '',
                fechaSalida: historial.FECHA_SALIDA || '',
                estado: historial.ACTA_FINIQUITO ? 'OK' : 'PENDIENTE',
                realizado: 'SL',
                actaFiniquito: historial.ACTA_FINIQUITO ? 'SI' : 'NO',
                novedad: historial.MOTIVO_SALIDA || ''
            };
        });

        res.status(200).send({
            data: avisosSalida
        });

    } catch (e) {
        console.log('Error obtenerAvisosSalida:', e);
        res.status(500).send({
            message: e.message || 'Error al obtener avisos de salida'
        });
    }
}

// Contar total de avisos de salida
async function contarAvisosSalida(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado || null;
        let novedad = req.body.novedad;
        let anio = req.body.anio || new Date().getFullYear();
        let mes = req.body.mes || null;

        let whereHistorial = {};

        // Filtrar por año y mes
        if (anio && mes) {
            const mesPad = String(mes).padStart(2, '0');
            whereHistorial.FECHA_SALIDA = {
                [Op.like]: `%${anio}-${mesPad}%`
            };
        } else if (anio) {
            whereHistorial.FECHA_SALIDA = {
                [Op.like]: `%${anio}%`
            };
        }

        if (novedad) {
            whereHistorial.MOTIVO_SALIDA = novedad;
        }

        // Filtro por estado (basado en ACTA_FINIQUITO)
        if (estado === 'OK') {
            whereHistorial.ACTA_FINIQUITO = 1;
        } else if (estado === 'PENDIENTE') {
            whereHistorial.ACTA_FINIQUITO = { [Op.or]: [0, null] };
        }

        let usuarioWhere = {};
        if (buscar) {
            usuarioWhere = {
                [Op.or]: [
                    { NOMBRES: { [Op.like]: `%${buscar}%` } },
                    { APELLIDOS: { [Op.like]: `%${buscar}%` } },
                    { IDENTIFICACION: { [Op.like]: `%${buscar}%` } }
                ]
            };
        }

        const total = await Historial_Empresa.count({
            where: whereHistorial,
            include: [
                {
                    model: Usuario,
                    as: 'USUARIO',
                    where: usuarioWhere,
                    required: true
                }
            ]
        });

        res.status(200).send({
            data: total
        });

    } catch (e) {
        console.log('Error contarAvisosSalida:', e);
        res.status(500).send({
            message: e.message || 'Error al contar avisos de salida'
        });
    }
}
// Función para calcular días laborados entre dos fechas (JavaScript puro)
function calcularDiasLaborados(fechaInicio, fechaFin) {
    if (!fechaInicio) return 0;
    
    try {
        const inicio = new Date(fechaInicio);
        const fin = fechaFin ? new Date(fechaFin) : new Date();
        
        // Verificar que las fechas sean válidas
        if (isNaN(inicio.getTime()) || isNaN(fin.getTime())) return 0;
        
        const diffTime = Math.abs(fin - inicio);
        const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
        
        return diffDays;
    } catch (error) {
        console.error('Error al calcular días:', error);
        return 0;
    }
}

// Función para formatear fecha a DD/MM/YYYY (JavaScript puro)
function formatearFecha(fecha) {
    if (!fecha) return '';
    
    try {
        const d = new Date(fecha);
        
        // Verificar si la fecha es válida
        if (isNaN(d.getTime())) return '';
        
        const dia = String(d.getDate()).padStart(2, '0');
        const mes = String(d.getMonth() + 1).padStart(2, '0');
        const anio = d.getFullYear();
        
        return `${dia}/${mes}/${anio}`;
    } catch (error) {
        console.error('Error al formatear fecha:', error);
        return '';
    }
}

// Endpoint principal: Obtener reporte de historial laboral
async function obtenerReporteHistorialLaboral(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado;

        // Construir condición de estado
        let estadoCondicion;
        if (estado !== null && estado !== undefined) {
            estadoCondicion = { ESTADO: estado };
        } else {
            estadoCondicion = {
                [Op.or]: [
                    { ESTADO: 1 },
                    { ESTADO: 0 }
                ]
            };
        }

        // Obtener todos los usuarios con sus historiales
        const usuarios = await Usuario.findAll({
            where: {
                [Op.and]: [
                    estadoCondicion,
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            include: [
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false,
                    include: [
                        {
                            model: Cargo,
                            required: false,
                            include: [
                                {
                                    model: Area,
                                    required: false
                                }
                            ]
                        }
                    ]
                }
            ],
            order: [
                ['APELLIDOS', 'ASC'],
                ['NOMBRES', 'ASC']
            ]
        });

        // Procesar datos para el reporte
        const reporte = usuarios.map(usuario => {
            const historiales = usuario.HISTORIAL_EMPRESA || [];
            
            // Ordenar historiales por fecha de ingreso (más antigua primero)
            const historialesOrdenados = historiales.sort((a, b) => {
                return new Date(a.FECHA_INGRESO) - new Date(b.FECHA_INGRESO);
            });

            // Preparar objeto base del reporte
            const registro = {
                IDENTIFICACION: usuario.IDENTIFICACION || '',
                ESTADO_USUARIO: usuario.ESTADO === 1 ? 'ACTIVO' : 'PASIVO',
                NOMBRES_APELLIDOS: `${usuario.APELLIDOS || ''} ${usuario.NOMBRES || ''}`.trim(),
                AREA: '',
                FECHA_PRIMER_INGRESO: '',
                TOTAL_DIAS: 0,
                CUMPLE_ANIO: 'no cumple'
            };

            // Inicializar campos para hasta 8 períodos
            for (let i = 1; i <= 8; i++) {
                registro[`FECHA_INGRESO_${i}`] = '';
                registro[`FECHA_SALIDA_${i}`] = '';
                registro[`DIAS_LABORADOS_${i}`] = 0;
            }

            let totalDias = 0;

            // Procesar cada historial (máximo 8 períodos)
            historialesOrdenados.forEach((historial, index) => {
                if (index >= 8) return; // Máximo 8 períodos

                const numeroPeriodo = index + 1;
                const area = historial.CARGO?.AREA?.DESCRIPCION || '';
                
                // Guardar área del período actual o del más reciente
                if (index === 0) {
                    registro.AREA = area;
                    registro.FECHA_PRIMER_INGRESO = formatearFecha(historial.FECHA_INGRESO);
                }
                
                // Si es el historial activo (ESTADO = true), usar su área
                if (historial.ESTADO) {
                    registro.AREA = area;
                }

                // Asignar fechas del período
                registro[`FECHA_INGRESO_${numeroPeriodo}`] = formatearFecha(historial.FECHA_INGRESO);
                registro[`FECHA_SALIDA_${numeroPeriodo}`] = formatearFecha(historial.FECHA_SALIDA);
                
                // Calcular días laborados
                const diasPeriodo = calcularDiasLaborados(
                    historial.FECHA_INGRESO,
                    historial.FECHA_SALIDA || (historial.ESTADO ? null : historial.FECHA_INGRESO)
                );
                
                registro[`DIAS_LABORADOS_${numeroPeriodo}`] = diasPeriodo;
                totalDias += diasPeriodo;
            });

            registro.TOTAL_DIAS = totalDias;
            
            // Verificar si cumple año (365 días o más)
            if (totalDias >= 365) {
                registro.CUMPLE_ANIO = 'si cumple';
            }

            return registro;
        });

        // Aplicar paginación
        const numeroPagina = req.body.numeroPagina || 0;
        const tamanioLote = req.body.tamanioLote || 10;
        const inicio = numeroPagina * tamanioLote;
        const reportePaginado = reporte.slice(inicio, inicio + tamanioLote);

        res.status(200).send({
            data: reportePaginado,
            message: 'Reporte generado exitosamente'
        });

    } catch (e) {
        console.log('Error obtenerReporteHistorialLaboral:', e);
        res.status(500).send({
            message: e.name || 'Error al generar reporte de historial laboral'
        });
    }
}

// Endpoint para contar total de registros del reporte
async function contarReporteHistorialLaboral(req, res) {
    try {
        let buscar = req.body.palabra || '';
        let estado = req.body.estado;

        let estadoCondicion;
        if (estado !== null && estado !== undefined) {
            estadoCondicion = { ESTADO: estado };
        } else {
            estadoCondicion = {
                [Op.or]: [
                    { ESTADO: 1 },
                    { ESTADO: 0 }
                ]
            };
        }

        const total = await Usuario.count({
            where: {
                [Op.and]: [
                    estadoCondicion,
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            }
        });

        res.status(200).send({
            data: total
        });

    } catch (e) {
        console.log('Error contarReporteHistorialLaboral:', e);
        res.status(500).send({
            message: e.name || 'Error al contar registros del reporte'
        });
    }
}

module.exports = {
    autenticarUsuario,
    registrarUsuario,
    obtenerAreas,
    obtenerCargos,
    obtenerSistemas,
    obtenerRoles,
    obtenerUsuarios,
    contarTotalUsuarios,
    obtenerUsuario,
    actualizarUsuario,
    eliminarRol,
    actualizarEstadoUsuario,
    actualizarContrasenia,
    recuperarContrasenia,
    obtenerMiUsuario,
    actualizarMisDatosPersonales,
    registrarCapacitacion,
    obtenerCapacitaciones,
    contarTotalCapacitaciones,
    obtenerCapacitacion,
    actualizarCapacitacion,
    eliminarCapacitacion,

    registrarEstudio,
    obtenerEstudios,
    contarTotalEstudios,
    obtenerEstudio,
    actualizarEstudio,
    eliminarEstudio,

    registrarCargaFamiliar,
    obtenerCargasFamiliares,
    contarTotalCargasFamiliares,
    obtenerCargaFamiliar,
    actualizarCargaFamiliar,
    eliminarCargaFamiliar,

    obtenerHijosFamiliares,
    contarTotalHijosFamiliares,



    obtenerTodaInformacionUsuario,

    registrarLlamadoAtencion,
    obtenerLlamadosAtencion,
    contarTotalLlamadosAtencion,
    obtenerLlamadoAtencion,
    actualizarLlamadoAtencion,
    actualizarEstadoLlamadoAtencion,

    registrarHistorialEmpresa,
    obtenerHistorialesEmpresa,
    contarTotalHistorialesEmpresa,
    obtenerHistorialEmpresa,
    actualizarHistorialEmpresa,
    eliminarHistorialEmpresa,


    actualizarInformacionHSE,
    listarTiposVacunas,
    listarTiposCertificacionesHabilitantes,

    registrarExperienciaLaboral,
    obtenerExperienciasLaborales,
    contarTotalExperienciasLaborales,
    obtenerExperienciaLaboral,
    actualizarExperienciaLaboral,
    eliminarExperienciaLaboral,

    obtenerIdiomasUsuario,
    obtenerIdiomaUsuario,
    registrarIdiomaUsuario,
    actualizarIdiomaUsuario,
    eliminarIdiomaUsuario,

    contarTotalUsuariosPorArea,
    obtenerUsuariosPorArea,
    obtenerUsuariosActivos,
    obtenerReporteVacunas,
    exportarUsuariosCompletos,

    // Matrices IESS
    obtenerAvisosEntrada,
    contarAvisosEntrada,
    obtenerAvisosSalida,
    contarAvisosSalida,
    obtenerReporteHistorialLaboral,
    contarReporteHistorialLaboral,
};