<?php

namespace App\Http\Controllers;

use App\Models\InformacionFinanciera;
use App\Models\DistribucionIfmCostosCuentas;
use App\Models\DistribucionIfmCostosBases;
use App\Models\DistribucionValorDirecto;
use App\Models\CuentasContables;
use App\Models\CentrosCosto;
use App\Models\InformacionBasesDistribucion;
use App\Models\ManoObraTerceros;
use App\Models\AvanceModulos;
use Illuminate\Http\Request;

class InformacionFinancieraController extends Controller
{
    private $apiKey;

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

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

    public function crearMovimientoInfoFinanciera(Request $request) {
        $valor = 0;
        $id = null;

        \DB::transaction(function() use($request, &$valor, &$id) {
            $con_fk_id = $request->input('con_fk_id');
            $ins_fk_id = $request->input('ins_fk_id');
            $ifm_ano = $request->input('ifm_ano');
            $ifm_mes = $request->input('ifm_mes');
            $cuc_fk_id = $request->input('cuc_fk_id');
            $ifm_nit_tercero = $request->input('ifm_nit_tercero');
            $ifm_razon_social = $request->input('ifm_razon_social');
            $ifm_detalle_movimiento = $request->input('ifm_detalle_movimiento');
            $ifm_debito = $request->input('ifm_debito');
            $ifm_credito = $request->input('ifm_credito');

            $naturaleza = CuentasContables::on('costos_principal')
                                          ->where('con_fk_id', $con_fk_id)
                                          ->where('ins_fk_id', $ins_fk_id)
                                          ->where('cuc_ano', $ifm_ano)
                                          ->where('cuc_pk_id', $cuc_fk_id)
                                          ->value('nac_fk_id');

            if ($naturaleza == 2) {
                $valor = $ifm_credito - $ifm_debito;
            } else {
                $valor = $ifm_debito - $ifm_credito;
            }

            $id = InformacionFinanciera::on('costos_principal')->create(
                [
                    "con_fk_id" => $con_fk_id,
                    "ins_fk_id" => $ins_fk_id,
                    "ifm_ano" => $ifm_ano,
                    "ifm_mes" => $ifm_mes,
                    "cuc_fk_id" => $cuc_fk_id,
                    "ifm_nit_tercero" => $ifm_nit_tercero,
                    "ifm_razon_social" => $ifm_razon_social,
                    "ifm_detalle_movimiento" => $ifm_detalle_movimiento,
                    "ifm_debito" =>  $ifm_debito,
                    "ifm_credito" => $ifm_credito,
                    "ifm_valor" => $valor,
                    "ifm_asignado" => false,
                    "ifm_preasignado" => false,
                    "ifm_mano_obra" => false
                ]
            )->ifm_pk_id;

            $this->verificarAvance($con_fk_id, $ins_fk_id, $ifm_ano, $ifm_mes);
        });

        return array("response" => [$id, $valor]);
    }

    public function crearDistribucionCostosIfm(Request $request) {
        \DB::transaction(function() use($request) {
            $dcCuentas = DistribucionIfmCostosCuentas::on('costos_principal');
            $dcBases = DistribucionIfmCostosBases::on('costos_principal');
            $dvDirecto = DistribucionValorDirecto::on('costos_principal');

            $movimientos = json_decode($request->input('movimientos'));
            $centrosCosto = json_decode($request->input('centrosCosto'));
            $basesDistribucion = json_decode($request->input('basesDistribucion'));
            $dineroValorDirecto = json_decode($request->input('dineroValorDirecto'));

            foreach ($movimientos as $ifm) {
                // Centros de costo
                foreach ($centrosCosto as $cco) {
                    $id = $dcCuentas->create(
                        [
                            "con_fk_id" => $request->input("con_fk_id"),
                            "ins_fk_id" => $request->input("ins_fk_id"),
                            "dcu_ano" => $request->input("ifm_ano"),
                            "dcu_mes" => $request->input("ifm_mes"),
                            "ifm_fk_id" => $ifm->ifm_pk_id,
                            "cco_fk_id" => $cco->cco_pk_id
                        ]
                    );
                }

                // Bases de distribucion
                foreach ($basesDistribucion as $bdi) {
                    $id = $dcBases->create(
                        [
                            "con_fk_id" => $request->input("con_fk_id"),
                            "ins_fk_id" => $request->input("ins_fk_id"),
                            "dib_ano" => $request->input("ifm_ano"),
                            "dib_mes" => $request->input("ifm_mes"),
                            "ifm_fk_id" => $ifm->ifm_pk_id,
                            "bdi_fk_id" => $bdi->bdi_pk_id,
                            "dib_ponderacion" => $bdi->dib_ponderacion
                        ]
                    );
                }

                // Dinero de valor directo
                if (count($basesDistribucion) === 1 && $basesDistribucion[0]->bdi_pk_id === 1) {
                    foreach ($dineroValorDirecto as $dvd) {
                        $id = $dvDirecto->create(
                            [
                                "con_fk_id" => $request->input('con_fk_id'),
                                "ins_fk_id" => $request->input('ins_fk_id'),
                                "dvd_ano" => $request->input('ifm_ano'),
                                "dvd_mes" => $request->input('ifm_mes'),
                                "ifm_fk_id" => $ifm->ifm_pk_id,
                                "cco_fk_id" => $dvd->cco_fk_id,
                                "dvd_valor" => $dvd->dvd_valor
                            ]
                        );
                    }
                }

                // Actualizar la asignacion del movimiento
                InformacionFinanciera::on('costos_principal')
                                     ->where('ifm_pk_id', $ifm->ifm_pk_id)
                                     ->update(['ifm_asignado' => true]);
            }

            $this->verificarAvance($request->input("con_fk_id"),
                                   $request->input("ins_fk_id"),
                                   $request->input("ifm_ano"),
                                   $request->input("ifm_mes"));
        });

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

    public function actualizarDistribucionCostosIfm(Request $request) {
        \DB::transaction(function() use($request) {
            $dcCuentas = DistribucionIfmCostosCuentas::on('costos_principal');
            $dcBases = DistribucionIfmCostosBases::on('costos_principal');
            $dvDirecto = DistribucionValorDirecto::on('costos_principal');

            $movimientos = json_decode($request->input('movimientos'));
            $centrosCosto = json_decode($request->input('centrosCosto'));
            $basesDistribucion = json_decode($request->input('basesDistribucion'));
            $dineroValorDirecto = json_decode($request->input('dineroValorDirecto'));

            foreach ($movimientos as $ifm) {
                // BORRAR INFORMACION ANTERIOR
                $dcCuentas->where('con_fk_id', $request->input("con_fk_id"))
                          ->where('ins_fk_id', $request->input("ins_fk_id"))
                          ->where('dcu_ano', $request->input("ifm_ano"))
                          ->where('dcu_mes', $request->input("ifm_mes"))
                          ->where('ifm_fk_id', $ifm->ifm_pk_id)
                          ->delete();

                $dcBases->where('con_fk_id', $request->input("con_fk_id"))
                        ->where('ins_fk_id', $request->input("ins_fk_id"))
                        ->where('dib_ano', $request->input("ifm_ano"))
                        ->where('dib_mes', $request->input("ifm_mes"))
                        ->where('ifm_fk_id', $ifm->ifm_pk_id)
                        ->delete();

                $dvDirecto->where('con_fk_id', $request->input("con_fk_id"))
                          ->where('ins_fk_id', $request->input("ins_fk_id"))
                          ->where('dvd_ano', $request->input("ifm_ano"))
                          ->where('dvd_mes', $request->input("ifm_mes"))
                          ->where('ifm_fk_id', $ifm->ifm_pk_id)
                          ->delete();

                // AGREGAR INFORMACION ACTUALIZADA
                // Centros de costo
                foreach ($centrosCosto as $cco) {
                    $id = $dcCuentas->create(
                        [
                            "con_fk_id" => $request->input("con_fk_id"),
                            "ins_fk_id" => $request->input("ins_fk_id"),
                            "dcu_ano" => $request->input("ifm_ano"),
                            "dcu_mes" => $request->input("ifm_mes"),
                            "ifm_fk_id" => $ifm->ifm_pk_id,
                            "cco_fk_id" => $cco->cco_pk_id
                        ]
                    );
                }

                // Bases de distribucion
                foreach ($basesDistribucion as $bdi) {
                    $id = $dcBases->create(
                        [
                            "con_fk_id" => $request->input("con_fk_id"),
                            "ins_fk_id" => $request->input("ins_fk_id"),
                            "dib_ano" => $request->input("ifm_ano"),
                            "dib_mes" => $request->input("ifm_mes"),
                            "ifm_fk_id" => $ifm->ifm_pk_id,
                            "bdi_fk_id" => $bdi->bdi_pk_id,
                            "dib_ponderacion" => $bdi->dib_ponderacion
                        ]
                    );
                }

                // Dinero de valor directo
                if (count($basesDistribucion) === 1 && $basesDistribucion[0]->bdi_pk_id === 1) {
                    foreach ($dineroValorDirecto as $dvd) {
                        $id = $dvDirecto->create(
                            [
                                "con_fk_id" => $request->input('con_fk_id'),
                                "ins_fk_id" => $request->input('ins_fk_id'),
                                "dvd_ano" => $request->input('ifm_ano'),
                                "dvd_mes" => $request->input('ifm_mes'),
                                "ifm_fk_id" => $ifm->ifm_pk_id,
                                "cco_fk_id" => $dvd->cco_fk_id,
                                "dvd_valor" => $dvd->dvd_valor
                            ]
                        );
                    }
                }

                // Actualizar la asignacion del movimiento
                InformacionFinanciera::on('costos_principal')
                                     ->where('ifm_pk_id', $ifm->ifm_pk_id)
                                     ->update(['ifm_asignado' => true]);
            }
        });

        $this->verificarAvance($request->input("con_fk_id"),
                               $request->input("ins_fk_id"),
                               $request->input("ifm_ano"),
                               $request->input("ifm_mes"));
    }

    public function aprobarMasivamente(Request $request) {
        \DB::transaction(function() use($request) {
            $movimientos = json_decode($request->input('movimientos'));

            foreach ($movimientos as $movimiento) {
                $centrosCosto = DistribucionIfmCostosCuentas::on('costos_principal')
                                                            ->selectRaw('cco_fk_id as cco_pk_id')
                                                            ->where('con_fk_id', $request->input('con_fk_id'))
                                                            ->where('ins_fk_id', $request->input('ins_fk_id'))
                                                            ->where('dcu_ano', $request->input('ifm_ano'))
                                                            ->where('dcu_mes', $request->input('ifm_mes'))
                                                            ->where('ifm_fk_id', $movimiento->ifm_pk_id)
                                                            ->get()->toArray();

                $centrosCosto = json_encode($centrosCosto);

                $basesDistribucion = DistribucionIfmCostosBases::on('costos_principal')
                                                               ->selectRaw('bdi_fk_id as bdi_pk_id, dib_ponderacion')
                                                               ->where('con_fk_id', $request->input('con_fk_id'))
                                                               ->where('ins_fk_id', $request->input('ins_fk_id'))
                                                               ->where('dib_ano', $request->input('ifm_ano'))
                                                               ->where('dib_mes', $request->input('ifm_mes'))
                                                               ->where('ifm_fk_id', $movimiento->ifm_pk_id)
                                                               ->get()->toArray();

                $basesDistribucion = json_encode($basesDistribucion);

                $myRequest = new \Illuminate\Http\Request();
                $myRequest->setMethod('POST');

                $myRequest->request->add(['con_fk_id' => $request->input('con_fk_id')]);
                $myRequest->request->add(['ins_fk_id' => $request->input('ins_fk_id')]);
                $myRequest->request->add(['ifm_ano' => $request->input('ifm_ano')]);
                $myRequest->request->add(['ifm_mes' => $request->input('ifm_mes')]);
                $myRequest->request->add(['movimientos' => json_encode([$movimiento])]);
                $myRequest->request->add(['centrosCosto' => $centrosCosto]);
                $myRequest->request->add(['basesDistribucion' => $basesDistribucion]);

                $this->actualizarDistribucionCostosIfm($myRequest);
            }
        });
    }

    public function importarInformacionMesAnterior(Request $request) {
        \DB::transaction(function() use($request) {
            $contrato = $request->input('con_fk_id');
            $institucion = $request->input('ins_fk_id');
            $ano = $request->input('ifm_ano');
            $mesActual = $request->input('ifm_mes_actual');
            $mesAnterior = $request->input('ifm_mes_anterior');

            // Buscar las cuentas cuentas y terceros validos para importar
            $relaciones = \DB::select("select rel.cuc_fk_id, rel.ifm_nit_tercero
                                       from (
                                            select cco.cuc_fk_id, cco.ifm_nit_tercero
                                            from (
                                                /* CENTROS DE COSTO */
                                        
                                                /* Traer los que son asiganbles */
                                                select cuc_fk_id, ifm_nit_tercero
                                                from (
                                                    /* Mirar las relaciones unicas entre cuenta, tercero y cco */
                                                    select distinct ifm_agg.cuc_fk_id, ifm_agg.ifm_nit_tercero, ifm_agg.cco
                                                    from (
                                                        /* Los movimientos junto con los centros de costo en un sola línea */
                                                        select ifm.ifm_pk_id, ifm.cuc_fk_id, ifm.ifm_nit_tercero, string_agg(cast(ifm.cco_fk_id as text), '-') as cco
                                                        from (
                                                            /* Los movimientos junto con los centros de costo */
                                                            select ifm.ifm_pk_id, cuc_fk_id, ifm_nit_tercero, cco_fk_id
                                                            from costos_principal.informacion_financiera as ifm
                                                            join costos_principal.cuentas_contables as cuc on (ifm.cuc_fk_id = cuc.cuc_pk_id)
                                                            join costos_principal.distribucion_ifm_costos_cuentas as dcc on (ifm.ifm_pk_id = dcc.ifm_fk_id)
                                                            where ifm.con_fk_id = ".$contrato." and
                                                                ifm.ins_fk_id = '".$institucion."' and
                                                                ifm_ano = ".$ano." and
                                                                ifm_mes = ".$mesAnterior." and
                                                                ifm_mano_obra = false
                                                            order by 1, 2, 3, 4
                                                        ) as ifm
                                                        group by 1, 2, 3
                                                    ) ifm_agg
                                                    order by 1, 2
                                                ) as ifm_cco_final
                                                group by 1, 2
                                                having count(*) = 1
                                            ) as cco
                                            join (
                                                /* BASES DISTRIBUCION */
                                        
                                                /* Traer los que son asiganbles */
                                                select cuc_fk_id, ifm_nit_tercero
                                                from (
                                                    /* Mirar las relaciones unicas entre cuenta, tercero y bdi */
                                                    select distinct ifm_agg.cuc_fk_id, ifm_agg.ifm_nit_tercero, ifm_agg.bdi
                                                    from (
                                                        /* Los movimientos junto con bases dedistribucion y ponderacion en un sola línea */
                                                        select ifm.ifm_pk_id, ifm.cuc_fk_id, ifm.ifm_nit_tercero, string_agg(cast(ifm.bdi_fk_id || '/' || ifm.dib_ponderacion  as text), '-') as bdi
                                                        from (
                                                            /* Los movimientos junto con los centros de costo */
                                                            select ifm.ifm_pk_id, cuc_fk_id, ifm_nit_tercero, bdi_fk_id, dib_ponderacion
                                                            from costos_principal.informacion_financiera as ifm
                                                            join costos_principal.cuentas_contables as cuc on (ifm.cuc_fk_id = cuc.cuc_pk_id)
                                                            join costos_principal.distribucion_ifm_costos_bases as dcb on (ifm.ifm_pk_id = dcb.ifm_fk_id)
                                                            where ifm.con_fk_id = ".$contrato." and
                                                                  ifm.ins_fk_id = '".$institucion."' and
                                                                  ifm_ano = ".$ano." and
                                                                  ifm_mes = ".$mesAnterior." and
                                                                  ifm_mano_obra = false
                                                            order by 1, 2, 3, 4, 5
                                                        ) as ifm
                                                        group by 1, 2, 3
                                                    ) ifm_agg
                                                    order by 1, 2
                                                ) as ifm_bdi_final
                                                group by 1, 2
                                                having count(*) = 1	
                                            ) as bdi on (cco.cuc_fk_id = bdi.cuc_fk_id and cco.ifm_nit_tercero = bdi.ifm_nit_tercero)
                                       ) as rel
                                       join costos_principal.informacion_financiera as ifm on (ifm.cuc_fk_id = rel.cuc_fk_id and
                                                                                               ifm.ifm_nit_tercero = rel.ifm_nit_tercero and
                                                                                               ifm.ifm_ano = ".$ano." and ifm.ifm_mes = ".$mesActual." and
                                                                                               ifm_asignado = false and ifm_mano_obra = false)");

            // Buscar las relaciones y crear las asignaciones
            foreach($relaciones as $relacion) {
                // Buscar los movimientos que cumplan con la relacion
                $movimientos = InformacionFinanciera::on('costos_principal')
                                                    ->where('con_fk_id', $contrato)
                                                    ->where('ins_fk_id', $institucion)
                                                    ->where('ifm_ano', $ano)
                                                    ->where('ifm_mes', $mesActual)
                                                    ->where('cuc_fk_id', $relacion->cuc_fk_id)
                                                    ->where('ifm_nit_tercero', $relacion->ifm_nit_tercero)
                                                    ->where('ifm_asignado', false)
                                                    ->get()->toArray();

                // Movimiento del mes anterior con la informacion
                $movMesAnterior = InformacionFinanciera::on('costos_principal')
                                                       ->where('con_fk_id', $contrato)
                                                       ->where('ins_fk_id', $institucion)
                                                       ->where('ifm_ano', $ano)
                                                       ->where('ifm_mes', $mesAnterior)
                                                       ->where('cuc_fk_id', $relacion->cuc_fk_id)
                                                       ->where('ifm_nit_tercero', $relacion->ifm_nit_tercero)
                                                       ->first()['ifm_pk_id'];

                // Informacion que se va a importar
                $centrosCosto = DistribucionIfmCostosCuentas::on('costos_principal')
                                                            ->where('con_fk_id', $contrato)
                                                            ->where('ins_fk_id', $institucion)
                                                            ->where('dcu_ano', $ano)
                                                            ->where('dcu_mes', $mesAnterior)
                                                            ->where('ifm_fk_id', $movMesAnterior)
                                                            ->get()->toArray();


                $basesDistribucion = DistribucionIfmCostosBases::on('costos_principal')
                                                               ->where('con_fk_id', $contrato)
                                                               ->where('ins_fk_id', $institucion)
                                                               ->where('dib_ano', $ano)
                                                               ->where('dib_mes', $mesAnterior)
                                                               ->where('ifm_fk_id', $movMesAnterior)
                                                               ->get()->toArray();

                foreach ($movimientos as $ifm) {
                    // Borrar la informacion anterior
                    DistribucionIfmCostosCuentas::on('costos_principal')
                                                ->where('ifm_fk_id', $ifm['ifm_pk_id'])
                                                ->delete();

                    DistribucionIfmCostosBases::on('costos_principal')
                                              ->where('ifm_fk_id', $ifm['ifm_pk_id'])
                                              ->delete();

                    // Insertar la nueva informacion
                    foreach ($centrosCosto as $cco) {
                        DistribucionIfmCostosCuentas::on('costos_principal')->create(
                            [
                                "con_fk_id" => $contrato,
                                "ins_fk_id" => $institucion,
                                "dcu_ano" => $ano,
                                "dcu_mes" => $mesActual,
                                "ifm_fk_id" => $ifm['ifm_pk_id'],
                                "cco_fk_id" => $cco['cco_fk_id']
                            ]
                        );
                    }

                    foreach ($basesDistribucion as $bdi) {
                        DistribucionIfmCostosBases::on('costos_principal')->create(
                            [
                                "con_fk_id" => $contrato,
                                "ins_fk_id" => $institucion,
                                "dib_ano" => $ano,
                                "dib_mes" => $mesActual,
                                "ifm_fk_id" => $ifm['ifm_pk_id'],
                                "bdi_fk_id" => $bdi['bdi_fk_id'],
                                "dib_ponderacion" => $bdi['dib_ponderacion']
                            ]
                        );
                    }

                    InformacionFinanciera::on('costos_principal')
                                         ->where('ifm_pk_id', $ifm['ifm_pk_id'])
                    ->update(
                        [
                            "ifm_preasignado" => true,
                            "ifm_asignado" => false
                        ]
                    );
                }
            }
        });
    }

    public function getInformacionFinanciera(Request $request) {
        ini_set("memory_limit", "1024M");

        return InformacionFinanciera::on('costos_principal')
                                    ->selectRaw('ifm_pk_id,
                                                 cuc_fk_id,
                                                 ifm_nit_tercero,
                                                 ifm_razon_social,
                                                 ifm_detalle_movimiento,
                                                 ifm_debito,
                                                 ifm_credito,
                                                 ifm_valor,
                                                 ifm_asignado,
                                                 ifm_preasignado,
                                                 ifm_mano_obra')
                                    ->where('con_fk_id', $request->input('con_fk_id'))
                                    ->where('ins_fk_id', $request->input('ins_fk_id'))
                                    ->where('ifm_ano', $request->input('ifm_ano'))
                                    ->where('ifm_mes', $request->input('ifm_mes'))
                                    ->where('ifm_mano_obra', false)
                                    ->orderBy('ifm_pk_id')
                                    ->get()->toArray();
    }

    public function getValorIfmTipoCuenta(Request $request) {
        return \DB::select("
            select coalesce(sum(ifm_valor) filter(where substr(cuc_cuenta, 1, 1) = '4'), 0) as cuc4,
                   coalesce(sum(ifm_valor) filter(where substr(cuc_cuenta, 1, 1) = '5'), 0) as cuc5,
                   coalesce(sum(ifm_valor) filter(where substr(cuc_cuenta, 1, 1) = '6'), 0) as cuc6,
                   coalesce(sum(ifm_valor) filter(where substr(cuc_cuenta, 1, 1) = '7'), 0) as cuc7
            from costos_principal.informacion_financiera as ifm
            join costos_principal.cuentas_contables as cuc on (ifm.cuc_fk_id = cuc.cuc_pk_id)
            where ifm.con_fk_id = ".$request->input('con_fk_id')." and
                  ifm.ins_fk_id = '".$request->input('ins_fk_id')."' and
                  ifm_ano = ".$request->input('ifm_ano')." and
                  ifm_mes = ".$request->input('ifm_mes'));
    }

    public function getDistribucionIfmCuentas(Request $request) {
        return DistribucionIfmCostosCuentas::on('costos_principal')
                                           ->where('con_fk_id', $request->input('con_fk_id'))
                                           ->where('ins_fk_id', $request->input('ins_fk_id'))
                                           ->where('dcu_ano', $request->input('dcu_ano'))
                                           ->where('dcu_mes', $request->input('dcu_mes'))
                                           ->where('ifm_fk_id', $request->input('ifm_fk_id'))
                                           ->get()->toArray();
    }

    public function getDistribucionIfmBases(Request $request) {
        return DistribucionIfmCostosBases::on('costos_principal')
                                         ->where('con_fk_id', $request->input('con_fk_id'))
                                         ->where('ins_fk_id', $request->input('ins_fk_id'))
                                         ->where('dib_ano', $request->input('dib_ano'))
                                         ->where('dib_mes', $request->input('dib_mes'))
                                         ->where('ifm_fk_id', $request->input('ifm_fk_id'))
                                         ->get()->toArray();
    }

    public function getDistribucionValorDirecto(Request $request) {
        return DistribucionValorDirecto::on('costos_principal')
                                       ->where('con_fk_id', $request->input('con_fk_id'))
                                       ->where('ins_fk_id', $request->input('ins_fk_id'))
                                       ->where('dvd_ano', $request->input('dvd_ano'))
                                       ->where('dvd_mes', $request->input('dvd_mes'))
                                       ->where('ifm_fk_id', $request->input('ifm_fk_id'))
                                       ->get()->toArray();
    }

    public function getMovimientosValorDirecto(Request $request) {
        return \DB::select("select distinct ifm_fk_id
                            from costos_principal.distribucion_ifm_costos_bases
                            where con_fk_id = ".$request->input('con_fk_id')." and
                                  ins_fk_id = '".$request->input('ins_fk_id')."' and
                                  dib_ano = ".$request->input('ifm_ano')." and
                                  dib_mes = ".$request->input('ifm_mes')." and
                                  bdi_fk_id = 1
                            order by 1");
    }

    public function getValorTotalMovimientos(Request $request) {
        return InformacionFinanciera::on('costos_principal')
                                    ->join('cuentas_contables', 'cuc_pk_id', 'cuc_fk_id')
                                    ->where('informacion_financiera.con_fk_id', $request->input('con_fk_id'))
                                    ->where('informacion_financiera.ins_fk_id', $request->input('ins_fk_id'))
                                    ->where('ifm_ano', $request->input('ifm_ano'))
                                    ->where('ifm_mes', $request->input('ifm_mes'))
                                    ->where('ifm_mes', $request->input('ifm_mes'))
                                    ->where('elm_fk_id', '!=', '1')
                                    ->sum('ifm_valor');
    }

    public function getDistribucionCentrosCostosCompleto(Request $request) {
        return \DB::select("
            select ifm_fk_id,
                   cuc_cuenta,
                   cuc_descripcion,
                   ifm_nit_tercero,
                   ifm_razon_social,
                   cco_cod_homologado,
                   cco_descripcion
            from costos_principal.distribucion_ifm_costos_cuentas as dcc
            join costos_principal.centros_costo as cco on (cco.cco_pk_id = dcc.cco_fk_id)
            join costos_principal.informacion_financiera as ifm on (ifm.ifm_pk_id = dcc.ifm_fk_id)
            join costos_principal.cuentas_contables as cuc on (cuc.cuc_pk_id = ifm.cuc_fk_id)
            where dcc.con_fk_id = ".$request->input('con_fk_id')." and
                  dcc.ins_fk_id = '".$request->input('ins_fk_id')."' and
                  dcu_ano = ".$request->input('dco_ano')." and
                  dcu_mes = ".$request->input('dco_mes')." and
                  ifm_mano_obra = false
            order by 1
        ");
    }

    public function getDistribucionBasesDistribucionCompleto(Request $request) {
        return \DB::select("
            select ifm_fk_id,
                   cuc_cuenta,
                   cuc_descripcion,
                   ifm_nit_tercero,
                   ifm_razon_social,
                   bdi_codigo,
                   bdi_descripcion,
                   dib_ponderacion
            from costos_principal.distribucion_ifm_costos_bases as dcb
            join costos_principal.bases_distribucion as bdi on (bdi.bdi_pk_id = dcb.bdi_fk_id)
            join costos_principal.informacion_financiera as ifm on (ifm.ifm_pk_id = dcb.ifm_fk_id)
            join costos_principal.cuentas_contables as cuc on (cuc.cuc_pk_id = ifm.cuc_fk_id)
            where dcb.con_fk_id = ".$request->input('con_fk_id')." and
                  dcb.ins_fk_id = '".$request->input('ins_fk_id')."' and
                  dib_ano = ".$request->input('dco_ano')." and
                  dib_mes = ".$request->input('dco_mes')." and
                  ifm_mano_obra = false
            order by 1
        ");
    }

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

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

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

            fclose($archivo);

            return $this->procesarArchivoInformacionFinanciera($informacionFinanciera,
                                                               $request->con_fk_id,
                                                               $request->ins_fk_id,
                                                               $request->ifm_ano,
                                                               $request->ifm_mes);
        } else {
            throw new \Exception('Imposible completar la petición.');
        }
    }

    private function procesarArchivoInformacionFinanciera($informacionFinanciera, $con_fk_id, $ins_fk_id, $ifm_ano, $ifm_mes) {
        $resultados = new \stdClass();
        $resultados->errores = "";
        $resultados->terceros = "";

        if (count($informacionFinanciera) === 0) {
            $resultados->correcto = false;
            $resultados->errores = 'El archivo está vacío. ';
            return json_encode($resultados);
        } else if (count($informacionFinanciera[0]) !== 7) {
            $resultados->correcto = false;
            $resultados->errores = 'La cantidad de columnas no corresponde. ';
            return json_encode($resultados);
        } else {
            \DB::transaction(function() use($informacionFinanciera, $con_fk_id, $ins_fk_id, $ifm_ano, $ifm_mes, &$resultados) {
                DistribucionIfmCostosCuentas::on('costos_principal')
                                            ->where('con_fk_id', $con_fk_id)
                                            ->where('ins_fk_id', $ins_fk_id)
                                            ->where('dcu_ano', $ifm_ano)
                                            ->where('dcu_mes', $ifm_mes)
                                            ->delete();

                DistribucionIfmCostosBases::on('costos_principal')
                                          ->where('con_fk_id', $con_fk_id)
                                          ->where('ins_fk_id', $ins_fk_id)
                                          ->where('dib_ano', $ifm_ano)
                                          ->where('dib_mes', $ifm_mes)
                                          ->delete();

                // Eliminar la anterior información financiera mensual
                InformacionFinanciera::on('costos_principal')
                                     ->where('con_fk_id', $con_fk_id)
                                     ->where('ins_fk_id', $ins_fk_id)
                                     ->where('ifm_ano', $ifm_ano)
                                     ->where('ifm_mes', $ifm_mes)
                                     ->delete();

                ManoObraTerceros::on('costos_principal')
                                ->where('con_fk_id', $con_fk_id)
                                ->where('ins_fk_id', $ins_fk_id)
                                ->where('mot_ano', $ifm_ano)
                                ->where('mot_mes', $ifm_mes)
                                ->delete();

                $ibd = InformacionBasesDistribucion::on('costos_principal');

                $ibd->where('con_fk_id', $con_fk_id)
                    ->where('ins_fk_id', $ins_fk_id)
                    ->where('ibd_ano', $ifm_ano)
                    ->where('ibd_mes', $ifm_mes)
                    ->where('ibd_automatico', true)
                    ->where('ibd_costo_primario', true)
                    ->where('bdi_fk_id', '!=', 3)
                    ->delete();

                // Quitar el avance del modulo de informacion de mano de obra
                AvanceModulos::on('costos_principal')
                            ->where('con_fk_id', $con_fk_id)
                            ->where('ins_fk_id', $ins_fk_id)
                            ->where('avm_ano', $ifm_ano)
                            ->where('avm_mes', $ifm_mes)
                ->update(
                    [
                        "avm_info_mano_obra" => false
                    ]
                ); 

                // Información de la base de datos
                $cuentasContablesBd = CuentasContables::on('costos_principal')
                                                    ->where('con_fk_id', $con_fk_id)
                                                    ->where('ins_fk_id', $ins_fk_id)
                                                    ->where('cuc_ano', $ifm_ano)
                                                    ->get()->toArray();

                $centrosCostoBd = CentrosCosto::on('costos_principal')
                                            ->where('con_fk_id', $con_fk_id)
                                            ->where('ins_fk_id', $ins_fk_id)
                                            ->where('cco_ano', $ifm_ano)
                                            ->get()->toArray();

                $cuentasContablesExistentes = [];
                $centrosCostoExistentes = [];
                $registrosProcesados = 0;

                // Crear las relaciones existentes en la base de datos
                foreach ($cuentasContablesBd as $cucDb) {
                    $cuentasContablesExistentes[$cucDb['cuc_cuenta']] = new \stdClass();

                    $cuentasContablesExistentes[$cucDb['cuc_cuenta']]->cuc_pk_id = $cucDb['cuc_pk_id'];
                    $cuentasContablesExistentes[$cucDb['cuc_cuenta']]->nac_fk_id = $cucDb['nac_fk_id'];
                    $cuentasContablesExistentes[$cucDb['cuc_cuenta']]->elm_fk_id = $cucDb['elm_fk_id'];
                }

                foreach ($centrosCostoBd as $ccoDb) {
                    $centrosCostoExistentes[$ccoDb['cco_cod_homologado']] = $ccoDb['cco_pk_id'];
                }

                // Errores
                $descripcionLargas = false;
                $camposVacios = false;
                $cuentasContablesInexistentes = "";
                $centrosCostoInexistentes = "";
                $nitIncorrecto = false;
                $valoresIncorrectos = false;

                $infoBasesDistribucion = [];

                // Revisar el archivo respecto a las relaciones existentes
                foreach($informacionFinanciera as $ifmCsv) {
                    $cuentaContable = trim($ifmCsv[0]);
                    $nit = utf8_encode(trim($ifmCsv[1]));
                    $razonSocial = strtoupper($this->eliminarAcentos(utf8_encode(trim($ifmCsv[2]))));
                    $detalleMovimiento = utf8_encode(trim($ifmCsv[3]));
                    $centroCosto = trim($ifmCsv[4]);
                    $debito = trim($ifmCsv[5]);
                    $credito = trim($ifmCsv[6]);

                    // Campos vacios
                    if ($cuentaContable != "" && $nit != "" && $razonSocial != "" && $debito != "" && $credito != "") {
                        // Descripcion largas
                        if (strlen($nit) <= 20 && strlen($razonSocial) <= 500 && strlen($detalleMovimiento) <= 300) {
                            // Existe la cuenta contable
                            if (isset($cuentasContablesExistentes[$cuentaContable])) {
                                // Existe el centro de costos
                                if (isset($centrosCostoExistentes[$centroCosto]) || $centroCosto == "") {
                                    // Valores correctos
                                    if (is_numeric($debito) && is_numeric($credito) && ($debito != 0 || $credito != 0)) {
                                        // Nit correcto
                                        if (ctype_alnum($nit)) {
                                            // Informacion financiera
                                            $ifmNuevo = InformacionFinanciera::on('costos_principal');

                                            $valor = doubleval($debito) - doubleval($credito);

                                            // Si en una cuenta credito
                                            if ($cuentasContablesExistentes[$cuentaContable]->nac_fk_id == "2") {
                                                $valor = doubleval($credito) - doubleval($debito);
                                            }

                                            $idIfm = $ifmNuevo->create(
                                                [
                                                    "con_fk_id" => $con_fk_id,
                                                    "ins_fk_id" => $ins_fk_id,
                                                    "ifm_ano" => $ifm_ano,
                                                    "ifm_mes" => $ifm_mes,
                                                    "cuc_fk_id" => $cuentasContablesExistentes[$cuentaContable]->cuc_pk_id,
                                                    "ifm_nit_tercero" => $nit,
                                                    "ifm_razon_social" => $razonSocial,
                                                    "ifm_detalle_movimiento" => $detalleMovimiento,
                                                    "ifm_debito" => $debito,
                                                    "ifm_credito" => $credito,
                                                    "ifm_valor" => $valor,
                                                    "ifm_mano_obra" => $cuentasContablesExistentes[$cuentaContable]->elm_fk_id !== 3 ? false : true 
                                                ]
                                            );

                                            // Valor directo cuando no es mano de obra
                                            if ($centroCosto != "" && $cuentasContablesExistentes[$cuentaContable]->elm_fk_id != 3) {
                                                $ifmCostosCuentas = DistribucionIfmCostosCuentas::on('costos_principal');

                                                $ifmCostosCuentas->create(
                                                    [
                                                        "con_fk_id" => $con_fk_id,
                                                        "ins_fk_id" => $ins_fk_id,
                                                        "dcu_ano" => $ifm_ano,
                                                        "dcu_mes" => $ifm_mes,
                                                        "ifm_fk_id" => $idIfm->ifm_pk_id,
                                                        "cco_fk_id" => $centrosCostoExistentes[$centroCosto]
                                                    ]
                                                );

                                                $ifmCostosBases = DistribucionIfmCostosBases::on('costos_principal');

                                                $ifmCostosBases->create(
                                                    [
                                                        "con_fk_id" => $con_fk_id,
                                                        "ins_fk_id" => $ins_fk_id,
                                                        "dib_ano" => $ifm_ano,
                                                        "dib_mes" => $ifm_mes,
                                                        "ifm_fk_id" => $idIfm->ifm_pk_id,
                                                        "bdi_fk_id" => 1,
                                                        "dib_ponderacion" => 100
                                                    ]
                                                );

                                                $ifmValorDirecto = DistribucionValorDirecto::on('costos_principal');

                                                $ifmValorDirecto->create(
                                                    [
                                                        "con_fk_id" => $con_fk_id,
                                                        "ins_fk_id" => $ins_fk_id,
                                                        "dvd_ano" => $ifm_ano,
                                                        "dvd_mes" => $ifm_mes,
                                                        "ifm_fk_id" => $idIfm->ifm_pk_id,
                                                        "cco_fk_id" => $centrosCostoExistentes[$centroCosto],
                                                        "dvd_valor" => $valor
                                                    ]
                                                );

                                                // Actualizar la asignacion del movimiento
                                                InformacionFinanciera::on('costos_principal')
                                                                    ->where('ifm_pk_id', $idIfm->ifm_pk_id)
                                                                    ->update(['ifm_asignado' => true]);
                                            }

                                            $registrosProcesados++;
                                        } else {
                                            $nitIncorrecto = true;
                                        }
                                    } else {
                                        $valoresIncorrectos = true;
                                    }
                                } else {
                                    $centrosCostoInexistentes .= $centroCosto.", ";
                                }
                            } else {
                                $cuentasContablesInexistentes .= $cuentaContable.", ";
                            }
                        } else {
                            $descripcionLargas = true;
                        }
                    } else {
                        $camposVacios = true;
                    }
                }

                // Errores de cuentas contables
                if ($cuentasContablesInexistentes !== "") {
                    $cuentasContablesInexistentes[strlen($cuentasContablesInexistentes) - 1] = " ";
                    $cuentasContablesInexistentes[strlen($cuentasContablesInexistentes) - 2] = " ";
                    $cuentasContablesInexistentes = "No existen las siguientes cuentas contables: ".$cuentasContablesInexistentes;

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

                    $resultados->errores .= $cuentasContablesInexistentes;
                }

                // Errores de centros de costo
                if ($centrosCostoInexistentes !== "") {
                    $centrosCostoInexistentes[strlen($centrosCostoInexistentes) - 1] = " ";
                    $centrosCostoInexistentes[strlen($centrosCostoInexistentes) - 2] = " ";
                    $centrosCostoInexistentes = "No existen los siguientes centros de costo: ".$centrosCostoInexistentes;

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

                    $resultados->errores .= $centrosCostoInexistentes;
                }

                // Descripciones largas
                if ($descripcionLargas) {
                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= "Hay descripciones con más caracteres de los permitidos. El máximo para el nit son 20 caracteres,
                                            500 caracteres para la razon social y 300 caracteres para el detalle del movimiento.";
                }

                // Campos vacios
                if ($camposVacios) {
                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= "Hay campos vacíos.";
                }

                // Valores incorrectos
                if ($valoresIncorrectos) {
                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= "Hay valores numéricos incorrectos (los decimales deben ser separados por un punto) o el débito y crédito de un movimiento son cero.";
                }

                // Valores incorrectos
                if ($nitIncorrecto) {
                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= "El NIT del tercero debe ser alfanumérico, no debe incluir caracteres especiales.";
                }

                if (!$descripcionLargas && !$camposVacios && !$valoresIncorrectos && !$nitIncorrecto &&
                    $cuentasContablesInexistentes === "" && $centrosCostoInexistentes === "") {
                    $resultados->correcto = true;
                } else {
                    $resultados->correcto = false;
                }

                $resultados->registros = $registrosProcesados;

                // Validar los terceros
                $terceros = \DB::select("select nit.ifm_nit_tercero
                                         from (
                                            select distinct ifm_nit_tercero, ifm_razon_social
                                            from costos_principal.informacion_financiera
                                            where con_fk_id = ".$con_fk_id." and 
                                                  ins_fk_id = '".$ins_fk_id."' and
                                                  ifm_ano = ".$ifm_ano." and
                                                  ifm_mes = ".$ifm_mes."
                                         ) as nit
                                         group by 1
                                         having count(*) > 1");

                $resultados->terceros = json_encode($terceros);

                if (count($terceros) > 0) {
                    $resultados->correcto = false;

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

                    $resultados->errores .= "HAY NIT DE TERCEROS CON RAZONES SOCIALES DIFERENTES.
                                             Se exporta informe y se recomienda corregir las incosistencias.";
                }

                $this->verificarAvance($con_fk_id, $ins_fk_id, $ifm_ano, $ifm_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
        $ifm = InformacionFinanciera::on('costos_principal')
                                    ->where('informacion_financiera.con_fk_id', $contrato)
                                    ->where('informacion_financiera.ins_fk_id', $institucion)
                                    ->where('ifm_ano', $ano)
                                    ->where('ifm_mes', $mes)
                                    ->where('ifm_asignado', false)
                                    ->where('ifm_mano_obra', false)
                                    ->count();

        if ($conteo > 0) {
            if ($ifm == 0) {
                AvanceModulos::on('costos_principal')
                                ->where('con_fk_id', $contrato)
                                ->where('ins_fk_id', $institucion)
                                ->where('avm_ano', $ano)
                                ->where('avm_mes', $mes)
                ->update(
                    [
                        "avm_inf_financiera" => 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_inf_financiera" => false
                    ]
                ); 
            }
        } else {
            if ($ifm == 0) {
                AvanceModulos::on('costos_principal')
                ->create(
                    [
                        "con_fk_id" => $contrato,
                        "ins_fk_id" => $institucion,
                        "avm_ano" => $ano,
                        "avm_mes" => $mes,
                        "avm_inf_financiera" => true
                    ]
                );
            } else {
                AvanceModulos::on('costos_principal')
                ->create(
                    [
                        "con_fk_id" => $contrato,
                        "ins_fk_id" => $institucion,
                        "avm_ano" => $ano,
                        "avm_mes" => $mes,
                        "avm_inf_financiera" => false
                    ]
                );
            }
        }            
    }

    function eliminarAcentos($cadena){
		//Reemplazamos la A y a
		$cadena = str_replace(
		array('Á', 'À', 'Â', 'Ä', 'á', 'à', 'ä', 'â', 'ª'),
		array('A', 'A', 'A', 'A', 'a', 'a', 'a', 'a', 'a'),
		$cadena
		);

		//Reemplazamos la E y e
		$cadena = str_replace(
		array('É', 'È', 'Ê', 'Ë', 'é', 'è', 'ë', 'ê'),
		array('E', 'E', 'E', 'E', 'e', 'e', 'e', 'e'),
		$cadena );

		//Reemplazamos la I y i
		$cadena = str_replace(
		array('Í', 'Ì', 'Ï', 'Î', 'í', 'ì', 'ï', 'î'),
		array('I', 'I', 'I', 'I', 'i', 'i', 'i', 'i'),
		$cadena );

		//Reemplazamos la O y o
		$cadena = str_replace(
		array('Ó', 'Ò', 'Ö', 'Ô', 'ó', 'ò', 'ö', 'ô'),
		array('O', 'O', 'O', 'O', 'o', 'o', 'o', 'o'),
		$cadena );

		//Reemplazamos la U y u
		$cadena = str_replace(
		array('Ú', 'Ù', 'Û', 'Ü', 'ú', 'ù', 'ü', 'û'),
		array('U', 'U', 'U', 'U', 'u', 'u', 'u', 'u'),
		$cadena );

		//Reemplazamos la N, n, C y c
		$cadena = str_replace(
		array('Ñ', 'ñ', 'Ç', 'ç'),
		array('N', 'n', 'C', 'c'),
		$cadena
		);
		
		return $cadena;
	}
}
