<?php

namespace App\Http\Controllers;

use App\Models\InformacionManoObra;
use App\Models\ManoObraTerceros;
use App\Models\BasesDistribucion;
use App\Models\InformacionBasesDistribucion;
use App\Models\InformacionBasesDistribucion2;
use App\Models\DistribucionIfmCostosCuentas;
use App\Models\DistribucionIfmCostosBases;
use App\Models\InformacionFinanciera;
use App\Models\CentrosCosto;
use App\Models\ManoObra;
use App\Models\AvanceModulos;
use Illuminate\Http\Request;

class InformacionManoObraController extends Controller
{
    private $apiKey;

    function __construct() {
        $apiController = new ApiController();

        $this->apiKey = $apiController->getApiKey()["key"];
    }

    public function crearInformacionManoObra(Request $request) {
        \DB::transaction(function() use($request) {
            $this->guardarManoObraTercero($request->input('con_fk_id'),
                                          $request->input('ins_fk_id'),
                                          $request->input('imo_ano'),
                                          $request->input('imo_mes'),
                                          $request->input('mot_fk_id'),
                                          $request->input('ccoCargos'),
                                          $request->input('ccoHoras'));
        });

        $this->verificarAvance($request->input('con_fk_id'),
                               $request->input('ins_fk_id'),
                               $request->input('imo_ano'),
                               $request->input('imo_mes'));

        return array("response" => 0);
    }

    public function actualizarInformacionManoObra(Request $request) {
        \DB::transaction(function() use($request) {
            InformacionManoObra::on('costos_principal')
                               ->where('con_fk_id', $request->input('con_fk_id'))
                               ->where('ins_fk_id', $request->input('ins_fk_id'))
                               ->where('imo_ano', $request->input('imo_ano'))
                               ->where('imo_mes', $request->input('imo_mes'))
                               ->where('mot_fk_id', $request->input('mot_fk_id'))
                               ->delete();

            // Reemplazar con informacion nueva
            $this->guardarManoObraTercero($request->input('con_fk_id'),
                                          $request->input('ins_fk_id'),
                                          $request->input('imo_ano'),
                                          $request->input('imo_mes'),
                                          $request->input('mot_fk_id'),
                                          $request->input('ccoCargos'),
                                          $request->input('ccoHoras'));
        });

        $this->verificarAvance($request->input('con_fk_id'),
                               $request->input('ins_fk_id'),
                               $request->input('imo_ano'),
                               $request->input('imo_mes'));

        return array("response" => 0);
    }

    private function guardarManoObraTercero($con_fk_id, $ins_fk_id, $imo_ano, $imo_mes, $mot_fk_id, $ccoCargos, $ccoHoras) {
        // Verificar si existe la base de distribucion del tercero
        $idBdi = 0;

        $tercero = ManoObraTerceros::on('costos_principal')
                                   ->where('mot_pk_id', $mot_fk_id);

        $nombreBd = "Horas laboradas de ".strtoupper($tercero->value('mot_nit_tercero'))." - ".strtoupper($tercero->value('mot_razon_social'));
        $rand1 = rand(0,9);
        $rand2 = rand(0,9);
        $rand3 = rand(0,9);
        $rand4 = rand(0,9);

        $bdi = BasesDistribucion::on('costos_principal')
                                ->where('con_fk_id', $con_fk_id)
                                ->where('ins_fk_id', $ins_fk_id)
                                ->where('bdi_ano', $imo_ano)
                                ->where('bdi_descripcion', $nombreBd)
                                ->where('bdi_mano_obra', true);

        if ($bdi->count() > 0) {
            $idBdi = $bdi->value('bdi_pk_id');
        } else {
            $nuevaBdi = BasesDistribucion::on('costos_principal')
            ->create(
                [
                    "con_fk_id" => $con_fk_id,
                    "ins_fk_id" => $ins_fk_id,
                    "bdi_ano" => $imo_ano,
                    "bdi_codigo" => "BDMO".$tercero->value('mot_nit_tercero').$rand1.$rand2.$rand3.$rand4,
                    "bdi_descripcion" => $nombreBd,
                    "bdi_predefinida" => false,
                    "bdi_mano_obra" => true
                ]
            );

            $idBdi = $nuevaBdi->bdi_pk_id;
        }

        $ccoCargosAux = json_decode($ccoCargos);

        // Guardar en informacion de mano de obra
        foreach($ccoCargosAux as $ccoMob) {
            foreach($ccoMob->centroCosto as $cco) {
                InformacionManoObra::on('costos_principal')
                ->create(
                    [
                        "con_fk_id" => $con_fk_id,
                        "ins_fk_id" => $ins_fk_id,
                        "imo_ano" => $imo_ano,
                        "imo_mes" => $imo_mes,
                        "mot_fk_id" => $mot_fk_id,
                        "mob_fk_id" => $ccoMob->mob_fk_id,
                        "cco_fk_id" => $cco->cco_pk_id,
                        "imo_horas" => $cco->imo_horas,
                        "imo_valor" => $ccoMob->imo_valor
                    ]
                );
            }
        }

        $ccoHorasAux = json_decode($ccoHoras);

        // Guardar para conteo por centro de costo
        foreach($ccoHorasAux as $cco) {
            // Bases de distribucion costo total
            $ibd2 = InformacionBasesDistribucion2::on('costos_principal')
                                                 ->where('con_fk_id', $con_fk_id)
                                                 ->where('ins_fk_id', $ins_fk_id)
                                                 ->where('ibd2_ano', $imo_ano)
                                                 ->where('ibd2_mes', $imo_mes)
                                                 ->where('cco_fk_id', $cco->cco_pk_id)
                                                 ->where('bdi_fk_id', $idBdi);

            if ($ibd2->count() > 0) {
                $ibd2->update(
                    [
                        "ibd2_valor" => $cco->imo_horas,
                        "ibd2_automatico" => true
                    ]
                );
            } else {
                InformacionBasesDistribucion2::on('costos_principal')
                ->create(
                    [
                        "con_fk_id" => $con_fk_id,
                        "ins_fk_id" => $ins_fk_id,
                        "ibd2_ano" => $imo_ano,
                        "ibd2_mes" => $imo_mes,
                        "cco_fk_id" => $cco->cco_pk_id,
                        "bdi_fk_id" => $idBdi,
                        "ibd2_valor" => $cco->imo_horas,
                        "ibd2_automatico" => true
                    ]
                );
            }
        }
    }

    public function getCargosTercero(Request $request) {
        return \DB::select("select distinct mob.*
                            from costos_principal.informacion_mano_obra as imo
                            join costos_principal.mano_obra as mob on (imo.mob_fk_id = mob.mob_pk_id)
                            where imo.con_fk_id = ".$request->input('con_fk_id')." and
                                  imo.ins_fk_id = '".$request->input('ins_fk_id')."' and
                                  imo_ano = ".$request->input('imo_ano')." and
                                  imo_mes = ".$request->input('imo_mes')." and
                                  mot_fk_id = ".$request->input('mot_fk_id')."
                            order by mob_cargo");
    }

    public function getInformacionManoObra(Request $request) {
        return InformacionManoObra::on('costos_principal')
                                  ->where('con_fk_id', $request->input('con_fk_id'))
                                  ->where('ins_fk_id', $request->input('ins_fk_id'))
                                  ->where('imo_ano', $request->input('imo_ano'))
                                  ->where('imo_mes', $request->input('imo_mes'))
                                  ->where('mot_fk_id', $request->input('mot_fk_id'))
                                  ->orderBy('mot_fk_id')
                                  ->orderBy('mob_fk_id')
                                  ->get()->toArray();
    }

    public function getInformacionManoObraCompleta(Request $request) {
        return InformacionManoObra::on('costos_principal')
                                  ->where('con_fk_id', $request->input('con_fk_id'))
                                  ->where('ins_fk_id', $request->input('ins_fk_id'))
                                  ->where('imo_ano', $request->input('imo_ano'))
                                  ->where('imo_mes', $request->input('imo_mes'))
                                  ->get()->toArray();
    }

    public function borrarCargoTercero(Request $request) {
        InformacionManoObra::on('costos_principal')
                           ->where('con_fk_id', $request->input('con_fk_id'))
                           ->where('ins_fk_id', $request->input('ins_fk_id'))
                           ->where('imo_ano', $request->input('imo_ano'))
                           ->where('imo_mes', $request->input('imo_mes'))
                           ->where('mot_fk_id', $request->input('mot_fk_id'))
                           ->where('mob_fk_id', $request->input('mob_fk_id'))
                           ->delete();
    }

    public function cargarArchivoInformacionManoObra(Request $request) {
        $apiKey = $request->apiKey;

        if ($apiKey === $this->apiKey) {
            $rutaDelArchivo = $request->infoManoObra->path();
            $delimitador = $request->delimitador;
            $archivo = fopen($rutaDelArchivo, 'r');
            $infoManoObra = array();
            $primeraLinea = true;

            // Extraer cada línea del archivo CSV y convertirlo en un arreglo
            while($linea = fgetcsv($archivo, 1000, $delimitador)) {
                if (!$primeraLinea) {
                    $registro = $linea;
                    array_push($infoManoObra, $registro);
                } else {
                    $primeraLinea = false;
                }
            }

            fclose($archivo);

            return $this->procesarArchivoInfoManoObra($infoManoObra,
                                                      $request->con_fk_id,
                                                      $request->ins_fk_id,
                                                      $request->imo_ano,
                                                      $request->imo_mes);
        } else {
            throw new \Exception('Imposible completar la petición.');
        }
    }

    public function cargarArchivoInformacionCostoCargo(Request $request) {
        $apiKey = $request->apiKey;

        if ($apiKey === $this->apiKey) {
            $rutaDelArchivo = $request->infoCostoCargo->path();
            $delimitador = $request->delimitador;
            $archivo = fopen($rutaDelArchivo, 'r');
            $infoCostoCargo = array();
            $primeraLinea = true;

            // Extraer cada línea del archivo CSV y convertirlo en un arreglo
            while($linea = fgetcsv($archivo, 1000, $delimitador)) {
                if (!$primeraLinea) {
                    $registro = $linea;
                    array_push($infoCostoCargo, $registro);
                } else {
                    $primeraLinea = false;
                }
            }

            fclose($archivo);

            return $this->procesarArchivoInfoCostoCargo($infoCostoCargo,
                                                        $request->con_fk_id,
                                                        $request->ins_fk_id,
                                                        $request->imo_ano,
                                                        $request->imo_mes);
        } else {
            throw new \Exception('Imposible completar la petición.');
        }
    }

    private function procesarArchivoInfoManoObra($infoManoObra, $con_fk_id, $ins_fk_id, $imo_ano, $imo_mes) {
        $resultados = new \stdClass();
        $resultados->errores = "";

        \DB::transaction(function() use(&$resultados, $infoManoObra, $con_fk_id, $ins_fk_id, $imo_ano, $imo_mes) {
            if (count($infoManoObra) === 0) {
                $resultados->correcto = false;
                $resultados->errores = 'El archivo está vacío. ';
                return json_encode($resultados);
            } else if (count($infoManoObra[0]) !== 4) {
                $resultados->correcto = false;
                $resultados->errores = 'La cantidad de columnas no corresponde. ';
                return json_encode($resultados);
            } else {
                $centrosCostoBd = CentrosCosto::on('costos_principal')
                                              ->where('con_fk_id', $con_fk_id)
                                              ->where('ins_fk_id', $ins_fk_id)
                                              ->where('cco_ano', $imo_ano)
                                              ->get()->toArray();


                $manoObraBd = ManoObra::on('costos_principal')
                                      ->where('con_fk_id', $con_fk_id)
                                      ->where('ins_fk_id', $ins_fk_id)
                                      ->where('mob_ano', $imo_ano)
                                      ->get()->toArray();


                $manoObraTercerosBd = ManoObraTerceros::on('costos_principal')
                                                      ->where('con_fk_id', $con_fk_id)
                                                      ->where('ins_fk_id', $ins_fk_id)
                                                      ->where('mot_ano', $imo_ano)
                                                      ->where('mot_mes', $imo_mes)
                                                      ->get()->toArray();

                $cargosExistentes = [];
                $centrosCostoExistentes = [];
                $manoObraTercerosExistente = [];

                // Crear las relaciones existentes en la base de datos
                foreach ($centrosCostoBd as $ccoDb) {
                    $centrosCostoExistentes[$ccoDb['cco_cod_homologado']] = $ccoDb['cco_pk_id'];
                }

                foreach ($manoObraBd as $mobDb) {
                    $cargosExistentes[$mobDb['mob_codigo']] = $mobDb['mob_pk_id'];
                }

                foreach ($manoObraTercerosBd as $motDb) {
                    $manoObraTercerosExistente[$motDb['mot_nit_tercero']] = new \stdClass();

                    $manoObraTercerosExistente[$motDb['mot_nit_tercero']]->mot_pk_id = $motDb['mot_pk_id'];
                    $manoObraTercerosExistente[$motDb['mot_nit_tercero']]->mot_costo = $motDb['mot_costo'];
                }

                $centrosCostoErroneos = "";
                $tercerosErroneos = "";
                $cargosErroneos = "";
                $numerosIncorrectos = false;
                $archivoCorrecto = true;
                $registrosProcesados = 0;

                // Validacion de los parametros del archivo
                foreach($infoManoObra as $imo) {
                    $tercero = $imo[0];
                    $cargo = $imo[1];
                    $centroCosto = $imo[2];
                    $horas = $imo[3];

                    $registrosProcesados++;

                    // Terceros
                    if (!isset($manoObraTercerosExistente[$tercero])) {
                        $tercerosErroneos .= $tercero.", ";
                        $archivoCorrecto = false;
                    }

                    // Cargos
                    if (!isset($cargosExistentes[$cargo])) {
                        $cargosErroneos .= $cargo.", ";
                        $archivoCorrecto = false;
                    }

                    // Centros costo
                    if (!isset($centrosCostoExistentes[$centroCosto])) {
                        $centrosCostoErroneos .= $centroCosto."\", ";
                        $archivoCorrecto = false;
                    }

                    // Horas trabajadas
                    if (!is_numeric($horas) || doubleval($horas) <= 0) {
                        $numerosIncorrectos = true;
                        $archivoCorrecto = false;
                    }
                }

                // Errores de terceros
                if ($tercerosErroneos !== "") {
                    $tercerosErroneos[strlen($tercerosErroneos) - 1] = " ";
                    $tercerosErroneos[strlen($tercerosErroneos) - 2] = " ";
                    $tercerosErroneos = "Los siguientes NIT de terceros no existen: ".$tercerosErroneos;

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $tercerosErroneos;
                }

                // Errores de centros de costo
                if ($centrosCostoErroneos !== "") {
                    $centrosCostoErroneos[strlen($centrosCostoErroneos) - 1] = " ";
                    $centrosCostoErroneos[strlen($centrosCostoErroneos) - 2] = " ";
                    $centrosCostoErroneos = "Los siguientes códigos de centros de costo son incorrectos: ".$centrosCostoErroneos;

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $centrosCostoErroneos;
                }

                // Errores de cargos
                if ($cargosErroneos !== "") {
                    $cargosErroneos[strlen($cargosErroneos) - 1] = " ";
                    $cargosErroneos[strlen($cargosErroneos) - 2] = " ";
                    $cargosErroneos = "Los siguientes códigos de cargos son incorrectos: ".$cargosErroneos;

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $cargosErroneos;
                }

                // Errores numericos
                if ($numerosIncorrectos) {
                    $resultados->errores .= "Hay valores numéricos incorrectos";
                }

                $resultados->registros = $registrosProcesados;

                if(!$numerosIncorrectos && $cargosErroneos == "" && $centrosCostoErroneos == "" && $tercerosErroneos == "") {
                    $resultados->correcto = true;
                } else {
                    $resultados->correcto = false;
                }

                // Procesamiento de los datos (post-validacion)
                if ($archivoCorrecto) {
                    $terceroActual = "";
                    $cargoActual = "";
                    $cantidadCargos = 1;
                    $primeraVez = false;

                    $infoActual = new \stdClass();
                    sort($infoManoObra);

                    foreach($infoManoObra as $imo) {
                        $tercero = $imo[0];
                        $cargo = $cargosExistentes[$imo[1]];
                        $centroCosto = $imo[2];
                        $horas = $imo[3];

                        // Es un nuevo tercero
                        if ($terceroActual !== $tercero) {
                            // Evitar un guardado en vacio al principio
                            if (!$primeraVez) {
                                $primeraVez = true;
                            } else {
                                if ($cantidadCargos == 1) {
                                    $infoActual->cargos[$cargoActual]->imo_valor = $manoObraTercerosExistente[$terceroActual]->mot_costo;
                                }

                                // Guardar el tercero con sus centros de costo
                                $this->guardarInformacionTercero($con_fk_id,
                                                                 $ins_fk_id,
                                                                 $imo_ano,
                                                                 $imo_mes,
                                                                 $infoActual);
                            }

                            $terceroActual = $tercero;
                            $cargoActual = $cargo;
                            $cantidadCargos = 1;

                            $infoActual = new \stdClass();
                            $infoActual->tercero = $manoObraTercerosExistente[$tercero]->mot_pk_id;
                            $infoActual->cargos = [];

                            $infoActual->cargos[$cargo] = new \stdClass();
                            $infoActual->cargos[$cargo]->imo_valor = null;
                            $infoActual->cargos[$cargo]->centrosCosto = [];

                            $infoActual->cargos[$cargo]->centrosCosto[$centrosCostoExistentes[$centroCosto]] = $horas;
                        } else {
                            // Revisar si el tercero tiene más de un cargo
                            if ($cargo !== $cargoActual) {
                                $cargoActual = $cargo;
                                $cantidadCargos++;

                                $infoActual->cargos[$cargo] = new \stdClass();
                                $infoActual->cargos[$cargo]->imo_valor = null;
                                $infoActual->cargos[$cargo]->centrosCosto = [];
                            }

                            $infoActual->cargos[$cargo]->centrosCosto[$centrosCostoExistentes[$centroCosto]] = $horas;
                        }
                    }

                    if ($cantidadCargos == 1) {
                        $infoActual->cargos[$cargoActual]->imo_valor = $manoObraTercerosExistente[$terceroActual]->mot_costo;
                    }

                    // Guardar el ultimo registro del tercero con sus centros de costo
                    $this->guardarInformacionTercero($con_fk_id,
                                                     $ins_fk_id,
                                                     $imo_ano,
                                                     $imo_mes,
                                                     $infoActual);
                }
            }

            $this->verificarAvance($con_fk_id, $ins_fk_id, $imo_ano, $imo_mes);
        });

        return json_encode($resultados);
    }

    // Solo se usa desde la carga del excel
    private function guardarInformacionTercero($con_fk_id, $ins_fk_id, $imo_ano, $imo_mes, $infoTercero) {
        // Informacion de horas por cargo/centro de costo
        $ccoAux = [];

        foreach($infoTercero->cargos as $key => $value) {
            array_push($ccoAux, array("mob_fk_id" => $key,
                                      "imo_valor" => $value->imo_valor,
                                      "centroCosto" => array()));

            $indice = count($ccoAux) - 1;

            foreach ($value->centrosCosto as $key2 => $value2) {
                array_push($ccoAux[$indice]["centroCosto"], array("cco_pk_id" => $key2,
                                                                  "imo_horas" => $value2));
            }
        }

        $cargosCco = json_encode($ccoAux);

        // Totalizar horas por centro de costo
        $horasAux = [];

        foreach($infoTercero->cargos as $key => $value) {
            foreach ($value->centrosCosto as $key2 => $value2) {
                if (!isset($horasAux[$key2])) {
                    $horasAux[$key2] = $value2;
                } else {
                    $horasAux[$key2] += $value2;
                }
            }
        }

        $arregloHorasAux = array();

        foreach ($horasAux as $key => $value) {
            array_push($arregloHorasAux, array("cco_pk_id" => $key, "imo_horas" => $value));
        }

        $horasCco = json_encode($arregloHorasAux);

        $request = new Request([
            'con_fk_id' => $con_fk_id,
            'ins_fk_id' => $ins_fk_id,
            'imo_ano' => $imo_ano,
            'imo_mes' => $imo_mes,
            'mot_fk_id' => $infoTercero->tercero,
            'ccoCargos' => $cargosCco,
            'ccoHoras' => $horasCco
        ]);

        $this->actualizarInformacionManoObra($request);
    }

    private function procesarArchivoInfoCostoCargo($infoCostoCargo, $con_fk_id, $ins_fk_id, $imo_ano, $imo_mes) {
        $resultados = new \stdClass();
        $resultados->errores = "";

        \DB::transaction(function() use(&$resultados, $infoCostoCargo, $con_fk_id, $ins_fk_id, $imo_ano, $imo_mes) {
            if (count($infoCostoCargo) === 0) {
                $resultados->correcto = false;
                $resultados->errores = 'El archivo está vacío. ';
                return json_encode($resultados);
            } else if (count($infoCostoCargo[0]) !== 3) {
                $resultados->correcto = false;
                $resultados->errores = 'La cantidad de columnas no corresponde. ';
                return json_encode($resultados);
            } else {
                sort($infoCostoCargo);

                // Parametros
                $tercerosMultiCargo = \DB::select("with info_imo as (
                                                        select mot_fk_id, count(distinct mob_fk_id) as conteo
                                                        from costos_principal.informacion_mano_obra as imo
                                                        where con_fk_id = ".$con_fk_id." and
                                                            ins_fk_id = '".$ins_fk_id."' and
                                                            imo_ano = ".$imo_ano." and
                                                            imo_mes = ".$imo_mes."
                                                        group by 1
                                                   )
                                                   select imo.mot_fk_id, mot_nit_tercero, mot_costo, imo2.conteo as cargos
                                                   from (
                                                            select mot_fk_id
                                                            from info_imo
                                                            where info_imo.conteo > 1
                                                   ) as imo
                                                   join costos_principal.mano_obra_terceros as mot on (imo.mot_fk_id = mot.mot_pk_id)
                                                   join (
                                                            select *
                                                            from info_imo
                                                            where info_imo.conteo > 1
                                                   ) as imo2 on (imo.mot_fk_id = imo2.mot_fk_id)");


                $cargosBd = ManoObra::on('costos_principal')
                                    ->where('con_fk_id', $con_fk_id)
                                    ->where('ins_fk_id', $ins_fk_id)
                                    ->where('mob_ano', $imo_ano)
                                    ->get()->toArray();

                $tercerosExistentes = [];
                $cargosTerExistentes = [];
                $cargosExistentes = [];
                $listadoTerceroMulti = "";

                foreach ($tercerosMultiCargo as $imo) {
                    $tercerosExistentes[$imo->mot_nit_tercero] = new \stdClass();

                    $tercerosExistentes[$imo->mot_nit_tercero]->mot_fk_id = $imo->mot_fk_id;
                    $tercerosExistentes[$imo->mot_nit_tercero]->mot_costo = $imo->mot_costo;
                    $tercerosExistentes[$imo->mot_nit_tercero]->cargos = $imo->cargos;

                    if ($listadoTerceroMulti != "") {
                        $listadoTerceroMulti .= ",";
                    }

                    $listadoTerceroMulti .= $imo->mot_fk_id;
                }

                $cargosTercerosBd = \DB::select("select distinct mot_nit_tercero, mob_codigo
                                                from costos_principal.informacion_mano_obra as imo
                                                join costos_principal.mano_obra_terceros as mot on (imo.mot_fk_id = mot.mot_pk_id)
                                                join costos_principal.mano_obra as mob on (imo.mob_fk_id = mob.mob_pk_id)
                                                where imo.con_fk_id = ".$con_fk_id." and
                                                      imo.ins_fk_id = '".$ins_fk_id."' and
                                                      imo_ano = ".$imo_ano." and
                                                      imo_mes = ".$imo_mes." and
                                                      imo.mot_fk_id in (".$listadoTerceroMulti.")
                                                order by 1");

                foreach ($cargosTercerosBd as $cte) {
                    $cargosTerExistentes[$cte->mot_nit_tercero][$cte->mob_codigo] = "OK";
                }

                foreach ($cargosBd as $mob) {
                    $cargosExistentes[$mob['mob_codigo']] = $mob['mob_pk_id'];
                }

                // Verificacion del archivo
                $tercerosErroneos = "";
                $cargosErroneos = "";
                $relacionTerceroCargo = "";
                $terCargosImcompletos = "";
                $costoErroneo = false;
                $costoTotalErroneo = "";

                $tercerosCompilado = [];

                $terceroActual = '@wedrt789*/*';
                $noCargos = 0;
                $totalDinero = 0;
                $primeraVez = true;

                foreach ($infoCostoCargo as $icc) {
                    $tercero = $icc[0];
                    $cargo = $icc[1];
                    $costo = $icc[2];

                    if ($tercero != $terceroActual) {
                        if (!$primeraVez) {
                            $tercerosCompilado[$terceroActual]->noCargos = $noCargos;
                            $tercerosCompilado[$terceroActual]->total = $totalDinero;
                        } else {
                            $primeraVez = false;
                        }

                        $terceroActual = $tercero;

                        $tercerosCompilado[$tercero] = new \stdClass();

                        $tercerosCompilado[$tercero]->cargos = [];
                        $tercerosCompilado[$tercero]->cargos[$cargo] = $costo;

                        $noCargos = 1;
                        $totalDinero = $costo;
                    } else {
                        if (!isset($tercerosCompilado[$tercero]->cargo[$cargo])) {
                            $noCargos++;
                            $totalDinero += $costo;
                        }
        
                        $tercerosCompilado[$tercero]->cargos[$cargo] = $costo;
                    }
                }

                $tercerosCompilado[$terceroActual]->noCargos = $noCargos;
                $tercerosCompilado[$terceroActual]->total = $totalDinero;

                error_log(json_encode($tercerosCompilado));

                foreach ($tercerosCompilado as $ter => $info) {
                    if (isset($tercerosExistentes[$ter])) {

                        foreach ($info->cargos as $key => $value) {
                            if (isset($cargosExistentes[$key])) {
                                if (isset($cargosTerExistentes[$ter][$key])) {
                                    if (!is_numeric($value) || $value <= 0) {
                                        $costoErroneo = true;
                                    }
                                } else {
                                    if ($relacionTerceroCargo != "") {
                                        $relacionTerceroCargo .= ", ";
                                    }

                                    $relacionTerceroCargo .= $ter.' - '.$key;
                                }
                            } else {
                                if ($cargosErroneos != "") {
                                    $cargosErroneos .= ", ";
                                }
                
                                $cargosErroneos .= $key;
                            }
                        }

                        if (intval($tercerosExistentes[$ter]->cargos) != intval($info->noCargos)) {
                            if ($terCargosImcompletos != "") {
                                $terCargosImcompletos .= ", ";
                            }

                            $terCargosImcompletos .= $ter;
                        }

                        if (intval($tercerosExistentes[$ter]->mot_costo) != intval($info->total)) {
                            if ($costoTotalErroneo != "") {
                                $costoTotalErroneo .= ", ";
                            }

                            $costoTotalErroneo .= $ter;
                        }
                    } else {
                        if ($tercerosErroneos != "") {
                            $tercerosErroneos .= ", ";
                        }
        
                        $tercerosErroneos .= $ter;
                    }
                }

                // Validacion de errores
                if ($tercerosErroneos != "") {
                    $tercerosErroneos = "Los siguientes NIT de terceros no existen o solo tienen un cargo: ".$tercerosErroneos.". ";

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $tercerosErroneos;
                }

                if ($cargosErroneos != "") {
                    $cargosErroneos = "Los siguientes cargos no existen: ".$cargosErroneos.". ";

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $cargosErroneos;
                }

                if ($relacionTerceroCargo != "") {
                    $relacionTerceroCargo = "Los siguientes relaciones NIT - cargo no existen: ".$relacionTerceroCargo.". ";

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $relacionTerceroCargo;
                }

                if ($terCargosImcompletos != "") {
                    $terCargosImcompletos = "Los siguientes NIT no tiene la información de cargos completa o no corresponde: ".$terCargosImcompletos.". ";

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $terCargosImcompletos;
                }

                if ($costoErroneo) {
                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= "Hay costos de cargos erroneos o menores o iguales a cero. ";
                }

                if ($costoTotalErroneo != "") {
                    $costoTotalErroneo = "La suma de los siguientes NIT no suma el valor del tercero: ".$costoTotalErroneo.". ";

                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= $costoTotalErroneo;
                }

                $resultados->registros = 0;

                if (!$costoErroneo && $terCargosImcompletos == "" && $relacionTerceroCargo == "" && $cargosErroneos == "" &&
                    $tercerosErroneos == "" && $costoTotalErroneo == "") {
                    $resultados->correcto = true;
                } else {
                    $resultados->correcto = false;
                }

                if ($resultados->correcto) {
                    $noRegistros = 0;

                    // Carga de la informacion
                    foreach ($infoCostoCargo as $icc) {
                        $tercero = $icc[0];
                        $cargo = $icc[1];
                        $costo = $icc[2];

                        InformacionManoObra::on('costos_principal')
                                        ->where('con_fk_id', $con_fk_id)
                                        ->where('ins_fk_id', $ins_fk_id)
                                        ->where('imo_ano', $imo_ano)
                                        ->where('imo_mes', $imo_mes)
                                        ->where('mot_fk_id', $tercerosExistentes[$tercero]->mot_fk_id)
                                        ->where('mob_fk_id', $cargosExistentes[$cargo])
                        ->update([
                            "imo_valor" => $costo
                        ]);

                        $noRegistros++;
                    }

                    $resultados->registros = $noRegistros;

                    $this->verificarAvance($con_fk_id, $ins_fk_id, $imo_ano, $imo_mes);
                }
            }
        });

        return json_encode($resultados);
    }

    public function verificarAvance($contrato, $institucion, $ano, $mes) {
        // Verificar si existe registro del avance
        $conteo = AvanceModulos::on('costos_principal')
                               ->where('con_fk_id', $contrato)
                               ->where('ins_fk_id', $institucion)
                               ->where('avm_ano', $ano)
                               ->where('avm_mes', $mes)
                               ->count();

        // Verificar el avance del modulo
        $imo = InformacionManoObra::on('costos_principal')
                                  ->where('con_fk_id', $contrato)
                                  ->where('ins_fk_id', $institucion)
                                  ->where('imo_ano', $ano)
                                  ->where('imo_mes', $mes)
                                  ->whereNotNull('imo_valor')
                                  ->distinct('mot_fk_id')
                                  ->count('mot_fk_id');

        $mot = ManoObraTerceros::on('costos_principal')
                               ->where('con_fk_id', $contrato)
                               ->where('ins_fk_id', $institucion)
                               ->where('mot_ano', $ano)
                               ->where('mot_mes', $mes)
                               ->count();

        if ($conteo > 0) {
            if ($imo > 0 && $imo == $mot) {
                AvanceModulos::on('costos_principal')
                             ->where('con_fk_id', $contrato)
                             ->where('ins_fk_id', $institucion)
                             ->where('avm_ano', $ano)
                             ->where('avm_mes', $mes)
                ->update(
                    [
                        "avm_info_mano_obra" => true
                    ]
                );
            } else {
                AvanceModulos::on('costos_principal')
                             ->where('con_fk_id', $contrato)
                             ->where('ins_fk_id', $institucion)
                             ->where('avm_ano', $ano)
                             ->where('avm_mes', $mes)
                ->update(
                    [
                        "avm_info_mano_obra" => false
                    ]
                ); 
            }
        } else {
            if ($imo > 0 && $imo == $mot) {
                AvanceModulos::on('costos_principal')
                ->create(
                    [
                        "con_fk_id" => $contrato,
                        "ins_fk_id" => $institucion,
                        "avm_ano" => $ano,
                        "avm_mes" => $mes,
                        "avm_info_mano_obra" => true
                    ]
                );
            } else {
                AvanceModulos::on('costos_principal')
                ->create(
                    [
                        "con_fk_id" => $contrato,
                        "ins_fk_id" => $institucion,
                        "avm_ano" => $ano,
                        "avm_mes" => $mes,
                        "avm_info_mano_obra" => false
                    ]
                );
            }
        }          
    }
}
