<?php

namespace App\Http\Controllers;

use App\Models\Elementos;
use App\Models\DetalleElementos;
use App\Models\AvanceModulos;
use Illuminate\Http\Request;

class DetalleElementosController extends Controller
{
    private $apiKey;

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

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

    public function crearDetalleElemento(Request $request) {
        $id = new \stdClass();

        \DB::transaction(function() use(&$id, $request) {
            $detalleElemento = DetalleElementos::on('costos_principal');

            $id = $detalleElemento->create(
                [
                    "con_fk_id" => $request->input("con_fk_id"),
                    "ins_fk_id" => $request->input("ins_fk_id"),
                    "del_ano" => $request->input("del_ano"),
                    "elm_fk_id" => $request->input("elm_fk_id"),
                    "del_descripcion" => $request->input("del_descripcion")
                ]
            );

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

        return array("response" => $id->del_pk_id);
    }

    public function actualizarDetalleElemento(Request $request) {
        DetalleElementos::on('costos_principal')
                        ->where("con_fk_id", $request->input("con_fk_id"))
                        ->where("ins_fk_id", $request->input("ins_fk_id"))
                        ->where("del_ano", $request->input("del_ano"))
                        ->where("del_pk_id", $request->input("del_pk_id"))
        ->update(
            [
                "del_descripcion" => $request->input("del_descripcion")
            ]
        );
    }

    public function borrarDetalleElemento(Request $request) {
        \DB::transaction(function() use($request) {
            DetalleElementos::on('costos_principal')
                            ->where("del_pk_id", $request->input("del_pk_id"))
                            ->delete();

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

    public function getDetalleElementos(Request $request) {
        return DetalleElementos::on('costos_principal')
                               ->join('elementos', 'elm_pk_id', '=', 'elm_fk_id')
                               ->where('con_fk_id', $request->input('con_fk_id'))
                               ->where('ins_fk_id', $request->input('ins_fk_id'))
                               ->where('del_ano', $request->input('del_ano'))
                               ->orderBy('elm_descripcion')
                               ->orderBy('del_descripcion')
                               ->get()->toArray();

    }

    public function getDetalleElementosCsv(Request $request) {
        return DetalleElementos::on('costos_principal')
                               ->selectRaw('elm_fk_id, elm_descripcion, del_pk_id, del_descripcion')
                               ->join('elementos', 'elm_pk_id', '=', 'elm_fk_id')
                               ->where('con_fk_id', $request->input('con_fk_id'))
                               ->where('ins_fk_id', $request->input('ins_fk_id'))
                               ->where('del_ano', $request->input('del_ano'))
                               ->orderBy('elm_fk_id')
                               ->orderBy('elm_descripcion')
                               ->orderBy('del_pk_id')
                               ->orderBy('del_descripcion')
                               ->get()->toArray();

    }

    public function getDetalleElementosPorElemento(Request $request) {
        return DetalleElementos::on('costos_principal')
                               ->where('con_fk_id', $request->input('con_fk_id'))
                               ->where('ins_fk_id', $request->input('ins_fk_id'))
                               ->where('del_ano', $request->input('del_ano'))
                               ->where('elm_fk_id', $request->input('elm_fk_id'))
                               ->orderBy('del_descripcion')
                               ->get()->toArray();

    }

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

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

            fclose($archivo);

            return $this->procesarArchivoDetalleElementos($detalleElementos,
                                                          $request->con_fk_id,
                                                          $request->ins_fk_id,
                                                          $request->del_ano);
        } else {
            throw new \Exception('Imposible completar la petición.');
        }
    }

    private function procesarArchivoDetalleElementos($detalleElementos, $con_fk_id, $ins_fk_id, $del_ano) {
        $resultados = new \stdClass();
        $resultados->errores = "";

        \DB::transaction(function() use(&$resultados, $detalleElementos, $con_fk_id, $ins_fk_id, $del_ano) {
            if (count($detalleElementos) === 0) {
                $resultados->correcto = false;
                $resultados->errores = 'El archivo está vacío. ';
                return json_encode($resultados);
            } else if (count($detalleElementos[0]) !== 2) {
                $resultados->correcto = false;
                $resultados->errores = 'La cantidad de columnas no corresponde. ';
                return json_encode($resultados);
            } else {
                $elementosBd = Elementos::on('costos_principal')->get()->toArray();

                $detalleElementosBd = DetalleElementos::on('costos_principal')
                                                    ->join('elementos', 'elm_pk_id', '=', 'elm_fk_id')
                                                    ->where('con_fk_id', $con_fk_id)
                                                    ->where('ins_fk_id', $ins_fk_id)
                                                    ->where('del_ano', $del_ano)
                                                    ->get()->toArray();

                $elementosExistentes = [];
                $detalleElementosExistentes = [];
                $registrosProcesados = 0;

                // Crear las relaciones existentes en la base de datos
                foreach ($elementosBd as $elDb) {
                    $elementosExistentes[$elDb['elm_pk_id']] = $elDb['elm_descripcion'];
                }

                foreach ($detalleElementosBd as $delDb) {
                    $detalleElementosExistentes[$delDb['elm_pk_id']][$delDb['del_descripcion']] = $delDb['del_descripcion'];
                }

                // Errores de los centros de utilidad
                $codElementoErroneo = "";
                $descripcionesLargas = false;
                $camposVacios = false;

                // Revisar el archivo respecto a las relaciones existentes
                foreach($detalleElementos as $delCsv) {
                    $elemento = $delCsv[0];
                    $detalle = strtoupper(utf8_encode($delCsv[1]));

                    if (trim($elemento) != "" && trim($detalle) != "") {
                        // Existe el elemento
                        if (isset($detalleElementosExistentes[$elemento][$detalle])) {
                            // Descripcion largas
                            if (strlen($detalle) <= 80) {
                                if ($detalleElementosExistentes[$elemento][$detalle] != $detalle) {
                                    DetalleElementos::on('costos_principal')
                                                ->where("con_fk_id", $con_fk_id)
                                                ->where("ins_fk_id", $ins_fk_id)
                                                ->where("del_ano", $del_ano)
                                                ->where("elm_fk_id", $elemento)
                                                ->where("del_descripcion", $detalle)
                                    ->update(
                                        [
                                            "del_descripcion" => $detalle,
                                        ]
                                    );
                                }

                                $registrosProcesados++;
                            } else {
                                $descripcionesLargas = true;
                            }
                        } else { // No existe el elemento
                            // Existe el elemento
                            if (isset($elementosExistentes[$elemento]) && ($elemento == "1" || $elemento == "2" || $elemento == "3" || $elemento == "4")) {
                                // Descripciones largas
                                if (strlen($detalle) <= 80) {
                                    $detalleElemento = DetalleElementos::on('costos_principal');

                                    $id = $detalleElemento->create(
                                        [
                                            "con_fk_id" => $con_fk_id,
                                            "ins_fk_id" => $ins_fk_id,
                                            "del_ano" => $del_ano,
                                            "elm_fk_id" => $elemento,
                                            "del_descripcion" => $detalle
                                        ]
                                    );

                                    $registrosProcesados++;

                                    $detallElementosExistentes[$elemento][$detalle] = $detalle;
                                } else {
                                    $descripcionesLargas = true;
                                }
                            } else {
                                $codElementoErroneo .= $elemento.", ";
                            }
                        }
                    } else {
                        $camposVacios = true;
                    }
                }

                // Errores de elementos
                if ($codElementoErroneo !== "") {
                    $codElementoErroneo[strlen($codElementoErroneo) - 1] = " ";
                    $codElementoErroneo[strlen($codElementoErroneo) - 2] = " ";
                    $codElementoErroneo = "Los siguientes códigos de elementos no existen: ".$codElementoErroneo;

                    $resultados->errores = $codElementoErroneo;
                }

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

                    $resultados->errores .= "Hay descripciones de más de 80 caracteres";
                }

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

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

                if (!$descripcionesLargas && $codElementoErroneo === "" && !$camposVacios) {
                    $resultados->correcto = true;
                } else {
                    $resultados->correcto = false;
                }

                $resultados->registros = $registrosProcesados;
            }

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

        return json_encode($resultados);
    }

    public function verificarAvance($contrato, $institucion, $ano) {
        // 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)
                               ->whereNull('avm_mes')
                               ->count();

        // Verificar el avance del modulo
        $del = DetalleElementos::on('costos_principal')
                               ->where('con_fk_id', $contrato)
                               ->where('ins_fk_id', $institucion)
                               ->where('del_ano', $ano)
                               ->count();

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