<?php namespace App\Models;

use CodeIgniter\Model;

class UsuarioModelo extends Model {
/*    protected $table = 'usuario';
    protected $primaryKey = 'id_usuario';
    protected $allowedFields = ['id_usuario','usuario','contrasena','perfil_id','nombres','apellidos','tipo_documento','numero_documento','correo_electronico','token','fecha_caducidad_token','fecha_solicitud_recuperacion','fecha_cambio_contrasena','fecha_registro','fecha_actualizacion','eliminacion_logica'];
*/
    protected $table = 'tblusuario';
    protected $primaryKey = 'IdUsuario';
    protected $allowedFields = ['IdArea','IdPerfil','Matricula','Nombres','Apellidos','TipoDocumento','NumeroDoc','Telefono','Demo','Cargo','Categoria','Instalador','CC','LN','Manager','Correo','Usuario','Password','FechaIngreso','FechaCese','Estado','FTE','Foto','FechaHoraREG','FechaHoraMODIF','RMKT','Token','Estrellas','TCTV','RemarketingTV','TC','Push','Pull','Equipo','RemarketingTC', 'IDCargo', 'IDManager', 'IDSubarea','IDDelegacion', 'brevete', 'numero_placa','UsuarioCrea', 'FechaCrea', 'UsuarioModifica', 'FechaModifica', 'Localhost', 'UsuarioEstado', 'FechaEstado', 'MotivoEstado'];

    public function obtenerUsuario($idUsuario)
    {
        $this->select('tblusuario.*,
            estructura_subarea.IDArea,
            estructura_area.IDDireccion');
        $this->join('estructura_subarea', 'tblusuario.IDSubarea = estructura_subarea.IDSubarea', 'left');
        $this->join('estructura_area', 'estructura_subarea.IDArea = estructura_area.IDArea', 'left');
        $this->join('estructura_direccion', 'estructura_area.IDDireccion = estructura_direccion.IDDireccion', 'left');
        $this->where('tblusuario.IdUsuario', $idUsuario);
        $datos = $this->first();
        return $datos;
    }

    public function validarIngresoUsuario($usuario)
    {
        $this->select('tblusuario.IdUsuario,
            tblusuario.Usuario,
            tblusuario.Nombres,
            tblusuario.Apellidos,
            tblusuario.TipoDocumento,
            tblusuario.NumeroDoc,
            tblusuario.Correo,
            tblusuario.Estado,
            tblusuario.Password,
            tblusuario.IDDelegacion,
            tblusuario.IDSubarea,
            estructura_area.IDArea,
            estructura_area.Area,
            estructura_direccion.IDDireccion,
            estructura_direccion.Direccion,
            estructura_delegacion.CC,
            tblusuario.IDCargo,
            cargos.Cargo');
        $this->join('estructura_delegacion', 'tblusuario.IDDelegacion = estructura_delegacion.IDDelegacion', 'left');
        $this->join('estructura_subarea', 'tblusuario.IDSubarea = estructura_subarea.IDSubarea', 'left');
        $this->join('estructura_area', 'estructura_subarea.IDArea = estructura_area.IDArea', 'left');
        $this->join('estructura_direccion', 'estructura_area.IDDireccion = estructura_direccion.IDDireccion', 'left');
        $this->join('cargos', 'tblusuario.IDCargo = cargos.IDCargo', 'left');
        $this->where('tblusuario.Usuario', $usuario);
        $datos = $this->first();
        return $datos;
    }

    public function validarSistemaUsuario($idUsuario, $raiz)
    {
        $this->select('tblusuario.IdUsuario,
            usuario_sistemas.IDSistema,
            sistemas.Sistema,
            sistemas.Estado');
        $this->join('usuario_sistemas', 'tblusuario.IdUsuario = usuario_sistemas.IdUsuario');
        $this->join('sistemas', 'usuario_sistemas.IDSistema = sistemas.IDSistema');
        $this->where('usuario_sistemas.IdUsuario', $idUsuario);
        $this->where('sistemas.Raiz', $raiz);
        $datos = $this->first();
        return $datos;
    }

    public function listaGeneralUsuario($orderBy,$where,$length,$start) {
        $sSelect = "tblusuario.IdUsuario,CONCAT(tblusuario.Nombres, ' ', tblusuario.Apellidos) as nombre_usuario,tblusuario.Matricula,tblusuario.NumeroDoc, perfil.Perfil AS perfil_usuario, tblusuario.Usuario,tblusuario.Estado, (SELECT GROUP_CONCAT(DISTINCT sistemas.Sistema SEPARATOR '<br>') as grupo FROM usuario_sistemas LEFT JOIN sistemas ON usuario_sistemas.IDSistema = sistemas.IDSistema AND tblusuario.IdUsuario = usuario_sistemas.IdUsuario) AS sistemas, 'SININFO' AS acciones_usuario";
        $sTable = "tblusuario LEFT JOIN usuario_perfil ON tblusuario.IdUsuario = usuario_perfil.IdUsuario LEFT JOIN perfil ON usuario_perfil.IDPerfil = perfil.IDPerfil";
        $whereRespuesta = $where==""?"":"WHERE (".$where ."')";
        $consulta = "SELECT " . $sSelect ." FROM ".  $sTable . " " .$whereRespuesta ."  " . $orderBy . " LIMIT ". $length ." OFFSET " .$start;
        // echo $consulta;
        // exit;
        $obtieneConsulta = $this->db->query($consulta);
        
        $consultaTotal = "SELECT count(IdUsuario) as total FROM tblusuario";
        $totalRegistros = $this->db->query($consultaTotal);
        $obtieneTotalRegistros = $totalRegistros->getResultArray();
        
        if ($obtieneConsulta->getNumRows() > 0) {
            $datos = [
                // 'draw' => "4",
                'data' => $obtieneConsulta->getResultArray(),
                'recordsTotal' => $obtieneTotalRegistros[0]['total'],
                'recordsFiltered' => (int)(($obtieneTotalRegistros[0]['total']*$length)/$length)
            ];
            return $datos;
        } else {
            return FALSE;
        }
    }

    public function buscarUsuario($idUsuario)
    {
        $this->select('tblusuario.IdUsuario,
            tblusuario.Matricula,
            tblusuario.Usuario,
            tblusuario.Nombres,
            tblusuario.Apellidos,
            tblusuario.TipoDocumento,
            tblusuario.NumeroDoc,
            tblusuario.Correo,
            tblusuario.Estado,
            estructura_area.IDArea,
            estructura_area.Area,
            estructura_direccion.IDDireccion,
            estructura_direccion.Direccion,
            estructura_delegacion.CC,
            cargos.Cargo');
        $this->join('estructura_delegacion', 'tblusuario.IDDelegacion = estructura_delegacion.IDDelegacion', 'left');
        $this->join('estructura_subarea', 'tblusuario.IDSubarea = estructura_subarea.IDSubarea', 'left');
        $this->join('estructura_area', 'estructura_subarea.IDArea = estructura_area.IDArea', 'left');
        $this->join('estructura_direccion', 'estructura_area.IDDireccion = estructura_direccion.IDDireccion', 'left');
        $this->join('cargos', 'tblusuario.IDCargo = cargos.IDCargo', 'left');
        $this->where('tblusuario.IdUsuario', $idUsuario);
        $datos = $this->first();
        return $datos;
    }


    public function buscarUsuarioXusuario($usuario)
    {
        $this->select('tblusuario.IdUsuario,
            tblusuario.Matricula,
            tblusuario.Usuario,
            tblusuario.Nombres,
            tblusuario.Apellidos,
            tblusuario.TipoDocumento,
            tblusuario.NumeroDoc,
            tblusuario.Correo,
            tblusuario.Estado,
            estructura_area.IDArea,
            estructura_area.Area,
            estructura_direccion.IDDireccion,
            estructura_direccion.Direccion,
            estructura_delegacion.CC,
            cargos.Cargo');
        $this->join('estructura_delegacion', 'tblusuario.IDDelegacion = estructura_delegacion.IDDelegacion', 'left');
        $this->join('estructura_subarea', 'tblusuario.IDSubarea = estructura_subarea.IDSubarea', 'left');
        $this->join('estructura_area', 'estructura_subarea.IDArea = estructura_area.IDArea', 'left');
        $this->join('estructura_direccion', 'estructura_area.IDDireccion = estructura_direccion.IDDireccion', 'left');
        $this->join('cargos', 'tblusuario.IDCargo = cargos.IDCargo', 'left');
        $this->where('tblusuario.Usuario', $usuario);
        $datos = $this->first();
        return $datos;
    }

    public function listadoUsuariosSelect($variable, $cc = '')
    {
        $this->select('
        tblusuario.IdUsuario,
        tblusuario.Matricula,
        tblusuario.Nombres,
        tblusuario.Apellidos,
        tblusuario.NumeroDoc,
        estructura_delegacion.CC');
        $this->join('estructura_delegacion', 'tblusuario.IDDelegacion = estructura_delegacion.IDDelegacion', 'left');
        $this->join('estructura_subarea', 'tblusuario.IDSubarea = estructura_subarea.IDSubarea', 'left');
        $this->join('estructura_area', 'estructura_subarea.IDArea = estructura_area.IDArea', 'left');
        $this->join('estructura_direccion', 'estructura_area.IDDireccion = estructura_direccion.IDDireccion', 'left');
        $this->join('cargos', 'tblusuario.IDCargo = cargos.IDCargo', 'left');
        $this->where("(tblusuario.Matricula LIKE '%".$variable."%' OR 
            tblusuario.Nombres LIKE '%".$variable."%' OR
            tblusuario.Apellidos LIKE '%".$variable."%' OR 
            CONCAT(tblusuario.Nombres, ' ',tblusuario.Apellidos) LIKE '%".$variable."%' OR 
            tblusuario.NumeroDoc LIKE '%".$variable."%')");

        if($cc != '')
        {
            $this->where('estructura_delegacion.CC', $cc);
        }
        
        $datos = $this->findAll();
        return $datos;
    }

    public function listaGeneralUsuarios($array) 
    {
        $this->select('
        tblusuario.IdUsuario,
        tblusuario.Matricula,
        tblusuario.Nombres,
        tblusuario.Apellidos,
        tblusuario.TipoDocumento,
        tblusuario.NumeroDoc,
        tblusuario.FechaIngreso,
        tblusuario.FechaCese,
        tblusuario.FTE,
        estructura_subarea.Subarea,
        estructura_area.Area,
        estructura_direccion.Direccion,
        cargos.Cargo,
        estructura_delegacion.CC,
        estructura_delegacion.LN,
        UM.Matricula AS "Matricula_Manager",
        tblusuario.Estado');
        $this->join('estructura_delegacion', 'tblusuario.IDDelegacion = estructura_delegacion.IDDelegacion', 'left');
        $this->join('estructura_subarea', 'tblusuario.IDSubarea = estructura_subarea.IDSubarea', 'left');
        $this->join('estructura_area', 'estructura_subarea.IDArea = estructura_area.IDArea', 'left');
        $this->join('estructura_direccion', 'estructura_area.IDDireccion = estructura_direccion.IDDireccion', 'left');
        $this->join('cargos', 'tblusuario.IDCargo = cargos.IDCargo', 'left');
        $this->join('tblusuario AS UM', 'tblusuario.IDManager = UM.IdUsuario', 'left');

        if(isset($array['estado']) && $array['estado'] != '')
        {
            $this->where("tblusuario.Estado", $array['estado']);
        }
        
        if(isset($array['correo']))
        {
            if($array['correo'] == '')
            {
                $this->where("tblusuario.Correo = '' OR tblusuario.Correo IS NULL");
            }
            else
            {
                $this->where("tblusuario.Correo", $array['correo']);
            }
        }
        
        $datos = $this->findAll();
        return $datos;
    }
    
    public function listaMetricasCalculadasServerSide($get, $adicionales, $grupoTrabajoIds, $tipofuncion)
    {
        
        /*
        * ----------------------------
        * VALORES ESTÁTICOS A UTILIZAR
        * ----------------------------
        */
        // $this->globales = new Globales();
        $fields = array(
            0 => 'tblusuario.idUsuario',                  // ID Usuario
            1 => 'tblusuario.Nombres',                    // Nombres
            2 => 'tblusuario.Apellidos',                  // Apellidos
            3 => 'md.categoria',                          // Categoría
            4 => 'horas_trabajadas',                      // Horas Trabajadas
            5 => 'tardanza',                              // Tardanza
            6 => 'horas_extras',                          // Horas Extras
            7 => 'total_faltas',                          // Total Faltas
            8 => 'bono_desempeno',                        // Bono Desempeño
            9 => 'comision_total',                        // Comisión Total
        );

        /*
        * ----------------------------
        * ARMADO DE VALORES QUERY
        * ----------------------------
        */
        $this->select('
                    gt.GrupoTrabajo,
                    tblusuario.idUsuario, 
                    tblusuario.Nombres, 
                    tblusuario.Apellidos,
                    DATEDIFF(CURDATE(), tblusuario.FechaIngreso) / 30 AS meses_en_empresa,
                    md.categoria, 
                    md.cumplimiento_procesos, md.atencion_cliente, md.tmo, md.productividad, md.wp,
                    k1.kpi_dia AS kpi_cumplimiento_procesos, k2.kpi_dia AS kpi_atencion_cliente, k3.kpi_dia AS kpi_tmo, 
                    k4.kpi_dia AS kpi_productividad, k5.kpi_dia AS kpi_wp,
                    p1.pago_above AS pago_above_cp, p1.pago_target AS pago_target_cp, p1.pago_over AS pago_over_cp,
                    p2.pago_above AS pago_above_ac, p2.pago_target AS pago_target_ac, p2.pago_over AS pago_over_ac,
                    p3.pago_above AS pago_above_tmo, p3.pago_target AS pago_target_tmo, p3.pago_over AS pago_over_tmo,
                    p4.pago_above AS pago_above_product, p4.pago_target AS pago_target_product, p4.pago_over AS pago_over_product,
                    p5.pago_above AS pago_above_wp, p5.pago_target AS pago_target_wp, p5.pago_over AS pago_over_wp,
                    
                        -- Cálculo de bonificación para Cumplimiento de Procesos
                    ROUND(
                        CASE 
                            WHEN md.cumplimiento_procesos * 100 < k1.kpi_dia * k1.porcentaje_above THEN 0
                            WHEN md.cumplimiento_procesos * 100 >= k1.kpi_dia * k1.porcentaje_above AND md.cumplimiento_procesos * 100 < k1.kpi_dia THEN (p1.pago_above * k1.peso) / 100
                            WHEN md.cumplimiento_procesos * 100 >= k1.kpi_dia AND md.cumplimiento_procesos * 100 < k1.kpi_dia * k1.porcentaje_over THEN (p1.pago_target * k1.peso) / 100
                            ELSE (p1.pago_over * k1.peso) / 100
                        END) AS bonificacion_cumplimiento_procesos,
                    
                        -- Cálculo de % de Cumplimiento de Procesos
                    ROUND(
                        CASE 
                            WHEN (md.cumplimiento_procesos * 100 / k1.kpi_dia)*100 >= 110 THEN 110
                            ELSE (md.cumplimiento_procesos * 100 / k1.kpi_dia) * 100
                        END) AS cumplimiento_cumplimiento_procesos,
                    
                        -- Cálculo de bonificación para Atención al Cliente
                    ROUND(
                        CASE 
                            WHEN md.atencion_cliente * 100 < k2.kpi_dia * k2.porcentaje_above THEN 0
                            WHEN md.atencion_cliente * 100 >= k2.kpi_dia * k2.porcentaje_above AND md.atencion_cliente * 100 < k2.kpi_dia THEN (p2.pago_above * k2.peso) / 100
                            WHEN md.atencion_cliente * 100 >= k2.kpi_dia AND md.atencion_cliente * 100 < k2.kpi_dia * k2.porcentaje_over THEN (p2.pago_target * k2.peso) / 100
                            ELSE (p2.pago_over * k2.peso) / 100
                        END) AS bonificacion_atencion_cliente,
                    
                        -- Cálculo de % de Cumplimiento de Atención al Cliente
                    ROUND(
                        CASE 
                            WHEN (md.atencion_cliente * 100 / k2.kpi_dia) >= 110 THEN 110
                            ELSE (md.atencion_cliente * 100 / k2.kpi_dia) * 100
                        END) AS cumplimiento_atencion_cliente,
                    
                        -- Cálculo de bonificación para TMO
                    ROUND(
                        CASE 
                            WHEN md.tmo * 100 < k3.kpi_dia * k3.porcentaje_above THEN 0
                            WHEN md.tmo * 100 >= k3.kpi_dia * k3.porcentaje_above AND md.tmo * 100 < k3.kpi_dia THEN (p3.pago_above * k3.peso) / 100
                            WHEN md.tmo * 100 >= k3.kpi_dia AND md.tmo * 100 < k3.kpi_dia * k3.porcentaje_over THEN (p3.pago_target * k3.peso) / 100
                            ELSE (p3.pago_over * k3.peso) / 100
                        END) AS bonificacion_tmo,
                    
                        -- Cálculo de % de Cumplimiento de TMO
                    ROUND(
                        CASE 
                            WHEN (k3.kpi_dia / md.tmo) * 100 >= 110 THEN 110
                            ELSE (k3.kpi_dia / md.tmo) * 100
                        END) AS cumplimiento_tmo,
                    
                        -- Cálculo de bonificación para Productividad
                    ROUND(
                        CASE 
                            WHEN md.productividad < k4.kpi_dia * k4.porcentaje_above THEN 0
                            WHEN md.productividad >= k4.kpi_dia * k4.porcentaje_above AND md.productividad < k4.kpi_dia THEN (p4.pago_above * k4.peso) / 100
                            WHEN md.productividad >= k4.kpi_dia AND md.productividad < k4.kpi_dia * k4.porcentaje_over THEN (p4.pago_target * k4.peso) / 100
                            ELSE (p4.pago_over * k4.peso) / 100
                        END) AS bonificacion_productividad,
                    
                        -- Cálculo de % de Cumplimiento de Productividad
                    ROUND(
                        CASE 
                            WHEN (md.productividad / k4.kpi_dia) * 100 >= 110 THEN 110
                            ELSE (md.productividad / k4.kpi_dia) * 100
                        END) AS cumplimiento_productividad,
                    
                        -- Cálculo de bonificación para WP
                    ROUND(
                        CASE 
                            WHEN md.wp < k5.kpi_dia * k5.porcentaje_above THEN 0
                            WHEN md.wp >= k5.kpi_dia * k5.porcentaje_above AND md.wp < k5.kpi_dia THEN (p5.pago_above * k5.peso) / 100
                            WHEN md.wp >= k5.kpi_dia AND md.wp < k5.kpi_dia * k5.porcentaje_over THEN (p5.pago_target * k5.peso) / 100
                            ELSE (p5.pago_over * k5.peso) / 100
                        END) AS bonificacion_wp,
                    
                        -- Cálculo de % de Cumplimiento de WP
                    ROUND(
                        CASE 
                            WHEN (k5.kpi_noche / md.wp) * 100 >= 110 THEN 110
                            ELSE (k5.kpi_noche / md.wp) * 100
                        END) AS cumplimiento_wp,
                    
                        -- Cálculo del desempeño final basado en la suma de cumplimientos
                    ROUND
                        (ROUND(
                            CASE 
                                WHEN (md.cumplimiento_procesos * 100 / k1.kpi_dia)*100 >= 110 THEN 110
                                ELSE (md.cumplimiento_procesos * 100 / k1.kpi_dia) * 100
                            END,2) * 0.30 + 
                        ROUND(
                            CASE 
                                WHEN (md.atencion_cliente * 100 / k2.kpi_dia) >= 110 THEN 110
                                ELSE (md.atencion_cliente * 100 / k2.kpi_dia) * 100
                            END,2) * 0.30 + 
                        ROUND(
                            CASE 
                                WHEN (k3.kpi_dia / md.tmo) * 100 >= 110 THEN 110
                                ELSE (k3.kpi_dia / md.tmo) * 100
                            END,2) * 0.15 + 
                        ROUND(
                            CASE 
                                WHEN (md.productividad / k4.kpi_dia) * 100 >= 110 THEN 110
                                ELSE (md.productividad / k4.kpi_dia) * 100
                            END,2) * 0.15 + 
                        ROUND(
                            CASE 
                                WHEN (k5.kpi_noche / md.wp) * 100 >= 110 THEN 110
                                ELSE (k5.kpi_noche / md.wp) * 100
                            END,2) * 0.10)  AS desempeno_final,

                    -- Horas trabajadas
                    CASE
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio THEN 
                            TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(
                                TIMEDIFF(
                                    -- Si la hora de salida es al día siguiente, ajustamos el cálculo
                                    IF(a_fin.FechaHoraRegistro < CONCAT(p.FechaTrabajo, " ", h.HoraInicio), 
                                        CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin), 
                                        a_fin.FechaHoraRegistro), 
                                    a_inicio.FechaHoraRegistro)
                            ))), "%H:%i:%s")
                        ELSE 
                            -- Horarios normales
                            TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_fin.FechaHoraRegistro, a_inicio.FechaHoraRegistro)))), "%H:%i:%s")
                    END AS horas_trabajadas,
                    
                    -- Tardanzas
                    CASE
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio THEN 
                            CASE 
                               
                                WHEN a_inicio.FechaHoraRegistro > CONCAT(p.FechaTrabajo, " ", h.HoraInicio) THEN 
                                    TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_inicio.FechaHoraRegistro, CONCAT(p.FechaTrabajo, " ", h.HoraInicio))))), "%H:%i:%s")
                                
                                WHEN a_inicio.FechaHoraRegistro > CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin) THEN 
                                    TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_inicio.FechaHoraRegistro, CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin))))), "%H:%i:%s")
                                ELSE "00:00:00"
                            END
                        ELSE
                            -- Horarios normales que no cruzan la medianoche
                            CASE 
                                WHEN a_inicio.FechaHoraRegistro > CONCAT(p.FechaTrabajo, " ", h.HoraInicio) THEN 
                                    TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_inicio.FechaHoraRegistro, CONCAT(p.FechaTrabajo, " ", h.HoraInicio))))), "%H:%i:%s")
                                ELSE "00:00:00"
                            END
                    END AS tardanza,
                    
                    -- Horas extras
                    CASE
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio THEN
                            CASE
                                -- Si la hora de salida es mayor que la hora fin al día siguiente
                                WHEN a_fin.FechaHoraRegistro > CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin) THEN 
                                    TIMEDIFF(a_fin.FechaHoraRegistro, CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin))
                                ELSE "00:00:00"
                            END
                        ELSE
                            -- Horarios normales
                            CASE
                                WHEN a_fin.FechaHoraRegistro > CONCAT(p.FechaTrabajo, " ", h.HoraFin) THEN 
                                    TIMEDIFF(a_fin.FechaHoraRegistro, CONCAT(p.FechaTrabajo, " ", h.HoraFin))
                                ELSE "00:00:00"
                            END
                    END AS horas_extras,
                    
                    -- Faltas
                    COUNT(CASE 
                        -- Si no hay registro de inicio ni fin
                        WHEN a_inicio.FechaHoraRegistro IS NULL AND a_fin.FechaHoraRegistro IS NULL THEN 1
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio AND 
                             a_inicio.FechaHoraRegistro IS NULL AND a_fin.FechaHoraRegistro IS NULL THEN 1
                    END) AS total_faltas
                ');
                $this->join('usuario_grupostrabajo ug', 'tblusuario.IdUsuario = ug.IdUsuario');
                $this->join('grupostrabajo gt', 'ug.IDGrupoTrabajo = gt.IDGrupoTrabajo');
        $this->join('tbl_metricas_desempeno md', 'tblusuario.idUsuario = md.idUsuario');
        // LEFT JOIN con `temp_metricas_complementarias`
                
        $this->join('planificacion p', 'p.IdUsuario = tblusuario.idUsuario');
        $this->join('horarios h', 'p.id_horario = h.id_horario');
        $this->join('asistencia a_inicio', 'p.IdUsuario = a_inicio.IdUsuario AND a_inicio.TipoRegistro = "inicio" AND a_inicio.FechaHoraRegistro LIKE CONCAT(p.FechaTrabajo, "%") AND a_inicio.id_horario = p.id_horario','left');
        $this->join('asistencia a_fin', 'p.IdUsuario = a_fin.IdUsuario AND a_fin.TipoRegistro = "fin" AND a_fin.FechaHoraRegistro LIKE CONCAT(p.FechaTrabajo, "%") AND a_fin.id_horario = p.id_horario','left');
                
        $this->join('tbl_categoria_metrica c', 'md.categoria = c.nombre_categoria');
                
                // -- Uniones con las métricas de cada subcriterio
        $this->join('tbl_kpi_metrica k1', 'c.id_categoria = k1.id_categoria AND k1.id_subcriterio = 1');
        $this->join('tbl_pagos_metrica p1', 'c.id_categoria = p1.id_categoria AND p1.id_subcriterio = 1');
                
        $this->join('tbl_kpi_metrica k2', 'c.id_categoria = k2.id_categoria AND k2.id_subcriterio = 2');
        $this->join('tbl_pagos_metrica p2', 'c.id_categoria = p2.id_categoria AND p2.id_subcriterio = 2');
            
        $this->join('tbl_kpi_metrica k3', 'c.id_categoria = k3.id_categoria AND k3.id_subcriterio = 3');
        $this->join('tbl_pagos_metrica p3', 'c.id_categoria = p3.id_categoria AND p3.id_subcriterio = 3');
            
        $this->join('tbl_kpi_metrica k4', 'c.id_categoria = k4.id_categoria AND k4.id_subcriterio = 4');
        $this->join('tbl_pagos_metrica p4', 'c.id_categoria = p4.id_categoria AND p4.id_subcriterio = 4');
            
        $this->join('tbl_kpi_metrica k5', 'c.id_categoria = k5.id_categoria AND k5.id_subcriterio = 5');
        $this->join('tbl_pagos_metrica p5', 'c.id_categoria = p5.id_categoria AND p5.id_subcriterio = 5');
        $this->groupBy('tblusuario.idUsuario');
        $this->whereIn('ug.IDGrupoTrabajo', $grupoTrabajoIds);
        $this->where($adicionales);
        
        /*
        * ----------------------------
        * ARMADO DE CONDICIONES QUERY
        * ----------------------------
        */
        if($tipofuncion == 'dataTable'){
            if (isset($get['search']) &&  $get['search']['value'] != "") 
            {
                $this->groupStart(); // Inicia un grupo de condiciones
                foreach ($get['columns'] as $k => $column) 
                {
                    if(array_key_exists($k, $fields))
                    {
                        $this->orLike($fields[$k], $get['search']['value']);
                    }
                }
                $this->groupEnd(); // Finaliza el grupo de condiciones
            }
            
            /*
            * ----------------------------
            * ORDENAMIENTO DE QUERY
            * ----------------------------
            */
            if (isset($get['order'])) {
                foreach ($get['order'] as $order) {
                    if(array_key_exists($order['column'], $fields))
                    {
                        $this->orderBy($fields[$order['column']], $order['dir']);
                    }
                }
            }
            /*
            * ----------------------------
            * LIMITAR CANTIDAD DE RESULTADOS DE QUERY
            * ----------------------------
            */
            if (isset($get['length']) && isset($get['start'])) {
                $this->limit($get['length'], $get['start']);
            }
        }    
        /*
        * ----------------------------
        * EJECUTAR CONSULTA Y DEVOLVER VALORES
        * ----------------------------
        */
        // $this->get();
        // return $this->getLastQuery();
        $result = $this->get()->getResultArray(); 
        
        // Retornar datos y totales
        return   $result;  

    }    
    
    public function listaMetricasServerSide($get, $adicionales, $grupoTrabajoIds, $tipofuncion)
    {
        
        /*
        * ----------------------------
        * VALORES ESTÁTICOS A UTILIZAR
        * ----------------------------
        */
        // $this->globales = new Globales();
        $fields = array(
            0 => 'tblusuario.idUsuario',                  // ID Usuario
            1 => 'tblusuario.Nombres',                    // Nombres
            2 => 'tblusuario.Apellidos',                  // Apellidos
            3 => 'md.categoria',                          // Categoría
            4 => 'horas_trabajadas',                      // Horas Trabajadas
            5 => 'tardanza',                              // Tardanza
            6 => 'horas_extras',                          // Horas Extras
            7 => 'total_faltas',                          // Total Faltas
            8 => 'bono_desempeno',                        // Bono Desempeño
            9 => 'comision_total',                        // Comisión Total
        );

        /*
        * ----------------------------
        * ARMADO DE VALORES QUERY
        * ----------------------------
        */
        $this->select('
                    tblusuario.idUsuario, 
                    tblusuario.Nombres, 
                    tblusuario.Apellidos,
                    tmc.dias_trabajo_efectivo,
                    tmc.fechas_trabajo_efectivo,
                    tmc.dias_teletrabajo,
                    tmc.fechas_teletrabajo,
                    tmc.HHEE25,
                    tmc.HHEE35,
                    tmc.HHEE_dominical_100,
                    tmc.HHEE_feriado,
                    tmc.HHEE_1ro_de_mayo,
                    tmc.HHEE_nocturnas,
                    tmc.bono_productividad,
                    tmc.otros_bonos,
                    tmc.bono_de_carrera,
                    tmc.bonificacion_por_desempeno,
                    tmc.bono_responsabilidad,
                    tmc.bono_inicio,
                    tmc.bono_veritombola,
                    tmc.comisiones_upselling,
                    tmc.reintegro_afecto,
                    tmc.gift_card,
                    tmc.gift_card_upselling,
                    tmc.obsequios_upselling,
                    tmc.obsequios_al_personal,
                    tmc.descuento_por_equipo_celular,
                    tmc.descuento_uniforme_materiales,
                    tmc.descuento_por_demos,
                    tmc.descuento_eps,
                    tmc.descuento_alarma_verisure,
                    tmc.descuento_seguro_rimac,
                    tmc.observaciones,
                    tmc.matricula,
                    DATEDIFF(CURDATE(), tblusuario.FechaIngreso) / 30 AS meses_en_empresa,
                    md.categoria, 
                    md.cumplimiento_procesos, md.atencion_cliente, md.tmo, md.productividad, md.wp,
                    k1.kpi_dia AS kpi_cumplimiento_procesos, k2.kpi_dia AS kpi_atencion_cliente, k3.kpi_dia AS kpi_tmo, 
                    k4.kpi_dia AS kpi_productividad, k5.kpi_dia AS kpi_wp,
                    p1.pago_above AS pago_above_cp, p1.pago_target AS pago_target_cp, p1.pago_over AS pago_over_cp,
                    p2.pago_above AS pago_above_ac, p2.pago_target AS pago_target_ac, p2.pago_over AS pago_over_ac,
                    p3.pago_above AS pago_above_tmo, p3.pago_target AS pago_target_tmo, p3.pago_over AS pago_over_tmo,
                    p4.pago_above AS pago_above_product, p4.pago_target AS pago_target_product, p4.pago_over AS pago_over_product,
                    p5.pago_above AS pago_above_wp, p5.pago_target AS pago_target_wp, p5.pago_over AS pago_over_wp,
                    
                        -- Cálculo de bonificación para Cumplimiento de Procesos
                    ROUND(
                        CASE 
                            WHEN md.cumplimiento_procesos * 100 < k1.kpi_dia * k1.porcentaje_above THEN 0
                            WHEN md.cumplimiento_procesos * 100 >= k1.kpi_dia * k1.porcentaje_above AND md.cumplimiento_procesos * 100 < k1.kpi_dia THEN (p1.pago_above * k1.peso) / 100
                            WHEN md.cumplimiento_procesos * 100 >= k1.kpi_dia AND md.cumplimiento_procesos * 100 < k1.kpi_dia * k1.porcentaje_over THEN (p1.pago_target * k1.peso) / 100
                            ELSE (p1.pago_over * k1.peso) / 100
                        END) AS bonificacion_cumplimiento_procesos,
                    
                        -- Cálculo de % de Cumplimiento de Procesos
                    ROUND(
                        CASE 
                            WHEN (md.cumplimiento_procesos * 100 / k1.kpi_dia)*100 >= 110 THEN 110
                            ELSE (md.cumplimiento_procesos * 100 / k1.kpi_dia) * 100
                        END) AS cumplimiento_cumplimiento_procesos,
                    
                        -- Cálculo de bonificación para Atención al Cliente
                    ROUND(
                        CASE 
                            WHEN md.atencion_cliente * 100 < k2.kpi_dia * k2.porcentaje_above THEN 0
                            WHEN md.atencion_cliente * 100 >= k2.kpi_dia * k2.porcentaje_above AND md.atencion_cliente * 100 < k2.kpi_dia THEN (p2.pago_above * k2.peso) / 100
                            WHEN md.atencion_cliente * 100 >= k2.kpi_dia AND md.atencion_cliente * 100 < k2.kpi_dia * k2.porcentaje_over THEN (p2.pago_target * k2.peso) / 100
                            ELSE (p2.pago_over * k2.peso) / 100
                        END) AS bonificacion_atencion_cliente,
                    
                        -- Cálculo de % de Cumplimiento de Atención al Cliente
                    ROUND(
                        CASE 
                            WHEN (md.atencion_cliente * 100 / k2.kpi_dia) >= 110 THEN 110
                            ELSE (md.atencion_cliente * 100 / k2.kpi_dia) * 100
                        END) AS cumplimiento_atencion_cliente,
                    
                        -- Cálculo de bonificación para TMO
                    ROUND(
                        CASE 
                            WHEN md.tmo * 100 < k3.kpi_dia * k3.porcentaje_above THEN 0
                            WHEN md.tmo * 100 >= k3.kpi_dia * k3.porcentaje_above AND md.tmo * 100 < k3.kpi_dia THEN (p3.pago_above * k3.peso) / 100
                            WHEN md.tmo * 100 >= k3.kpi_dia AND md.tmo * 100 < k3.kpi_dia * k3.porcentaje_over THEN (p3.pago_target * k3.peso) / 100
                            ELSE (p3.pago_over * k3.peso) / 100
                        END) AS bonificacion_tmo,
                    
                        -- Cálculo de % de Cumplimiento de TMO
                    ROUND(
                        CASE 
                            WHEN (k3.kpi_dia / md.tmo) * 100 >= 110 THEN 110
                            ELSE (k3.kpi_dia / md.tmo) * 100
                        END) AS cumplimiento_tmo,
                    
                        -- Cálculo de bonificación para Productividad
                    ROUND(
                        CASE 
                            WHEN md.productividad < k4.kpi_dia * k4.porcentaje_above THEN 0
                            WHEN md.productividad >= k4.kpi_dia * k4.porcentaje_above AND md.productividad < k4.kpi_dia THEN (p4.pago_above * k4.peso) / 100
                            WHEN md.productividad >= k4.kpi_dia AND md.productividad < k4.kpi_dia * k4.porcentaje_over THEN (p4.pago_target * k4.peso) / 100
                            ELSE (p4.pago_over * k4.peso) / 100
                        END) AS bonificacion_productividad,
                    
                        -- Cálculo de % de Cumplimiento de Productividad
                    ROUND(
                        CASE 
                            WHEN (md.productividad / k4.kpi_dia) * 100 >= 110 THEN 110
                            ELSE (md.productividad / k4.kpi_dia) * 100
                        END) AS cumplimiento_productividad,
                    
                        -- Cálculo de bonificación para WP
                    ROUND(
                        CASE 
                            WHEN md.wp < k5.kpi_dia * k5.porcentaje_above THEN 0
                            WHEN md.wp >= k5.kpi_dia * k5.porcentaje_above AND md.wp < k5.kpi_dia THEN (p5.pago_above * k5.peso) / 100
                            WHEN md.wp >= k5.kpi_dia AND md.wp < k5.kpi_dia * k5.porcentaje_over THEN (p5.pago_target * k5.peso) / 100
                            ELSE (p5.pago_over * k5.peso) / 100
                        END) AS bonificacion_wp,
                    
                        -- Cálculo de % de Cumplimiento de WP
                    ROUND(
                        CASE 
                            WHEN (k5.kpi_noche / md.wp) * 100 >= 110 THEN 110
                            ELSE (k5.kpi_noche / md.wp) * 100
                        END) AS cumplimiento_wp,
                    
                        -- Cálculo del desempeño final basado en la suma de cumplimientos
                    ROUND
                        (ROUND(
                            CASE 
                                WHEN (md.cumplimiento_procesos * 100 / k1.kpi_dia)*100 >= 110 THEN 110
                                ELSE (md.cumplimiento_procesos * 100 / k1.kpi_dia) * 100
                            END,2) * 0.30 + 
                        ROUND(
                            CASE 
                                WHEN (md.atencion_cliente * 100 / k2.kpi_dia) >= 110 THEN 110
                                ELSE (md.atencion_cliente * 100 / k2.kpi_dia) * 100
                            END,2) * 0.30 + 
                        ROUND(
                            CASE 
                                WHEN (k3.kpi_dia / md.tmo) * 100 >= 110 THEN 110
                                ELSE (k3.kpi_dia / md.tmo) * 100
                            END,2) * 0.15 + 
                        ROUND(
                            CASE 
                                WHEN (md.productividad / k4.kpi_dia) * 100 >= 110 THEN 110
                                ELSE (md.productividad / k4.kpi_dia) * 100
                            END,2) * 0.15 + 
                        ROUND(
                            CASE 
                                WHEN (k5.kpi_noche / md.wp) * 100 >= 110 THEN 110
                                ELSE (k5.kpi_noche / md.wp) * 100
                            END,2) * 0.10)  AS desempeno_final,

                    -- Horas trabajadas
                    CASE
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio THEN 
                            TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(
                                TIMEDIFF(
                                    -- Si la hora de salida es al día siguiente, ajustamos el cálculo
                                    IF(a_fin.FechaHoraRegistro < CONCAT(p.FechaTrabajo, " ", h.HoraInicio), 
                                        CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin), 
                                        a_fin.FechaHoraRegistro), 
                                    a_inicio.FechaHoraRegistro)
                            ))), "%H:%i:%s")
                        ELSE 
                            -- Horarios normales
                            TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_fin.FechaHoraRegistro, a_inicio.FechaHoraRegistro)))), "%H:%i:%s")
                    END AS horas_trabajadas,
                    
                    -- Tardanzas
                    CASE
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio THEN 
                            CASE 
                               
                                WHEN a_inicio.FechaHoraRegistro > CONCAT(p.FechaTrabajo, " ", h.HoraInicio) THEN 
                                    TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_inicio.FechaHoraRegistro, CONCAT(p.FechaTrabajo, " ", h.HoraInicio))))), "%H:%i:%s")
                                
                                WHEN a_inicio.FechaHoraRegistro > CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin) THEN 
                                    TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_inicio.FechaHoraRegistro, CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin))))), "%H:%i:%s")
                                ELSE "00:00:00"
                            END
                        ELSE
                            -- Horarios normales que no cruzan la medianoche
                            CASE 
                                WHEN a_inicio.FechaHoraRegistro > CONCAT(p.FechaTrabajo, " ", h.HoraInicio) THEN 
                                    TIME_FORMAT(SEC_TO_TIME(SUM(TIME_TO_SEC(TIMEDIFF(a_inicio.FechaHoraRegistro, CONCAT(p.FechaTrabajo, " ", h.HoraInicio))))), "%H:%i:%s")
                                ELSE "00:00:00"
                            END
                    END AS tardanza,
                    
                    -- Horas extras
                    CASE
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio THEN
                            CASE
                                -- Si la hora de salida es mayor que la hora fin al día siguiente
                                WHEN a_fin.FechaHoraRegistro > CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin) THEN 
                                    TIMEDIFF(a_fin.FechaHoraRegistro, CONCAT(DATE_ADD(p.FechaTrabajo, INTERVAL 1 DAY), " ", h.HoraFin))
                                ELSE "00:00:00"
                            END
                        ELSE
                            -- Horarios normales
                            CASE
                                WHEN a_fin.FechaHoraRegistro > CONCAT(p.FechaTrabajo, " ", h.HoraFin) THEN 
                                    TIMEDIFF(a_fin.FechaHoraRegistro, CONCAT(p.FechaTrabajo, " ", h.HoraFin))
                                ELSE "00:00:00"
                            END
                    END AS horas_extras,
                    
                    -- Faltas
                    COUNT(CASE 
                        -- Si no hay registro de inicio ni fin
                        WHEN a_inicio.FechaHoraRegistro IS NULL AND a_fin.FechaHoraRegistro IS NULL THEN 1
                        -- Horarios que cruzan la medianoche
                        WHEN h.HoraFin < h.HoraInicio AND 
                             a_inicio.FechaHoraRegistro IS NULL AND a_fin.FechaHoraRegistro IS NULL THEN 1
                    END) AS total_faltas
                ');
        $this->join('tbl_metricas_desempeno md', 'tblusuario.idUsuario = md.idUsuario');
        // LEFT JOIN con `temp_metricas_complementarias`
        $this->join('temp_metricas_complementarias tmc', 'tmc.matricula = tblusuario.Matricula');
                
        $this->join('planificacion p', 'p.IdUsuario = tblusuario.idUsuario');
        $this->join('horarios h', 'p.id_horario = h.id_horario');
        $this->join('asistencia a_inicio', 'p.IdUsuario = a_inicio.IdUsuario AND a_inicio.TipoRegistro = "inicio" AND a_inicio.FechaHoraRegistro LIKE CONCAT(p.FechaTrabajo, "%") AND a_inicio.id_horario = p.id_horario','left');
        $this->join('asistencia a_fin', 'p.IdUsuario = a_fin.IdUsuario AND a_fin.TipoRegistro = "fin" AND a_fin.FechaHoraRegistro LIKE CONCAT(p.FechaTrabajo, "%") AND a_fin.id_horario = p.id_horario','left');
                
        $this->join('tbl_categoria_metrica c', 'md.categoria = c.nombre_categoria');
                
                // -- Uniones con las métricas de cada subcriterio
        $this->join('tbl_kpi_metrica k1', 'c.id_categoria = k1.id_categoria AND k1.id_subcriterio = 1');
        $this->join('tbl_pagos_metrica p1', 'c.id_categoria = p1.id_categoria AND p1.id_subcriterio = 1');
                
        $this->join('tbl_kpi_metrica k2', 'c.id_categoria = k2.id_categoria AND k2.id_subcriterio = 2');
        $this->join('tbl_pagos_metrica p2', 'c.id_categoria = p2.id_categoria AND p2.id_subcriterio = 2');
            
        $this->join('tbl_kpi_metrica k3', 'c.id_categoria = k3.id_categoria AND k3.id_subcriterio = 3');
        $this->join('tbl_pagos_metrica p3', 'c.id_categoria = p3.id_categoria AND p3.id_subcriterio = 3');
            
        $this->join('tbl_kpi_metrica k4', 'c.id_categoria = k4.id_categoria AND k4.id_subcriterio = 4');
        $this->join('tbl_pagos_metrica p4', 'c.id_categoria = p4.id_categoria AND p4.id_subcriterio = 4');
            
        $this->join('tbl_kpi_metrica k5', 'c.id_categoria = k5.id_categoria AND k5.id_subcriterio = 5');
        $this->join('tbl_pagos_metrica p5', 'c.id_categoria = p5.id_categoria AND p5.id_subcriterio = 5');
        $this->groupBy('tblusuario.idUsuario');
        $this->whereIn('p.IDGrupoTrabajo', $grupoTrabajoIds);
        $this->where($adicionales);
        
        /*
        * ----------------------------
        * ARMADO DE CONDICIONES QUERY
        * ----------------------------
        */
        if($tipofuncion == 'dataTable'){
            if (isset($get['search']) &&  $get['search']['value'] != "") 
            {
                $this->groupStart(); // Inicia un grupo de condiciones
                foreach ($get['columns'] as $k => $column) 
                {
                    if(array_key_exists($k, $fields))
                    {
                        $this->orLike($fields[$k], $get['search']['value']);
                    }
                }
                $this->groupEnd(); // Finaliza el grupo de condiciones
            }
            
            /*
            * ----------------------------
            * ORDENAMIENTO DE QUERY
            * ----------------------------
            */
            if (isset($get['order'])) {
                foreach ($get['order'] as $order) {
                    if(array_key_exists($order['column'], $fields))
                    {
                        $this->orderBy($fields[$order['column']], $order['dir']);
                    }
                }
            }
            /*
            * ----------------------------
            * LIMITAR CANTIDAD DE RESULTADOS DE QUERY
            * ----------------------------
            */
            if (isset($get['length']) && isset($get['start'])) {
                $this->limit($get['length'], $get['start']);
            }
        }    
        /*
        * ----------------------------
        * EJECUTAR CONSULTA Y DEVOLVER VALORES
        * ----------------------------
        */
        // $this->get();
        // return $this->getLastQuery();
        $result = $this->get()->getResultArray(); 
        
        // Retornar datos y totales
        return   $result;  

    }
    
}
