const fs = require('fs');
const moment = require('moment-timezone');
const { Op } = require('sequelize');
const Usuario = require('../models/usuario');
const Historial_Empresa = require('../models/historial_empresa');
const Cargo = require('../models/cargo');
const Area = require('../models/area');
const EvaluacionDesempeno = require('../models/evaluacion_desempeno');

function sumarMeses(fecha, meses) {
    const f = new Date(fecha.getTime());
    f.setMonth(f.getMonth() + meses);
    return f;
}

function sumarAnios(fecha, anios) {
    const f = new Date(fecha.getTime());
    f.setFullYear(f.getFullYear() + anios);
    return f;
}

function formatearFechaISO(fecha) {
    const year = fecha.getFullYear();
    const month = String(fecha.getMonth() + 1).padStart(2, '0');
    const day = String(fecha.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
}

async function obtenerProximasEvaluaciones(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; }

        const todosLosUsuarios = await Usuario.findAll({
            where: {
                [Op.and]: [
                    { ESTADO: 1 },
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            include: [
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false,
                    where: { ESTADO: true },
                    include: [
                        {
                            model: Cargo,
                            required: false,
                            include: [{
                                model: Area,
                                required: false
                            }]
                        }
                    ]
                }
            ]
        });

        const idsUsuarios = todosLosUsuarios.map(u => u.ID_USUARIO);

        // Obtener todas las evaluaciones y filtrar después
        const todasLasEvaluaciones = await EvaluacionDesempeno.findAll({
            where: { ID_USUARIO: { [Op.in]: idsUsuarios } },
            order: [['FECHA_EVALUACION', 'DESC']]
        });

        const mapaUltimasEvaluaciones = {};
        for (const evaluacion of todasLasEvaluaciones) {
            if (!mapaUltimasEvaluaciones[evaluacion.ID_USUARIO]) {
                // Solo excluir EMERGENCIA si la calificación es < 70%
                // Si EMERGENCIA >= 70%, SÍ cuenta para próximas evaluaciones
                if (evaluacion.TIPO_EVALUACION === 'EMERGENCIA' && evaluacion.CALIFICACION < 70) {
                    continue; // Ignorar esta evaluación
                }
                mapaUltimasEvaluaciones[evaluacion.ID_USUARIO] = evaluacion;
            }
        }

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

        for (const usuario of todosLosUsuarios) {
            const usuarioJSON = usuario.toJSON();

            if (usuarioJSON.HISTORIAL_EMPRESA && usuarioJSON.HISTORIAL_EMPRESA.length > 0) {
                const fechaIngreso = usuarioJSON.HISTORIAL_EMPRESA[0].FECHA_INGRESO;

                if (fechaIngreso) {
                    const fechaIngresoStr = fechaIngreso.substring(0, 10);
                    const [anio, mes, dia] = fechaIngresoStr.split('-');
                    const fechaIngresoDate = new Date(parseInt(anio, 10), parseInt(mes, 10) - 1, parseInt(dia, 10));
                    fechaIngresoDate.setHours(0, 0, 0, 0);

                    const ultimaEval = mapaUltimasEvaluaciones[usuarioJSON.ID_USUARIO];
                    let fechaEvaluacion;
                    let tipoEvaluacion;
                    let mostrarEnReporte = false;

                    if (!ultimaEval) {
                        // NO TIENE EVALUACIÓN - MOSTRAR TODOS SIN IMPORTAR FECHA
                        fechaEvaluacion = sumarMeses(fechaIngresoDate, 3);
                        tipoEvaluacion = 'TRIMESTRAL';
                        
                        fechaEvaluacion.setHours(0, 0, 0, 0);
                        const diffMs = fechaEvaluacion.getTime() - hoy.getTime();
                        const diasHastaEvaluacion = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
                        
                        // MOSTRAR TODOS los usuarios sin evaluación (sin filtro de días)
                        mostrarEnReporte = true;
                        usuarioJSON.DIAS_HASTA_EVALUACION = diasHastaEvaluacion;
                        
                    } else {
                        // TIENE EVALUACIÓN TRIMESTRAL - Mostrar cuando falte 1 mes o menos para el año
                        const fechaUltimaEval = new Date(ultimaEval.FECHA_EVALUACION);
                        fechaUltimaEval.setHours(0, 0, 0, 0);
                        fechaEvaluacion = sumarAnios(fechaUltimaEval, 1);
                        tipoEvaluacion = 'ANUAL';
                        
                        fechaEvaluacion.setHours(0, 0, 0, 0);
                        const diffMs = fechaEvaluacion.getTime() - hoy.getTime();
                        const diasHastaEvaluacion = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
                        
                        // Mostrar solo si falta 1 mes (30 días) o menos (incluye vencidas hasta 30 días atrás)
                        if (diasHastaEvaluacion <= 30 && diasHastaEvaluacion >= -30) {
                            mostrarEnReporte = true;
                            usuarioJSON.DIAS_HASTA_EVALUACION = diasHastaEvaluacion;
                        }
                    }

                    if (mostrarEnReporte) {
                        usuarioJSON.FECHA_INGRESO = fechaIngresoStr;
                        usuarioJSON.FECHA_PROXIMA_EVALUACION = formatearFechaISO(fechaEvaluacion);
                        usuarioJSON.TIPO_EVALUACION = tipoEvaluacion;
                        usuariosConEvaluacion.push(usuarioJSON);
                    }
                }
            }
        }

        // CAMBIO IMPORTANTE: Ordenar de más próximos a más atrasados
        // Primero los que tienen días positivos pequeños (próximos a vencer)
        // Luego los que tienen días negativos (ya vencidos, los más recientes primero)
        usuariosConEvaluacion.sort((a, b) => {
            const diasA = a.DIAS_HASTA_EVALUACION;
            const diasB = b.DIAS_HASTA_EVALUACION;
            
            // Ambos están por vencer o al día
            if (diasA >= 0 && diasB >= 0) {
                return diasA - diasB; // Menor a mayor 
            }
            
            // Ambos están vencidos (negativos)
            if (diasA < 0 && diasB < 0) {
                return diasB - diasA; // Mayor a menor
            }
            
            // Uno vencido y otro no: los próximos a vencer van primero
            return diasA >= 0 ? -1 : 1;
        });
        
        const usuariosPaginados = usuariosConEvaluacion.slice(mul, mul + limit);

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

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

async function contarTotalProximasEvaluaciones(req, res) {
    try {
        let buscar = req.body.palabra || '';

        const usuariosEncontrados = await Usuario.findAll({
            where: {
                [Op.and]: [
                    { ESTADO: 1 },
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            },
            include: [
                {
                    model: Historial_Empresa,
                    as: 'HISTORIAL_EMPRESA',
                    required: false,
                    where: { ESTADO: true }
                }
            ]
        });

        const idsUsuarios = usuariosEncontrados.map(u => u.ID_USUARIO);

        // Obtener todas las evaluaciones y filtrar después
        const todasLasEvaluaciones = await EvaluacionDesempeno.findAll({
            where: { ID_USUARIO: { [Op.in]: idsUsuarios } },
            order: [['FECHA_EVALUACION', 'DESC']]
        });

        const mapaUltimasEvaluaciones = {};
        for (const evaluacion of todasLasEvaluaciones) {
            if (!mapaUltimasEvaluaciones[evaluacion.ID_USUARIO]) {
                // Solo excluir EMERGENCIA si la calificación es < 70%
                // Si EMERGENCIA >= 70%, SÍ cuenta para próximas evaluaciones
                if (evaluacion.TIPO_EVALUACION === 'EMERGENCIA' && evaluacion.CALIFICACION < 70) {
                    continue; // Ignorar esta evaluación
                }
                mapaUltimasEvaluaciones[evaluacion.ID_USUARIO] = evaluacion;
            }
        }

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

        for (const usuario of usuariosEncontrados) {
            if (usuario.HISTORIAL_EMPRESA && usuario.HISTORIAL_EMPRESA.length > 0) {
                const fechaIngreso = usuario.HISTORIAL_EMPRESA[0].FECHA_INGRESO;

                if (fechaIngreso) {
                    const fechaIngresoStr = fechaIngreso.substring(0, 10);
                    const [anio, mes, dia] = fechaIngresoStr.split('-');
                    const fechaIngresoDate = new Date(parseInt(anio, 10), parseInt(mes, 10) - 1, parseInt(dia, 10));
                    fechaIngresoDate.setHours(0, 0, 0, 0);

                    const ultimaEval = mapaUltimasEvaluaciones[usuario.ID_USUARIO];

                    if (!ultimaEval) {
                        contador++;
                    } else {
                        // TIENE EVALUACIÓN - Contar si falta 1 mes o menos
                        const fechaUltimaEval = new Date(ultimaEval.FECHA_EVALUACION);
                        fechaUltimaEval.setHours(0, 0, 0, 0);
                        const fechaEvaluacion = sumarAnios(fechaUltimaEval, 1);
                        fechaEvaluacion.setHours(0, 0, 0, 0);
                        const diffMs = fechaEvaluacion.getTime() - hoy.getTime();
                        const diasHastaEvaluacion = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
                        
                        if (diasHastaEvaluacion <= 30 && diasHastaEvaluacion >= -30) {
                            contador++;
                        }
                    }
                }
            }
        }

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

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

async function obtenerUltimaEvaluacionUsuario(req, res) {
    try {
        const idUsuario = req.params.idUsuario;

        // Obtener todas las evaluaciones del usuario
        const todasLasEvaluaciones = await EvaluacionDesempeno.findAll({
            where: { ID_USUARIO: idUsuario },
            order: [['FECHA_EVALUACION', 'DESC']]
        });

        if (!todasLasEvaluaciones || todasLasEvaluaciones.length === 0) {
            return res.status(404).send({ message: 'No hay evaluaciones previas' });
        }

        // Buscar la última evaluación válida
        // Solo excluir EMERGENCIA si calificación < 70%
        let ultimaEvaluacion = null;
        for (const evaluacion of todasLasEvaluaciones) {
            if (evaluacion.TIPO_EVALUACION === 'EMERGENCIA' && evaluacion.CALIFICACION < 70) {
                continue; // Ignorar EMERGENCIA con calificación < 70%
            }
            ultimaEvaluacion = evaluacion;
            break; // Tomar la primera válida (más reciente)
        }

        if (!ultimaEvaluacion) {
            return res.status(404).send({ message: 'No hay evaluaciones previas' });
        }

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

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

async function registrarEvaluacionUsuario(req, res) {
    try {
        const idUsuario = req.params.idUsuario;
        const entidad = JSON.parse(req.body.entidadEvaluacion);

        const ultimaEvaluacion = await EvaluacionDesempeno.findOne({
            where: { ID_USUARIO: idUsuario },
            order: [['FECHA_EVALUACION', 'DESC']]
        });

        if (!ultimaEvaluacion && entidad.TIPO_EVALUACION !== 'TRIMESTRAL') {
            if (req.file && req.file.filename) {
                fs.unlinkSync(`uploads/evaluaciones/${req.file.filename}`);
            }
            return res.status(400).send({
                message: 'La primera evaluación debe ser TRIMESTRAL (3 meses después del ingreso)'
            });
        }

        // Si es evaluación de EMERGENCIA, no validar nada
        if (entidad.TIPO_EVALUACION === 'EMERGENCIA') {
            // Permitir sin restricciones
        } else if (ultimaEvaluacion && entidad.TIPO_EVALUACION === 'TRIMESTRAL') {
            if (req.file && req.file.filename) {
                fs.unlinkSync(`uploads/evaluaciones/${req.file.filename}`);
            }
            return res.status(400).send({
                message: 'Ya existe una evaluación TRIMESTRAL. Las siguientes deben ser ANUALES.'
            });
        } else if (ultimaEvaluacion && entidad.TIPO_EVALUACION === 'ANUAL') {
            const fechaUltimaEval = new Date(ultimaEvaluacion.FECHA_EVALUACION);
            const fechaNuevaEval = new Date(entidad.FECHA_EVALUACION);

            const diffMs = fechaNuevaEval.getTime() - fechaUltimaEval.getTime();
            const diffDias = Math.floor(diffMs / (1000 * 60 * 60 * 24));

            if (diffDias < 365) {
                if (req.file && req.file.filename) {
                    fs.unlinkSync(`uploads/evaluaciones/${req.file.filename}`);
                }
                return res.status(400).send({
                    message: `Debe esperar al menos 1 año desde la última evaluación. Faltan ${365 - diffDias} días.`
                });
            }
        }

        let archivoRuta = null;
        if (req.file) {
            archivoRuta = `uploads/evaluaciones/${req.file.filename}`;
        }

        const evaluacion = EvaluacionDesempeno.build();
        evaluacion.ID_USUARIO = idUsuario;
        evaluacion.TIPO_EVALUACION = entidad.TIPO_EVALUACION;
        evaluacion.FECHA_EVALUACION = entidad.FECHA_EVALUACION;
        evaluacion.CALIFICACION = entidad.CALIFICACION;
        evaluacion.ARCHIVO_EVALUACION = archivoRuta;
        evaluacion.FECHA_REGISTRO = moment.utc(moment().tz('America/Guayaquil').format('YYYY-MM-DD HH:mm:ss')).toDate();

        const guardada = await evaluacion.save();

        if (guardada) {
            return res.status(200).send({
                message: 'Evaluación registrada exitosamente',
                data: guardada
            });
        } else {
            if (req.file && req.file.filename) {
                fs.unlinkSync(`uploads/evaluaciones/${req.file.filename}`);
            }
            return res.status(402).send({
                message: 'No se ha podido registrar la evaluación'
            });
        }

    } catch (e) {
        console.log('Error registrarEvaluacionUsuario:', e);
        if (req.file && req.file.filename) {
            try {
                fs.unlinkSync(`uploads/evaluaciones/${req.file.filename}`);
            } catch (err) {
                console.log('Error al eliminar archivo:', err);
            }
        }
        res.status(500).send({ message: e.name });
    }
}

async function obtenerEvaluacionesUsuario(req, res) {
    try {
        const idUsuario = req.params.idUsuario;
        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; }

        const evaluacionesEncontradas = await EvaluacionDesempeno.findAll({
            where: {
                ID_USUARIO: idUsuario,
                [Op.or]: [
                    { TIPO_EVALUACION: { [Op.substring]: buscar } },
                    { FECHA_EVALUACION: { [Op.substring]: buscar } }
                ]
            },
            offset: mul,
            limit: limit,
            order: [['FECHA_EVALUACION', 'DESC']]
        });

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

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

async function contarTotalEvaluacionesUsuario(req, res) {
    try {
        const idUsuario = req.params.idUsuario;
        let buscar = req.body.palabra || '';

        const contadorEvaluaciones = await EvaluacionDesempeno.count({
            where: {
                ID_USUARIO: idUsuario,
                [Op.or]: [
                    { TIPO_EVALUACION: { [Op.substring]: buscar } },
                    { FECHA_EVALUACION: { [Op.substring]: buscar } }
                ]
            }
        });

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

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

async function obtenerEvaluacionUsuario(req, res) {
    try {
        const idEvaluacion = req.params.idEvaluacion;

        const evaluacion = await EvaluacionDesempeno.findOne({
            where: { ID_EVALUACION: idEvaluacion }
        });

        if (!evaluacion) {
            return res.status(404).send({ message: 'No existe la evaluación' });
        }

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

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

async function eliminarEvaluacionUsuario(req, res) {
    try {
        const idEvaluacion = req.params.idEvaluacion;

        const evaluacion = await EvaluacionDesempeno.findOne({
            where: { ID_EVALUACION: idEvaluacion }
        });

        if (!evaluacion) {
            return res.status(404).send({ message: 'No se encontró la evaluación' });
        }

        if (evaluacion.ARCHIVO_EVALUACION) {
            try {
                if (fs.existsSync(evaluacion.ARCHIVO_EVALUACION)) {
                    fs.unlinkSync(evaluacion.ARCHIVO_EVALUACION);
                }
            } catch (err) {
                console.log('Error al eliminar PDF de evaluación:', err);
            }
        }

        const eliminado = await EvaluacionDesempeno.destroy({
            where: { ID_EVALUACION: idEvaluacion }
        });

        if (eliminado > 0) {
            return res.status(200).send({ message: 'Evaluación eliminada exitosamente' });
        } else {
            return res.status(404).send({ message: 'No se pudo eliminar la evaluación' });
        }

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

async function obtenerUsuariosEnRiesgo(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; }

        const todosLosUsuarios = await Usuario.findAll({
            where: {
                [Op.and]: [
                    { ESTADO: 1 },
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            }
        });

        const idsUsuarios = todosLosUsuarios.map(u => u.ID_USUARIO);

        const ultimasEvaluaciones = await EvaluacionDesempeno.findAll({
            where: { ID_USUARIO: { [Op.in]: idsUsuarios } },
            order: [['FECHA_EVALUACION', 'DESC']]
        });

        const mapaUltimasEvaluaciones = {};
        for (const evaluacion of ultimasEvaluaciones) {
            if (!mapaUltimasEvaluaciones[evaluacion.ID_USUARIO]) {
                mapaUltimasEvaluaciones[evaluacion.ID_USUARIO] = evaluacion;
            }
        }

        const usuariosEnRiesgo = [];

        for (const usuario of todosLosUsuarios) {
            const usuarioJSON = usuario.toJSON();
            const ultimaEval = mapaUltimasEvaluaciones[usuarioJSON.ID_USUARIO];

            if (ultimaEval && ultimaEval.CALIFICACION < 70) {
                usuarioJSON.CALIFICACION = ultimaEval.CALIFICACION;
                usuarioJSON.TIPO_EVALUACION = ultimaEval.TIPO_EVALUACION;
                usuarioJSON.FECHA_EVALUACION = formatearFechaISO(new Date(ultimaEval.FECHA_EVALUACION));
                usuarioJSON.ID_EVALUACION = ultimaEval.ID_EVALUACION;
                usuarioJSON.NOMBRE_COMPLETO = `${usuarioJSON.NOMBRES} ${usuarioJSON.APELLIDOS}`;
                usuariosEnRiesgo.push(usuarioJSON);
            }
        }

        usuariosEnRiesgo.sort((a, b) => a.CALIFICACION - b.CALIFICACION);

        const usuariosPaginados = usuariosEnRiesgo.slice(mul, mul + limit);

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

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

async function contarTotalUsuariosEnRiesgo(req, res) {
    try {
        let buscar = req.body.palabra || '';

        const usuariosEncontrados = await Usuario.findAll({
            where: {
                [Op.and]: [
                    { ESTADO: 1 },
                    {
                        [Op.or]: [
                            { NOMBRES: { [Op.substring]: buscar } },
                            { APELLIDOS: { [Op.substring]: buscar } },
                            { IDENTIFICACION: { [Op.substring]: buscar } }
                        ]
                    }
                ]
            }
        });

        const idsUsuarios = usuariosEncontrados.map(u => u.ID_USUARIO);

        const ultimasEvaluaciones = await EvaluacionDesempeno.findAll({
            where: { ID_USUARIO: { [Op.in]: idsUsuarios } },
            order: [['FECHA_EVALUACION', 'DESC']]
        });

        const mapaUltimasEvaluaciones = {};
        for (const evaluacion of ultimasEvaluaciones) {
            if (!mapaUltimasEvaluaciones[evaluacion.ID_USUARIO]) {
                mapaUltimasEvaluaciones[evaluacion.ID_USUARIO] = evaluacion;
            }
        }

        let contador = 0;

        for (const usuario of usuariosEncontrados) {
            const ultimaEval = mapaUltimasEvaluaciones[usuario.ID_USUARIO];

            if (ultimaEval && ultimaEval.CALIFICACION < 70) {
                contador++;
            }
        }

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

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

module.exports = {
    obtenerProximasEvaluaciones,
    contarTotalProximasEvaluaciones,
    registrarEvaluacionUsuario,
    obtenerEvaluacionesUsuario,
    contarTotalEvaluacionesUsuario,
    obtenerEvaluacionUsuario,
    eliminarEvaluacionUsuario,
    obtenerUltimaEvaluacionUsuario,
    obtenerUsuariosEnRiesgo,
    contarTotalUsuariosEnRiesgo
};