<?php

namespace App\Http\Controllers;

use App\Models\InformacionBasesDistribucion;
use App\Models\InformacionBasesDistribucion2;
use App\Models\Sedes;
use App\Models\CentrosCosto;
use App\Models\BasesDistribucion;
use App\Models\AvanceModulos;
use Illuminate\Http\Request;

class InformacionBasesDistribucionController extends Controller
{
    private $apiKey;

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

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

    public function crearInfoBasesDistribucion(Request $request) {
        \DB::transaction(function() use($request) {
            $ibd = InformacionBasesDistribucion::on('costos_principal');
            $ibd2 = InformacionBasesDistribucion2::on('costos_principal');

            $ibd->create(
                [
                    "con_fk_id" => $request->input("con_fk_id"),
                    "ins_fk_id" => $request->input("ins_fk_id"),
                    "ibd_ano" => $request->input("ibd_ano"),
                    "ibd_mes" => $request->input("ibd_mes"),
                    "cco_fk_id" => $request->input("cco_fk_id"),
                    "bdi_fk_id" => $request->input("bdi_fk_id"),
                    "ibd_valor" => $request->input("ibd_valor")
                ]
            );

            $ibd2->create(
                [
                    "con_fk_id" => $request->input("con_fk_id"),
                    "ins_fk_id" => $request->input("ins_fk_id"),
                    "ibd2_ano" => $request->input("ibd_ano"),
                    "ibd2_mes" => $request->input("ibd_mes"),
                    "cco_fk_id" => $request->input("cco_fk_id"),
                    "bdi_fk_id" => $request->input("bdi_fk_id"),
                    "ibd2_valor" => $request->input("ibd_valor")
                ]
            );

            $this->verificarAvance($request->input("con_fk_id"),
                                   $request->input("ins_fk_id"),
                                   $request->input("ibd_ano"),
                                   $request->input("ibd_mes"));
        });

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

    public function actualizarInfoBasesDistribucion(Request $request) {
        \DB::transaction(function() use($request) {
            InformacionBasesDistribucion::on('costos_principal')
                                        ->where("con_fk_id", $request->input("con_fk_id"))
                                        ->where("ins_fk_id", $request->input("ins_fk_id"))
                                        ->where("ibd_ano", $request->input("ibd_ano"))
                                        ->where("ibd_mes", $request->input("ibd_mes"))
                                        ->where("cco_fk_id", $request->input("cco_fk_id"))
                                        ->where("bdi_fk_id", $request->input("bdi_fk_id"))
            ->update(
                [
                    "ibd_valor" => $request->input("ibd_valor")
                ]
            );

            InformacionBasesDistribucion2::on('costos_principal')
                                        ->where("con_fk_id", $request->input("con_fk_id"))
                                        ->where("ins_fk_id", $request->input("ins_fk_id"))
                                        ->where("ibd2_ano", $request->input("ibd_ano"))
                                        ->where("ibd2_mes", $request->input("ibd_mes"))
                                        ->where("cco_fk_id", $request->input("cco_fk_id"))
                                        ->where("bdi_fk_id", $request->input("bdi_fk_id"))
            ->update(
                [
                    "ibd2_valor" => $request->input("ibd_valor")
                ]
            );
        });
    }

    public function borrarInfoBasesDistribucion(Request $request) {
        \DB::transaction(function() use($request) {
            InformacionBasesDistribucion::on('costos_principal')
                                        ->where("con_fk_id", $request->input("con_fk_id"))
                                        ->where("ins_fk_id", $request->input("ins_fk_id"))
                                        ->where("ibd_ano", $request->input("ibd_ano"))
                                        ->where("ibd_mes", $request->input("ibd_mes"))
                                        ->where("cco_fk_id", $request->input("cco_fk_id"))
                                        ->where("bdi_fk_id", $request->input("bdi_fk_id"))
                                        ->delete();

            InformacionBasesDistribucion2::on('costos_principal')
                                        ->where("con_fk_id", $request->input("con_fk_id"))
                                        ->where("ins_fk_id", $request->input("ins_fk_id"))
                                        ->where("ibd2_ano", $request->input("ibd_ano"))
                                        ->where("ibd2_mes", $request->input("ibd_mes"))
                                        ->where("cco_fk_id", $request->input("cco_fk_id"))
                                        ->where("bdi_fk_id", $request->input("bdi_fk_id"))
                                        ->delete();

            $this->verificarAvance($request->input("con_fk_id"),
                                   $request->input("ins_fk_id"),
                                   $request->input("ibd_ano"),
                                   $request->input("ibd_mes"));
        });
    }

    public function getInfoBasesDistribucion(Request $request) {
        return InformacionBasesDistribucion::on('costos_principal')
                                           ->join('centros_costo', 'cco_pk_id', '=', 'cco_fk_id')
                                           ->join('bases_distribucion', 'bdi_pk_id', '=', 'bdi_fk_id')
                                           ->where('informacion_bases_distribucion.con_fk_id', $request->input('con_fk_id'))
                                           ->where('informacion_bases_distribucion.ins_fk_id', $request->input('ins_fk_id'))
                                           ->where('ibd_ano', $request->input('ibd_ano'))
                                           ->where('ibd_mes', $request->input('ibd_mes'))
                                           ->where('ibd_automatico', false)
                                           ->orderBy('cco_codigo')
                                           ->orderBy('bdi_descripcion')
                                           ->get()->toArray();
    }

    public function getInfoBasesDistribucionEspecifica(Request $request) {
        return InformacionBasesDistribucion::on('costos_principal')
                                           ->where('con_fk_id', $request->input('con_fk_id'))
                                           ->where('ins_fk_id', $request->input('ins_fk_id'))
                                           ->where('ibd_ano', $request->input('ibd_ano'))
                                           ->where('ibd_mes', $request->input('ibd_mes'))
                                           ->where('cco_fk_id', $request->input('cco_fk_id'))
                                           ->where('bdi_fk_id', $request->input('bdi_fk_id'))
                                           ->get()->toArray();
    }

    public function importarInformacionMesAnterior(Request $request) {
        \DB::transaction(function() use($request) {
            $mesActual = $request->input('mesActual');
            $mesAnterior = $request->input('mesAnterior');

            // Borrar la informacion anterior
            \DB::select("delete from costos_principal.informacion_bases_distribucion
                        where ibd_pk_id in(
                            select ibd_pk_id
                            from costos_principal.informacion_bases_distribucion as ibd
                            join costos_principal.bases_distribucion as bdi on (ibd.bdi_fk_id = bdi.bdi_pk_id)
                            where ibd.con_fk_id = ".$request->input('con_fk_id')." and
                                ibd.ins_fk_id = '".$request->input('ins_fk_id')."' and
                                ibd_ano = ".$request->input('ibd_ano')." and
                                ibd_mes = ".$mesActual." and
                                ibd_automatico = false and
                                ibd_costo_primario = false and
                                bdi_mano_obra = false
                            order by 1 asc	
                        )");

            \DB::select("delete from costos_principal.informacion_bases_distribucion2
                        where ibd2_pk_id in(
                            select ibd2_pk_id
                            from costos_principal.informacion_bases_distribucion2 as ibd2
                            where ibd2.con_fk_id = ".$request->input('con_fk_id')." and
                                ibd2.ins_fk_id = '".$request->input('ins_fk_id')."' and
                                ibd2_ano = ".$request->input('ibd_ano')." and
                                ibd2_mes = ".$mesActual." and
                                ibd2_automatico = false
                            order by 1 desc
                        )");

            // Insertar la nueva informacion para costo primario
            \DB::select("insert into costos_principal.informacion_bases_distribucion (con_fk_id, ins_fk_id, ibd_ano, ibd_mes,
                                                                                      cco_fk_id, bdi_fk_id, ibd_valor, ibd_automatico,
                                                                                      ibd_costo_primario)
                        select ".$request->input('con_fk_id').",
                               '".$request->input('ins_fk_id')."',
                               ".$request->input('ibd_ano').",
                               ".$mesActual.",
                               cco_fk_id,
                               bdi_fk_id,
                               ibd_valor,
                               ibd_automatico,
                               ibd_costo_primario
                        from costos_principal.informacion_bases_distribucion ibd
                        join costos_principal.bases_distribucion as bdi on (ibd.bdi_fk_id = bdi.bdi_pk_id)
                        where ibd.con_fk_id = ".$request->input('con_fk_id')." and
                              ibd.ins_fk_id = '".$request->input('ins_fk_id')."' and
                              ibd_ano = ".$request->input('ibd_ano')." and
                              ibd_mes = ".$mesAnterior." and
                              ibd_automatico = false and
                              ibd_costo_primario = false and
                              bdi_mano_obra = false");

            // Insertar la nueva informacion para costo total
            \DB::select("insert into costos_principal.informacion_bases_distribucion2 (con_fk_id, ins_fk_id, ibd2_ano, ibd2_mes,
                                                                                       cco_fk_id, bdi_fk_id, ibd2_valor, ibd2_automatico)
                        select ".$request->input('con_fk_id').",
                               '".$request->input('ins_fk_id')."',
                               ".$request->input('ibd_ano').",
                               ".$mesActual.",
                               cco_fk_id,
                               bdi_fk_id,
                               ibd2_valor,
                               ibd2_automatico
                        from costos_principal.informacion_bases_distribucion2
                        where con_fk_id = ".$request->input('con_fk_id')." and
                              ins_fk_id = '".$request->input('ins_fk_id')."' and
                              ibd2_ano = ".$request->input('ibd_ano')." and
                              ibd2_mes = ".$mesAnterior." and
                              ibd2_automatico = false");

            $this->verificarAvance($request->input("con_fk_id"),
                                   $request->input("ins_fk_id"),
                                   $request->input("ibd_ano"),
                                   $mesActual);
        });
    }

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

        if ($apiKey === $this->apiKey) {
            $rutaDelArchivo = $request->infoBasesDistribucion->path();
            $delimitador = $request->delimitador;
            $archivo = fopen($rutaDelArchivo, 'r');
            $infoBasesDistribucion = 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($infoBasesDistribucion, $registro);
                } else {
                    $primeraLinea = false;
                }
            }

            fclose($archivo);

            return $this->procesarArchivoInfoBasesDistribucion($infoBasesDistribucion,
                                                               $request->con_fk_id,
                                                               $request->ins_fk_id,
                                                               $request->ibd_ano,
                                                               $request->ibd_mes);
        } else {
            throw new \Exception('Imposible completar la petición.');
        }
    }

    private function procesarArchivoInfoBasesDistribucion($infoBasesDistribucion, $con_fk_id, $ins_fk_id, $ibd_ano, $ibd_mes) {
        $resultados = new \stdClass();
        $resultados->errores = "";

        \DB::transaction(function() use(&$resultados, $infoBasesDistribucion, $con_fk_id, $ins_fk_id, $ibd_ano, $ibd_mes) {
            if (count($infoBasesDistribucion) === 0) {
                $resultados->correcto = false;
                $resultados->errores = 'El archivo está vacío. ';
                return json_encode($resultados);
            } else if (count($infoBasesDistribucion[0]) !== 3) {
                $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', $ibd_ano)
                                            ->get()->toArray();

                $basesDistribucionBd = BasesDistribucion::on('costos_principal')
                                                        ->where('con_fk_id', $con_fk_id)
                                                        ->where('ins_fk_id', $ins_fk_id)
                                                        ->where('bdi_ano', $ibd_ano)
                                                        ->where('bdi_predefinida', false)
                                                        ->get()->toArray();

                $infoBasesDistribucionBd = InformacionBasesDistribucion::on('costos_principal')
                                                                    ->join('centros_costo', 'cco_pk_id', '=', 'cco_fk_id')
                                                                    ->where('informacion_bases_distribucion.con_fk_id', $con_fk_id)
                                                                    ->where('informacion_bases_distribucion.ins_fk_id', $ins_fk_id)
                                                                    ->where('ibd_ano', $ibd_ano)
                                                                    ->where('ibd_mes', $ibd_mes)
                                                                    ->get()->toArray();

                $centrosCostoExistentes = [];
                $basesDistribucionExistentes = [];
                $infoBasesDistribucionExistente = [];
                $registrosProcesados = 0;

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

                foreach ($basesDistribucionBd as $bdiDb) {
                    $basesDistribucionExistentes[$bdiDb['bdi_codigo']] = $bdiDb['bdi_pk_id'];
                }

                foreach ($infoBasesDistribucionBd as $ibdDb) {
                    $infoBasesDistribucionExistente[$ibdDb['cco_fk_id']][$ibdDb['bdi_fk_id']] = $ibdDb['ibd_valor'];
                }

                // Errores de los centros de utilidad
                $valorIncorrecto = false;
                $camposVacios = false;
                $centrosCostoInexistentes = "";
                $basesDistribucionInexistentes = "";
                $basesDistribucionInexistentes = "";

                // Revisar el archivo respecto a las relaciones existentes
                foreach($infoBasesDistribucion as $ibdCsv) {
                    $baseDistribucion = strtoupper(trim($ibdCsv[0]));
                    $centroCosto = trim($ibdCsv[1]);
                    $valor = trim($ibdCsv[2]);

                    if ($centroCosto != "" && $baseDistribucion != "" && $valor != "") {
                        if (is_numeric($valor) && doubleval($valor) > 0) {
                            // Existe el centro de costo
                            if (isset($centrosCostoExistentes[$centroCosto])) {
                                // Existe la base de distribucion
                                if (isset($basesDistribucionExistentes[$baseDistribucion])) {
                                    // Existe la informacion
                                    if (isset($infoBasesDistribucionExistente[$centrosCostoExistentes[$centroCosto]][$basesDistribucionExistentes[$baseDistribucion]])) {
                                        // Actualizar si la descripcion es diferente
                                        if ($infoBasesDistribucionExistente[$centrosCostoExistentes[$centroCosto]]
                                                                           [$basesDistribucionExistentes[$baseDistribucion]] != doubleval($valor)) {
                                            InformacionBasesDistribucion::on('costos_principal')
                                                                        ->where("con_fk_id", $con_fk_id)
                                                                        ->where("ins_fk_id", $ins_fk_id)
                                                                        ->where("ibd_ano", $ibd_ano)
                                                                        ->where("ibd_mes", $ibd_mes)
                                                                        ->where("cco_fk_id", $centrosCostoExistentes[$centroCosto])
                                                                        ->where("bdi_fk_id", $basesDistribucionExistentes[$baseDistribucion])
                                            ->update(
                                                [
                                                    "ibd_valor" => $valor
                                                ]
                                            );

                                            InformacionBasesDistribucion2::on('costos_principal')
                                                                         ->where("con_fk_id", $con_fk_id)
                                                                         ->where("ins_fk_id", $ins_fk_id)
                                                                         ->where("ibd2_ano", $ibd_ano)
                                                                         ->where("ibd2_mes", $ibd_mes)
                                                                         ->where("cco_fk_id", $centrosCostoExistentes[$centroCosto])
                                                                         ->where("bdi_fk_id", $basesDistribucionExistentes[$baseDistribucion])
                                            ->update(
                                                [
                                                    "ibd2_valor" => $valor
                                                ]
                                            );

                                            $registrosProcesados++;
                                        } else {
                                            $registrosProcesados++;
                                        }
                                    } else { // No existe, es necesario crearla
                                        $ibd = InformacionBasesDistribucion::on('costos_principal');
                                        $ibd2 = InformacionBasesDistribucion2::on('costos_principal');

                                        $id = $ibd->create(
                                            [
                                                "con_fk_id" => $con_fk_id,
                                                "ins_fk_id" => $ins_fk_id,
                                                "ibd_ano" => $ibd_ano,
                                                "ibd_mes" => $ibd_mes,
                                                "cco_fk_id" =>  $centrosCostoExistentes[$centroCosto],
                                                "bdi_fk_id" => $basesDistribucionExistentes[$baseDistribucion],
                                                "ibd_valor" => $valor
                                            ]
                                        );

                                        $id2 = $ibd2->create(
                                            [
                                                "con_fk_id" => $con_fk_id,
                                                "ins_fk_id" => $ins_fk_id,
                                                "ibd2_ano" => $ibd_ano,
                                                "ibd2_mes" => $ibd_mes,
                                                "cco_fk_id" =>  $centrosCostoExistentes[$centroCosto],
                                                "bdi_fk_id" => $basesDistribucionExistentes[$baseDistribucion],
                                                "ibd2_valor" => $valor
                                            ]
                                        );

                                        $registrosProcesados++;

                                        $infoBasesDistribucionExistente[$centrosCostoExistentes[$centroCosto]][$basesDistribucionExistentes[$baseDistribucion]] = $valor;
                                    }
                                } else {
                                    $basesDistribucionInexistentes .= $baseDistribucion.", ";
                                }
                            } else {
                                $centrosCostoInexistentes .= $centroCosto.", ";
                            }
                        } else {
                            $valorIncorrecto = true;
                        }
                    } else {
                        $camposVacios = true;
                    }
                }

                // 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;
                }

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

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

                    $resultados->errores .= $basesDistribucionInexistentes;
                }

                // Valor incorrecto
                if ($valorIncorrecto) {
                    if ($resultados->errores !== "") {
                        $resultados->errores .= "-  ";
                    }

                    $resultados->errores .= "Hay valores de bases de distribucion incorrectos (los decimales deben ser separados por un punto).";
                }

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

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

                if (!$valorIncorrecto && !$camposVacios && !$centrosCostoInexistentes &&
                    !$basesDistribucionInexistentes) {
                    $resultados->correcto = true;
                } else {
                    $resultados->correcto = false;
                }

                $resultados->registros = $registrosProcesados;
            }
        });

        $this->verificarAvance($con_fk_id, $ins_fk_id, $ibd_ano, $ibd_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
        $ibd = InformacionBasesDistribucion::on('costos_principal')
                                           ->where('con_fk_id', $contrato)
                                           ->where('ins_fk_id', $institucion)
                                           ->where('ibd_ano', $ano)
                                           ->where('ibd_mes', $mes)
                                           ->where('bdi_fk_id', '>', 8)
                                           ->where('ibd_automatico', false)
                                           ->count();

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