<?php

/*
Nombre del programador:         Cordourier Rojas Mathew
Ultima fecha de modificación:   [ 24 / Marzo / 2023 ]
Descripción:                    Controlador de ayuda para la nomenclatura e inserciòn de documentos.
*/

namespace App\Http\Controllers;

use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Throwable;

class DocumentsController extends Controller
{
    private $resources_controller;
    private $response_controller;
    public function __construct()
    {
        $this->resources_controller = new ResourcesController();
        $this->response_controller = new ResponseController();

    }
    // Metodo para la creación de un documento y la inserción de la liga en la base de datos
    public function createDocument($module_code, $document_clasification, $document_name, $id_employee = null, $storage_disk, $line_number = 1, $user_id, $employee_new_document = "N")
    {
        try {

            // Engloba los segmentos de la nomenclatura del nombre del documento
            $name_document = "";
            $REGISTER_DATE = Carbon::now()->timezone('America/Mexico_City')->format("ymd");
            $sequence_number = "000001";
            $version_number = "01";
            $line_number = $this->resources_controller->formatSecuence($line_number, 2);

            // Verifica que el nombre de la nomenclatura no se duplique
            $document_name = $this->deleteCodificationStructureName($document_name, $line_number, $module_code);

            $files_uploaded = Storage::disk($storage_disk)->files();

            // Itera cada archivo guardado en el disco del storage para ver si hay coincidencias en la nomenclatura
            foreach ($files_uploaded as $file) {

                // Si la clasificaciòn es la misma, se recupera el numero de secuencia
                if (substr($file, 0, 10) == ($line_number . '-' . $module_code . '-' . $document_clasification)) {
                    $sequence_number = substr($file, 18, 6);

                    // Verifica si el archivo es nuevo por medio del nombre
                    if (substr($file, 28) != $document_name) {

                        // Encuentra el siguiente numero de secuencia
                        if (substr($file, 18, 6) >= $sequence_number) {
                            $sequence_number = substr($file, 18, 6);
                            $sequence_number++;
                        }
                    } else {

                        // Verifica si el usuario creará nuevos documentos
                        if ($employee_new_document == "Y") {

                            // Busca el siguiente numero de secuencia para el archivo
                            while (true) {
                                $name_document = $line_number . '-' . $module_code . '-' . $document_clasification . '-' .
                                    $REGISTER_DATE . '-' . $sequence_number . '=' .
                                    $version_number . '=' . $document_name;

                                // Si el nombre es nuevo, sale del ciclo
                                if (Storage::disk($storage_disk)->missing($name_document)) {
                                    break;
                                }

                                $sequence_number++;
                                $sequence_number = $this->resources_controller->formatSecuence($sequence_number, 6);
                            }
                        } else {

                            // Busca el ultimo numero de secuencia para el archivo
                            while (true) {
                                $sequence_number = $this->resources_controller->formatSecuence($sequence_number, 6);
                                $name_document = $line_number . '-' . $module_code . '-' . $document_clasification . '-' .
                                    $REGISTER_DATE . '-' . $sequence_number . '=' .
                                    $version_number . '=' . $document_name;

                                // Si el nombre es nuevo, sale del ciclo recuperando el ultimo numero de secuencia
                                if (Storage::disk($storage_disk)->missing($name_document)) {
                                    $sequence_number--;
                                    $sequence_number = $this->resources_controller->formatSecuence($sequence_number, 6);
                                    break;
                                }

                                $sequence_number++;
                            }
                        }

                        // Busca el siguiente numero de versión para el archivo
                        while (true) {
                            $name_document = $line_number . '-' . $module_code . '-' . $document_clasification . '-' .
                                $REGISTER_DATE . '-' . $sequence_number . '=' .
                                $version_number . '=' . $document_name;

                            // Si el nombre es nuevo, sale del ciclo
                            if (Storage::disk($storage_disk)->missing($name_document)) {
                                break;
                            }

                            $version_number++;
                            if ($version_number <= 9) {
                                $version_number = 0 . $version_number;
                            }
                        }

                        break;
                    }
                }
            }

            // Si la clasificación es nueva, crea su nuevo nombre
            if ($name_document == "") {
                $sequence_number = $this->resources_controller->formatSecuence($sequence_number, 6);
                $name_document = $line_number . '-' . $module_code . '-' . $document_clasification . '-' .
                    $REGISTER_DATE . '-' . $sequence_number . '=' .
                    $version_number . '=' . $document_name;
            }

            DB::table("S002V01TDOCU_P")
                ->insert([
                    "DOCU_NUSE" => $sequence_number,
                    "DOCU_LIDO" => $name_document,
                    "DOCU_IDPE" => $id_employee,
                    "DOCU_NULI" => $line_number,
                    "DOCU_USRE" => $user_id,
                    "DOCU_FERE" => $REGISTER_DATE,
                    "DOCU_FEAR" => DB::raw('CURRENT_TIMESTAMP'),
                ]);

            return $name_document;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error inesperado guardando el documento', strtoupper($th->getMessage()), 500);
        }

    }

    // Metodo para eliminar duplicado en la estructura de un mismo nombre
    public function deleteCodificationStructureName($document_name, $line_number, $module_code)
    {
        try {

            // Verifica que la nomenclatura no se duplique
            if (substr($document_name, 0, 8) == ($line_number . '-' . $module_code . '-') && strlen($document_name) > 28) {
                $document_name = substr($document_name, 28);
            }
            return $document_name;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error inesperado renombrando el documento', strtoupper($th->getMessage()), 500);
        }
    }

    // Metodo para buscar el nombre de la ultima versión de un documento
    public function getDocumentsWithSameName($document_name, $storage_disk)
    {
        try {

            $files_uploaded = Storage::disk($storage_disk)->files();
            $files = [];

            // Itera cada archivo guardado en el disco del storage
            foreach ($files_uploaded as $file) {
                if ($document_name == substr($file, 28)) {

                    // Guarda la liga del documento con ese nombre, si es que existe
                    $files[] = $file;
                }
            }

            // Verifica si el arreglo contiene algo
            if (isset($files[0]) && !empty($files[0])) {
                return $files;
            }

            // Si no hay coincidencias, devuelve el codigo de error XXXX
            return null;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error verificando el nombre del documento', strtoupper($th->getMessage()), 500);
        }
    }

    // Metodo para buscar el nombre de la ultima versión de un documento
    public function getDocumentsWithSameCodificationStructureName($document_name, $storage_disk)
    {
        try {

            $files_uploaded = Storage::disk($storage_disk)->files();
            $files = [];

            // Itera cada archivo guardado en el disco del storage
            foreach ($files_uploaded as $file) {
                if ($document_name == $file) {

                    // Guarda la liga del documento con ese nombre, si es que existe
                    $files[] = $file;
                }
            }

            // Verifica si el arreglo contiene algo
            if (isset($files[0]) && !empty($files[0])) {
                return $files;
            }

            // Si no hay, devuelve el codigo de error XXXX
            return null;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error verificando el nombre del documento', strtoupper($th->getMessage()), 500);
        }
    }

    // Metodo para verificar si ya existe el documento pdf
    public function sameDocumentsPdf($content, $old_documents_name)
    {
        try {

            // Se crea temporalmente un documento en el storage
            Storage::disk('pdf')->put(
                "TEMPORAL_FILE.pdf",
                $content
            );

            $new_file = (Storage::disk('pdf')->size("TEMPORAL_FILE.pdf"));

            // Itera cada archivo guardado en el disco del storage
            foreach ($old_documents_name as $file) {
                $old_file = (Storage::disk('pdf')->size($file));

                // Verifica si los documentos son iguales
                if ($old_file == $new_file) {
                    Storage::disk('pdf')->delete('TEMPORAL_FILE.pdf');
                    return $file;
                }

            }

            Storage::disk('pdf')->delete('TEMPORAL_FILE.pdf');
            return null;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error verificando autenticidad del documento', strtoupper($th), 500);
        }
    }

    // Metodo para eliminar una lista de documentos
    public function deleteAllDocumentsByName($document_names, $storage_disk)
    {
        foreach ($document_names as $document) {
            Storage::disk($storage_disk)->delete($document);
        }
    }

    // Metodo para verificar si ya existe el documento pdf enviando la información del request
    public function sameDocumentsPdfOnRequest($content, $old_documents_name)
    {
        try {

            // Se crea temporalmente un documento en el storage
            $content->storeAs('public/pdf_documents', "TEMPORAL_FILE.pdf");
            $new_file = (Storage::disk('pdf')->size("TEMPORAL_FILE.pdf"));

            // Itera cada archivo guardado en el disco del storage
            foreach ($old_documents_name as $file) {
                $old_file = (Storage::disk('pdf')->size($file));

                // Verifica si los documentos son iguales
                if ($old_file == $new_file) {
                    Storage::disk('pdf')->delete('TEMPORAL_FILE.pdf');
                    return $file;
                }

            }

            Storage::disk('pdf')->delete('TEMPORAL_FILE.pdf');
            return null;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error verificando autenticidad del documento', strtoupper($th->getMessage()), 500);
        }

    }


    // Metodo para verificar si ya existe el documento excel
    public function sameDocumentsExcel($document, $old_documents_name)
    {
        try {
            $document_repeated = null;
            $data_new_document = []; # Arreglo donde estarán los datos del nuevo documento

            $document = $document->getActiveSheet();

            $max_row = $document->getHighestRow(); # Fila
            $max_col = $document->getHighestColumn(); # Columna

            $max_col = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($max_col); # Se convierte la columna en numero

            // Se recorre el documento
            for ($row = 1; $row <= $max_row; $row++) {
                for ($col = 1; $col <= $max_col; $col++) {

                    // Se obtiene el valor de esa celda del documento y se introduce en el arreglo
                    $data_new_document[] = $document->getCellByColumnAndRow($col, $row)->getValue();
                }
            }

            foreach ($old_documents_name as $old_document_name) {

                $data_old_document = []; # Arreglo donde estarán los datos del viejo documento
                $old_document = IOFactory::load(Storage::disk('excel')->path($old_document_name));

                $document = $old_document->getActiveSheet();

                $max_row = $document->getHighestRow(); # Fila
                $max_col = $document->getHighestColumn(); # Columna
                $max_col = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($max_col); # Se convierte la columna en numero

                // Se recorre el documento
                for ($row = 1; $row <= $max_row; $row++) {
                    for ($col = 1; $col <= $max_col; $col++) {

                        // Se obtiene el valor de esa celda del documento y se introduce en el arreglo
                        $data_old_document[] = $document->getCellByColumnAndRow($col, $row)->getValue();
                    }
                }

                // Se compara dato por dato de cada documento para verificar si contiene lo mismo
                for ($i = 0; $i < sizeof($data_new_document); $i++) {
                    if ($data_new_document[$i] != $data_old_document[$i]) {
                        $document_repeated = null;
                        break 1;
                    }
                    $document_repeated = $old_document_name;
                }

                if ($document_repeated != null) {
                    return $document_repeated;
                }
            }

            return $document_repeated;

        } catch (Throwable $th) {
            return $this->response_controller
                ->makeResponse(TRUE, 'ERR_DOCUMENTO_REG001: Error verificando autenticidad del documento', strtoupper($th->getMessage()), 500);
        }
    }


}