<?php

declare(strict_types=1);

namespace SmsNotifier\Facade;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use SmsNotifier\Data\NotificationData;
use SmsNotifier\Facade\ClientCallBellAPI;
use SmsNotifier\Factory\MessageTextFactory;
use SmsNotifier\Service\Logger;
use SmsNotifier\Service\SmsNumberProvider;
use Twilio\Exceptions\HttpException;
use Ubnt\UcrmPluginSdk\Service\UcrmApi;
use \DateTime;

/*
 * send message to client's number
 */

abstract class AbstractMessageNotifierFacade
{
    /**
     * @var Logger
     */
    protected $logger;

    /**
     * @var MessageTextFactory
     */
    protected $messageTextFactory;

    /**
     * @var SmsNumberProvider
     */
    protected $clientPhoneNumber;

    /**
     * @var PluginNotifierFacade
     */
    private $pluginNotifierFacade;

    /**
     * @var UcrmApi
     */
    protected $ucrmApi;

    const SUBJECT_OF_INSTALLER_CHANGE = ["se ha cancelado una tarea que tenías asignada con el folio ", "se te ha desasignado❌ la tarea con el folio "];
    const ADDITIONAL_CHANGE_DATA = ["Ya no es necesario realizar la visita técnica.", "En tu lugar asistirá el técnico 👷🏻‍♂️➡️ "];

    public function __construct(
        Logger $logger,
        MessageTextFactory $messageTextFactory,
        SmsNumberProvider $clientPhoneNumber,
    ) {
        $this->logger = $logger;
        $this->messageTextFactory = $messageTextFactory;
        $this->clientPhoneNumber = $clientPhoneNumber;

    }

    /*
     * Verify contact type numbers to do notification, update or both
     */
    public function verifyPaymentActionToDo(NotificationData $notificationData): void
    {

        //$this->logger->debug(print_r(json_encode($notificationData),true).PHP_EOL);

        // Obtener los números de teléfono de los contactos
        $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);

        // Imprimir el array de teléfonos
        $this->logger->info(json_encode($arrayPhones));

        // Procesar el array de teléfonos y ejecutar la función correspondiente
        foreach ($arrayPhones as $type => $phones) {

            // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
            $this->logger->info("Procesando tipo de contacto original: '$type'");

            // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
            $type = trim(strtolower($type));

            // Registrar el tipo de contacto después de la normalización
            $this->logger->info("Tipo de contacto normalizado: '$type'");

            // Asegurarse de que $phones es un array y recorrerlo
            if (is_array($phones)) {
                foreach ($phones as $phone) {
                    switch ($type) {
                        case 'whatsapp':
                            // Ejecutar función de notificación y actualización
                            $this->notifyAndUpdate($notificationData, $phone);
                            break;

                        case 'whatsnotifica':
                            // Ejecutar función de notificación
                            $this->notify($notificationData, $phone);
                            break;

                        case 'whatsactualiza':
                            // Ejecutar función de actualización
                            $this->onlyUpdate($notificationData, $phone, false);
                            break;

                        default:
                            // Registrar cuando el tipo no es reconocido
                            $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
                            break;
                    }
                }
            } else {
                $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
            }
        }

    }

    /*
     * Verify contact type numbers to do client's data update at CallBell
     */
    public function verifyClientActionToDo(NotificationData $notificationData): void
    {
        //$this->logger->debug("Verificar contactos" . PHP_EOL);

        $this->logger->debug(print_r(json_encode($notificationData), true) . PHP_EOL);

        $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);

        // Procesar el array de teléfonos y ejecutar la función correspondiente
        foreach ($arrayPhones as $type => $phones) {

            // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
            $this->logger->info("Procesando tipo de contacto original: '$type'");

            // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
            $type = trim(strtolower($type));

            // Registrar el tipo de contacto después de la normalización
            $this->logger->info("Tipo de contacto normalizado: '$type'");

            // Asegurarse de que $phones es un array y recorrerlo
            if (is_array($phones)) {
                foreach ($phones as $phone) {
                    switch ($type) {
                        case 'whatsapp':
                            // Ejecutar función de notificación y actualización
                            $this->onlyUpdate($notificationData, $phone);
                            break;

                        case 'whatsactualiza':
                            // Ejecutar función de actualización
                            $this->onlyUpdate($notificationData, $phone);
                            break;

                        default:
                            // Registrar cuando el tipo no es reconocido
                            $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
                            break;
                    }
                }
            } else {
                $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
            }
        }

    }
    /*
     * Verify contact type numbers to do client's data service status at CallBell
     */
    public function verifyServiceActionToDo(NotificationData $notificationData): void
    {

        //$this->logger->debug(print_r(json_encode($notificationData),true).PHP_EOL);

        $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);

        // Procesar el array de teléfonos y ejecutar la función correspondiente
        foreach ($arrayPhones as $type => $phones) {

            // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
            $this->logger->info("Procesando tipo de contacto original: '$type'");

            // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
            $type = trim(strtolower($type));

            // Registrar el tipo de contacto después de la normalización
            $this->logger->info("Tipo de contacto normalizado: '$type'");

            // Asegurarse de que $phones es un array y recorrerlo
            if (is_array($phones)) {
                foreach ($phones as $phone) {
                    switch ($type) {
                        case 'whatsapp':
                            // Ejecutar función de notificación y actualización
                            $this->onlyUpdateService($notificationData, $phone);
                            break;

                        case 'whatsactualiza':
                            // Ejecutar función de actualización
                            $this->onlyUpdateService($notificationData, $phone);
                            break;

                        default:
                            // Registrar cuando el tipo no es reconocido
                            $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
                            break;
                    }
                }
            } else {
                $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
            }
        }

    }

    /*
     * Verify contact type numbers to do client's
     */
    public function verifyJobActionToDo($jsonNotificationData, $reprogramming = null, $changeInstaller = null): void
    {

        $this->logger->debug('******** INCIO DE LA FUNCIÓN verifyJobActionToDo ******' . PHP_EOL);
        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        $IPServer = $config['ipserver'];
        $UCRMAPIToken = $config['apitoken'];
        $CallBellAPIToken = $config['tokencallbell'];
        $IPServer = $config['ipserver'];
        $installersData = $config['installersDataWhatsApp'];

        $this->logger->debug('Valor de $jsonNotificationData en verifyJobActionToDo: ' . json_encode($jsonNotificationData) . PHP_EOL);

        $clientId = $jsonNotificationData['extraData']['entity']['clientId'];
        $installerId = $jsonNotificationData['extraData']['entity']['assignedUserId'];
        $jobId = $jsonNotificationData['entityId'];
        $jobDescription = $jsonNotificationData['extraData']['entity']['description'] ?? null;

        $reprogrammingValue = var_export($reprogramming, true);
        $changeInstallerValue = var_export($changeInstaller, true);
        $this->logger->debug('Valor de $reprogramming en verifyJobActionToDo: ' . $reprogrammingValue . PHP_EOL);
        $this->logger->debug('Valor de $changeInstaller en verifyJobActionToDo: ' . $changeInstallerValue . PHP_EOL);

        // Obtener la fecha del nodo "entity"
        $dateString = $jsonNotificationData['extraData']['entity']['date'] ?? null;

        if ($dateString) {
            // Crear un objeto DateTime a partir de la fecha
            $date = new DateTime($dateString);


            // concaternar emoji de reloj de la hora que más se asemeje a la hora del evento, por ejemplo si la hora es 8:00 am o pm se concatena el emoji de reloj de las 8:00 am o pm como: 🕗
            $hour = $date->format('h');
            $clockEmoji = "🕐"; // Emoji por defecto
            // Determinar el emoji del reloj según la hora
            // switch ($hour) {
            //     case '01':
            //         $clockEmoji = "🕐";
            //         break;
            //     case '02':
            //         $clockEmoji = "🕑";
            //         break;
            //     case '03':
            //         $clockEmoji = "🕒";
            //         break;
            //     case '04':
            //         $clockEmoji = "🕓";
            //         break;
            //     case '05':
            //         $clockEmoji = "🕔";
            //         break;
            //     case '06':
            //         $clockEmoji = "🕕";
            //         break;
            //     case '07':
            //         $clockEmoji = "🕖";
            //         break;
            //     case '08':
            //         $clockEmoji = "🕗";
            //         break;
            //     case '09':
            //         $clockEmoji = "🕘";
            //         break;
            //     case '10':
            //         $clockEmoji = "🕙";
            //         break;
            //     case '11':
            //         $clockEmoji = "🕚";
            //         break;
            //     case '12':
            //         $clockEmoji = "🕛";
            //         break;
            // }

            // Formatear la fecha al formato deseado: día/mes/año a las hora:minuto am/pm aproximadamente
            // $formattedDate = "*" . $date->format('d/m/Y') . "* a las $clockEmoji *" . $date->format('h:i A') . "* aproximadamente";
            $formattedDate = sprintf("*%s*", $date->format('d/m/Y'));


            // $this->logger->debug('Valor de $formattedDate en verifyJobActionToDo: ' . $formattedDate . PHP_EOL);
        } else {
            $this->logger->error('La fecha no está disponible en el JSON' . PHP_EOL);
        }

        $this->logger->debug('Valor de $installersData en verifyJobActionToDo: ' . $installersData . PHP_EOL);

        $this->ucrmApi = UcrmApi::create();
        $usersInstallers = $this->ucrmApi->get('users/admins/' . $installerId, []);
        $this->logger->debug('Valor de $usersInstallers en verifyJobActionToDo: ' . json_encode($usersInstallers) . PHP_EOL);

        // Inicializar la variable para el nombre completo
        $installerFullName = '';

        $jsonInstallersData = json_decode($installersData, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->logger->error('Error al decodificar el JSON de instaladores: ' . json_last_error_msg());
            return;
        }

        // Verificar si el nodo "instaladores" existe
        if (!isset($jsonInstallersData['instaladores'])) {
            $this->logger->error('El nodo "instaladores" no existe en el JSON');
            return;
        }

        // Buscar el número de WhatsApp en el JSON
        $installerWhatsApp = '';
        foreach ($jsonInstallersData['instaladores'] as $installer) {
            if ($installer['id'] === $installerId) {
                $installerWhatsApp = $installer['whatsapp'];
                break;
            }
        }
        //$this->logger->debug('tipo de dato de installerWhatsApp: ' . gettype($installerWhatsApp) . PHP_EOL);

        // Validar si se encontró el WhatsApp
        if (empty($installerWhatsApp)) {
            $this->logger->warning('No se encontró un número de WhatsApp para el instalador con ID 1019');
        } else {
            $this->logger->debug('Número de WhatsApp del Instalador: ' . $installerWhatsApp . PHP_EOL);
        }

        $this->ucrmApi = UcrmApi::create();
        $usersInstallers = $this->ucrmApi->get('users/admins/' . $installerId, []);
        //$this->logger->debug('Valor de $usersInstallers ' . json_encode($usersInstallers) . PHP_EOL);

        $firstName = $usersInstallers['firstName'] ?? '';
        $lastName = $usersInstallers['lastName'] ?? '';
        $installerFullName = trim("$firstName $lastName");
        $this->logger->debug('Valor de $installerFullName: ' . $installerFullName . PHP_EOL);

        $baseUri = 'https://' . $IPServer . '/crm/api/v1.0/';

        $clientGuzzleHttp = new Client([
            'base_uri' => $baseUri,
            'headers' => [
                'X-Auth-App-Key' => $UCRMAPIToken,
                'Accept' => 'application/json',
            ],
            'verify' => false,
        ]);

        $responseClients = $clientGuzzleHttp->request('GET', "clients/" . $clientId);
        $arrayClientCRM = json_decode($responseClients->getBody()->getContents(), true);
        // $this->logger->debug('Valor de $arrayClientCRM en verifyJobActionToDo: ' . json_encode($arrayClientCRM) . PHP_EOL);
        //ejemplo de $arrayClientCRM: {"id":2,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"Chiapas 31","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"Chiapas 31, Dolores Hidalgo Cuna de la Independencia Nacional, 37800","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":"Cliente espacial, el m\u00e1s chido","sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2024-01-25T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":true,"firstName":"Daniel Humberto","lastName":"Soto Villegas","username":"danydhsv","contacts":[{"id":2,"clientId":2,"email":"dhsv.141089@gmail.com","phone":"5214181878106","name":null,"isBilling":false,"isContact":false,"types":[]},{"id":170,"clientId":2,"email":null,"phone":"5214181148783","name":null,"isBilling":false,"isContact":false,"types":[{"id":1000,"name":"WhatsApp"}]}],"attributes":[{"id":112,"clientId":2,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_PetN1dhr4rx0kX","clientZoneVisible":true},{"id":113,"clientId":2,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"0021804341999569810","clientZoneVisible":true},{"id":178,"clientId":2,"customAttributeId":15,"name":"Site","key":"site","value":"0LOCS","clientZoneVisible":false},{"id":179,"clientId":2,"customAttributeId":16,"name":"Antena\/Sectorial","key":"antenaSectorial","value":"Sectorial-4b 172.16.13.16\/24","clientZoneVisible":false},{"id":200,"clientId":2,"customAttributeId":14,"name":"Chat de CallBell","key":"chatDeCallbell","value":"https","clientZoneVisible":false},{"id":202,"clientId":2,"customAttributeId":17,"name":"Password Antena Cliente","key":"passwordAntenaCliente","value":"gYAIEK:Be}SK*01z5+\/V","clientZoneVisible":false}],"accountBalance":-200,"accountCredit":100,"accountOutstanding":300,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#f1df43","addressGpsLat":21.1564414,"addressGpsLon":-100.9383654,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":true,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}

        //buscar en los attributes del cliente el atributo de con la key "passwordAntenaCliente" y almacenar su valor en la variable $passwordAntenaClienteCRM
        $passwordAntenaClienteCRM = '';
        foreach ($arrayClientCRM['attributes'] as $attribute) {
            if ($attribute['key'] === 'passwordAntenaCliente') {
                $passwordAntenaClienteCRM = $attribute['value'];
                $this->logger->debug('Valor de $passwordAntenaClienteCRM en verifyJobActionToDo: ' . $passwordAntenaClienteCRM . PHP_EOL);
                break;
            }
        }

        $clientFullName = sprintf("%s %s", $arrayClientCRM['firstName'], $arrayClientCRM['lastName']);

        // Extraer la dirección completa
        $fullAddress = $arrayClientCRM['fullAddress'] ?? null;

        // Validar si la dirección completa está disponible
        if ($fullAddress) {
            // Convertir la dirección a HTML seguro
            $safeAddress = htmlspecialchars($fullAddress, ENT_QUOTES, 'UTF-8');
            // $this->logger->debug('Dirección completa: ' . $safeAddress . PHP_EOL);
        } else {
            $this->logger->error('La dirección completa no está disponible en el JSON' . PHP_EOL);
        }

        // Extraer las coordenadas del nodo "entity"
        $gpsLat = $arrayClientCRM['addressGpsLat'] ?? null;
        $gpsLon = $arrayClientCRM['addressGpsLon'] ?? null;

        // Validar si las coordenadas están disponibles
        if ($gpsLat && $gpsLon) {
            // Construir la URL de Google Maps
            $googleMapsUrl = sprintf('https://www.google.com/maps?q=%s,%s', $gpsLat, $gpsLon);
            // $this->logger->debug('URL de Google Maps: ' . $googleMapsUrl . PHP_EOL);
        } else {
            $googleMapsUrl = 'Las coordenadas no están disponibles en este cliente.';
            $this->logger->error('Las coordenadas no están disponibles en el JSON' . PHP_EOL);
        }

        $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers(null, $arrayClientCRM);
        // $this->logger->debug('Valor de $arrayPhones en verifyJobActionToDo: ' . json_encode($arrayPhones) . PHP_EOL);

        $arrayAllPhones = $this->clientPhoneNumber->getAllUcrmClientNumbers($arrayClientCRM);

        // Convertir el array de teléfonos en una cadena separada por comas
        $clientAllPhonesString = implode(',', $arrayAllPhones);
        $this->logger->debug('Valor de $clientAllPhonesString en verifyJobActionToDo: ' . $clientAllPhonesString . PHP_EOL);

        // Dividir los números en un array
        $arrayNumeros = explode(',', $clientAllPhonesString);
        $this->logger->debug('Valor de $arrayNumeros en verifyJobActionToDo: ' . json_encode($arrayNumeros) . PHP_EOL);

        // Procesar cada número
        $resultados = [];
        foreach ($arrayNumeros as $numero) {
            $numero = trim($numero);
            $numeroValidado = $this->validarNumeroTelefono($numero);

            // Asegurar que solo quedan números
            $numeroValidado = preg_replace('/\D/', '', $numeroValidado);

            // Si empieza con 521 y tiene más de 12 dígitos, lo quitamos
            if (substr($numeroValidado, 0, 3) === "521") {
                $resultados[] = substr($numeroValidado, 3);
            } else {
                $resultados[] = $numeroValidado;
            }
        }
        $this->logger->debug('Valor de $resultados en verifyJobActionToDo: ' . json_encode($resultados) . PHP_EOL);

        // Convertir el array de resultados en una cadena separada por comas
        $resultadoFinalNumerosCliente = implode(', ', $resultados);
        $this->logger->debug('Valor de $resultadoFinalNumerosCliente en verifyJobActionToDo: ' . $resultadoFinalNumerosCliente . PHP_EOL);

        $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);

        // Construir el array asociativo con los datos de la notificación para el cliente
        $jsonClientJobNotificationData = [
            "clientFullName" => $clientFullName,
            "jobId" => $jobId,
            "date" => $formattedDate,
            "installerName" => $installerFullName,
        ];

        $clientWhatsApp = '';

        //Parte de la notificación al cliente
        // Procesar el array de teléfonos y ejecutar la función correspondiente
        foreach ($arrayPhones as $type => $phones) {

            // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
            $type = trim(strtolower($type));

            switch ($type) {
                case 'whatsapp':
                case 'whatsnotifica':
                    $this->logger->debug("Se encontró un tipo de contacto $type" . PHP_EOL);

                    // Verificar si el valor es un array de teléfonos
                    if (is_array($phones)) {
                        $attempts = 0;
                        $maxAttempts = 3;
                        $result = false;
                        foreach ($phones as $phone) {

                            //Aquí se enviará la notificación al cliente
                            // Reintentar hasta 3 veces si la función retorna false
                            while ($attempts < $maxAttempts && $result === false) {
                                $attempts++;
                                $result = $client_callbell_api->sendJobNotificationWhatsAppToClient(
                                    $this->validarNumeroTelefono($phone), // Validar número de teléfono
                                    $jsonClientJobNotificationData,       // Datos de notificación
                                    $reprogramming,                       // Reprogramación
                                    $changeInstaller                      // Cambio de instalador
                                );

                                if ($result === false) {
                                    sleep(1); // Esperar 1 segundo antes de reintentar
                                    $this->logger->warning("Intento $attempts fallido en el envío de notificación a $phone. Reintentando..." . PHP_EOL);
                                }
                            }

                            // Verificar el resultado final
                            if ($result === true) {
                                $this->logger->info("Notificación enviada correctamente al cliente con teléfono $phone después de $attempts intento(s)." . PHP_EOL);
                                $title = $jsonNotificationData['extraData']['entity']['title'];
                                $this->logger->debug('Valor de $title en verifyJobActionToDo: ' . $title . PHP_EOL);
                                //la variable $title contiene el título del trabajo con un prefijo "[NOTIFICACION-PENDIENTE]" aquí hay que quitarlo

                                // $this->ucrmApi = UcrmApi::create();
                                // $responsePatch = $this->ucrmApi->patch('scheduling/jobs/' . $jsonNotificationData['entityId'], [
                                //     'title' => $title,
                                // ]);
                                if (strpos($title, '[NOTIFICACION-PENDIENTE]') !== false) {             //si el título contiene el prefijo [NOTIFICACION-PENDIENTE] entonces se quita
                                    $title = str_replace('[NOTIFICACION-PENDIENTE]', '', $title); // Quitar el prefijo
                                    $responseClients = $clientGuzzleHttp->request('PATCH', "scheduling/jobs/" . $jsonNotificationData['entityId'], [
                                        'json' => [
                                            'title' => $title,
                                        ],
                                    ]);
                                    $this->logger->debug('Valor de $title después de quitar el prefijo en verifyJobActionToDo: ' . $title . PHP_EOL);
                                    break;

                                } else {
                                    $this->logger->debug('El título no contiene el prefijo [NOTIFICACION-PENDIENTE] en verifyJobActionToDo: ' . $title . PHP_EOL);
                                }

                            } else {
                                $this->logger->error("No se pudo enviar la notificación al cliente con teléfono $phone después de $maxAttempts intentos." . PHP_EOL);
                            }
                        }
                    } else {
                        $this->logger->warning("No se encontraron números de teléfono para el tipo de contacto $type." . PHP_EOL);
                    }

                    break;

                default:
                    $this->logger->info("Tipo de contacto no reconocido: $type" . PHP_EOL);
                    break;
            }
        }

        // --- ¡AÑADE ESTAS LÍNEAS PARA CONVERTIR A BOOLEANO REAL! ---
        $reprogramming = filter_var($reprogramming, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        $changeInstaller = filter_var($changeInstaller, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        // -----------------------------------------------------------

        // Puedes volver a loggear los valores para confirmar la conversión (opcional)
        $this->logger->debug("DEBUG: Valores después de conversión para mensaje instalador - Reprogramming: " . var_export($reprogramming, true) . ", ChangeInstaller: " . var_export($changeInstaller, true) . PHP_EOL);


        if ($changeInstaller) { //Si se cambió el instalador
            $this->logger->debug('Se cambió el instalador, por lo tanto se procede a enviarle mensaje al que se le desasignó' . PHP_EOL);

            // Construir el array asociativo con los datos de la notificación

            //Enviar notificación al instalador anterior

            $previousinstallerInstallerId = $installerId = $jsonNotificationData['extraData']['entityBeforeEdit']['assignedUserId'];
            $usersInstallers = $this->ucrmApi->get('users/admins/' . $previousinstallerInstallerId, []);
            $firstNamePreviousInstaller = $usersInstallers['firstName'] ?? ''; //Obtener el nombre del instalador anterior
            $lastNamePreviousInstaller = $usersInstallers['lastName'] ?? '';  //Obtener el apellido del instalador anterior
            $previousInstallerFullName = trim("$firstNamePreviousInstaller $lastNamePreviousInstaller");
            $attempts = 0;
            $maxAttempts = 3;
            $result = false;

            $jsonPreviousInstallerJobNotificationData = [
                "installerName" => "👷🏻‍♂️" . $previousInstallerFullName,
                "subjectOfChange" => self::SUBJECT_OF_INSTALLER_CHANGE[1],
                "jobId" => $jobId,
                "clientFullName" => sprintf("[%s] %s", $arrayClientCRM['id'], $clientFullName),
                "additionalChangeData" => self::ADDITIONAL_CHANGE_DATA[1] . ' *' . $installerFullName . '*',

            ];

            // Buscar el número de WhatsApp en el JSON del instalador anterior
            $previousInstallerWhatsApp = '';
            foreach ($jsonInstallersData['instaladores'] as $installer) {
                if ($installer['id'] === $previousinstallerInstallerId) {
                    $previousInstallerWhatsApp = $installer['whatsapp'];
                    $this->logger->debug('Se encontró el Whatsapp del instalador anterior en el JSON y es: ' . $previousInstallerWhatsApp . PHP_EOL);
                    break;
                }
            }

            //Enviar mensaje al instalador anterior
            // Reintentar hasta 3 veces si la función retorna false
            while ($attempts < $maxAttempts && $result === false) {
                $attempts++;
                $result = $client_callbell_api->sendJobNotificationWhatsAppToInstaller(
                    $this->validarNumeroTelefono((string) $previousInstallerWhatsApp),
                    $jsonPreviousInstallerJobNotificationData,
                    $reprogramming,
                    $changeInstaller,
                    ''

                );

                if ($result === false) {
                    sleep(1);
                    $this->logger->warning("Intento $attempts fallido para enviar notificación a $phone. Reintentando..." . PHP_EOL);
                }
            }

            sleep(4);

            // Construir el array asociativo con los datos de la notificación para el instalador nuevo
            $jsonInstallerJobNotificationData = [
                "installerName" => $installerFullName,
                "clientFullName" => sprintf("%s [ID:%s]", $clientFullName, $arrayClientCRM['id']),
                "jobId" => $jobId,
                "clientAddress" => $safeAddress,
                "clientWhatsApp" => $resultadoFinalNumerosCliente,
                "date" => $formattedDate,
                "jobDescription" => $jobDescription,
                "gmapsLocation" => $googleMapsUrl,
                "passwordAntenaCliente" => ''

            ];

            //obtener la contraseña de la antena con el método getVaultCredentialsByClientId y compararlo con el campo de la contraseña de la antena en el CRM
            $passwordVault = $this->getVaultCredentialsByClientId($arrayClientCRM['id']);
            
            //Comparar las contraseñas y obtener la que se enviará al instalador
            $jsonInstallerJobNotificationData['passwordAntenaCliente'] = $this->comparePasswords($passwordAntenaClienteCRM, $passwordVault);



            //Enviar notificación al instalador nuevo

            $attempts = 0;
            $maxAttempts = 3;
            $result = false;

            // Reintentar hasta 3 veces si la función retorna false
            while ($attempts < $maxAttempts && $result === false) {
                $attempts++;
                $result = $client_callbell_api->sendJobNotificationWhatsAppToInstaller(
                    $this->validarNumeroTelefono((string) $installerWhatsApp),
                    $jsonInstallerJobNotificationData,
                    false,
                    false,

                );

                if ($result === false) {
                    sleep(1);
                    $this->logger->warning("Intento $attempts fallido para enviar notificación a $phone. Reintentando..." . PHP_EOL);
                }
            }

        } else { //si el instalador no cambió
            $this->logger->debug('No se cambió el instalador' . PHP_EOL);

            // Construir el array asociativo con los datos de la notificación
            $jsonInstallerJobNotificationData = [
                "installerName" => $installerFullName,
                "clientFullName" => sprintf("%s [ID:%s]", $clientFullName, $arrayClientCRM['id']),
                "jobId" => $jobId,
                "clientAddress" => $safeAddress,
                "clientWhatsApp" => $resultadoFinalNumerosCliente,
                "date" => $formattedDate,
                "jobDescription" => $jobDescription,
                "gmapsLocation" => $googleMapsUrl,
                "passwordAntenaCliente" => ''

            ];

            //obtener la contraseña de la antena con el método getVaultCredentialsByClientId y compararlo con el campo de la contraseña de la antena en el CRM
            $passwordVault = $this->getVaultCredentialsByClientId($arrayClientCRM['id']);

            //Comparar las contraseñas y obtener la que se enviará al instalador
            $jsonInstallerJobNotificationData['passwordAntenaCliente'] = $this->comparePasswords($passwordAntenaClienteCRM, $passwordVault);




            $attempts = 0;
            $maxAttempts = 3;
            $result = false;

            // // Reintentar hasta 3 veces si la función retorna false
            while ($attempts < $maxAttempts && $result === false) {
                $attempts++;
                $result = $client_callbell_api->sendJobNotificationWhatsAppToInstaller(
                    $this->validarNumeroTelefono((string) $installerWhatsApp),
                    $jsonInstallerJobNotificationData,
                    $reprogramming,
                    $changeInstaller,

                );

                if ($result === false) {
                    sleep(1);
                    $this->logger->warning("Intento $attempts fallido para enviar notificación a $phone. Reintentando..." . PHP_EOL);
                }
            }

        }

    }

    /*
     * Verify contact type numbers to do client's data update at CallBell by invoice add or edit
     */
    public function verifyInvoiceActionToDo(NotificationData $notificationData): void
    {

        $accountBalance = $notificationData->clientData['accountBalance'];
        $this->logger->debug(print_r(json_encode($notificationData), true) . PHP_EOL);

        $arrayPhones = $this->clientPhoneNumber->getUcrmClientNumbers($notificationData, null);

        // Procesar el array de teléfonos y ejecutar la función correspondiente
        foreach ($arrayPhones as $type => $phones) {

            // Registrar el tipo de contacto antes de la normalización para verificar qué valor se recibe
            $this->logger->info("Procesando tipo de contacto original: '$type'");

            // Normalizar el tipo para manejar posibles diferencias en las mayúsculas o espacios en blanco
            $type = trim(strtolower($type));

            // Registrar el tipo de contacto después de la normalización
            $this->logger->info("Tipo de contacto normalizado: '$type'");

            // Asegurarse de que $phones es un array y recorrerlo
            if (is_array($phones)) {
                foreach ($phones as $phone) {
                    switch ($type) {
                        case 'whatsapp':
                            // Ejec vb bbnbbnbvnutar función de notificación y actualización
                            $this->onlyUpdate($notificationData, $phone, false);
                            break;

                        case 'whatsactualiza':
                            // Ejecutar función de actualización
                            $this->onlyUpdate($notificationData, $phone, false);
                            break;

                        default:
                            // Registrar cuando el tipo no es reconocido
                            $this->logger->info("Tipo de contacto no reconocido: '$type'" . PHP_EOL);
                            break;
                    }
                }
            } else {
                $this->logger->info("Formato no esperado para los números de teléfono en el tipo: $type" . PHP_EOL);
            }
        }
    }

    /*
     * Notify to client with the payment receipt via WhatsApp
     */
    public function notify(NotificationData $notificationData, $phoneToNotify = null): void
    {

        // $notification_client_data = $notificationData->clientData; //array con los datos del cliente

        // $notification_client_data_export = json_encode($notification_client_data);
        // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        // the "exportFormat" key must be defined in plugin's manifest file, see the link above
        $IPServer = $config['ipserver'];
        $UCRMAPIToken = $config['apitoken'];
        $CallBellAPIToken = $config['tokencallbell'];
        $notificationTypeText = $config['notificationTypeText'];

        $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);

        //$clientPhoneNumber = $this->clientPhoneNumber->getUcrmClientNumber($notificationData);
        $clientPhoneNumber = $this->validarNumeroTelefono($phoneToNotify); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"

        //$this->logger->debug("Numero de cel obtenido " . $clientPhoneNumber . PHP_EOL);

        if (empty($clientPhoneNumber)) {
            $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
            return;
        } else {

            if ($notificationTypeText) {
                try {
                    $attempts = 0;
                    $maxAttempts = 3;
                    $result = false;

                    while ($attempts < $maxAttempts && !$result) {
                        $attempts++;
                        $result = $client_callbell_api->sendTextPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData);

                        if (!$result) {
                            $this->logger->warning("Intento $attempts fallido para enviar notificación de texto al cliente con número $clientPhoneNumber." . PHP_EOL);
                        }
                    }

                    if ($result) {
                        $this->logger->info("Notificación de texto enviada correctamente al cliente con número $clientPhoneNumber después de $attempts intento(s)." . PHP_EOL);
                    } else {
                        $this->logger->error("No se pudo enviar la notificación de texto al cliente con número $clientPhoneNumber después de $maxAttempts intentos." . PHP_EOL);
                    }
                } catch (HttpException $httpException) {
                    $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
                }

            } else {
                try {
                    $attempts = 0;
                    $maxAttempts = 3;
                    $result = false;

                    while ($attempts < $maxAttempts && !$result) {
                        $attempts++;
                        $result = $client_callbell_api->sendPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData);

                        if (!$result) {
                            $this->logger->warning("Intento $attempts fallido para enviar notificación al cliente con número $clientPhoneNumber." . PHP_EOL);
                        }
                    }

                    if ($result) {
                        $this->logger->info("Notificación enviada correctamente al cliente con número $clientPhoneNumber después de $attempts intento(s)." . PHP_EOL);
                    } else {
                        $this->logger->error("No se pudo enviar la notificación al cliente con número $clientPhoneNumber después de $maxAttempts intentos." . PHP_EOL);
                    }
                } catch (HttpException $httpException) {
                    $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
                }

            }

        }

        // $messageBody = $this->messageTextFactory->createBody($notificationData);
        // if (! $messageBody) {
        //     $this->logger->info('No text configured for event: ' . $notificationData->eventName);
        //     return;
        // }

    }

    /*
     * Notify to client with the payment receipt via WhatsApp and Update the client's data at CallBell
     */
    public function notifyAndUpdate(NotificationData $notificationData, $phoneToNotifyAndUpdate = null): void
    {
        $this->logger->debug("***Se notifica y actualiza al cliente sobre su pago***" . PHP_EOL);

        // $notification_client_data = $notificationData->clientData; //array con los datos del cliente

        // $notification_client_data_export = json_encode($notification_client_data);
        // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
        //$this->logger->debug("Creando instancia callbell ".PHP_EOL);
        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        // the "exportFormat" key must be defined in plugin's manifest file, see the link above
        $IPServer = $config['ipserver'];
        $UCRMAPIToken = $config['apitoken'];
        $CallBellAPIToken = $config['tokencallbell'];
        $notificationTypeText = $config['notificationTypeText'];

        $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
        //$this->logger->debug(" instancia callbell creada".PHP_EOL);
        //$clientPhoneNumber = $this->validarNumeroTelefono($this->clientPhoneNumber->getUcrmClientNumber($notificationData));

        //$clientPhoneNumber = $this->clientPhoneNumber->getUcrmClientNumber($notificationData);
        //$clientPhoneNumber = $this->validarNumeroTelefono($this->clientPhoneNumber->getUcrmClientNumber($notificationData)); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"

        $clientPhoneNumber = $this->validarNumeroTelefono($phoneToNotifyAndUpdate);

        if (empty($clientPhoneNumber)) {
            $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
            return;
        } else {

            //$this->logger->debug(sprintf('llego al llamado de sendPaymentNotificationWhatsApp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));

            if ($notificationTypeText) {
                $this->logger->debug("Activado el check de mensajes de texto: " . $notificationTypeText . PHP_EOL);
            }

            if ($notificationTypeText) {
                try {

                    if ($client_callbell_api->sendTextPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData)) {
                        $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
                        $client_callbell_api->patchWhatsapp($response_getContactCallBell, $notificationData);
                    } else {
                        $this->logger->warning("No se pudo enviar el comprobante para este cliente" . PHP_EOL);
                    }
                } catch (\Exception $Exception) {
                    $this->logger->error($Exception->getCode() . ' ' . $Exception->getMessage());
                }

            } else {

                try {
                    if ($client_callbell_api->sendPaymentNotificationWhatsApp($clientPhoneNumber, $notificationData)) {
                        $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
                        $client_callbell_api->patchWhatsapp($response_getContactCallBell, $notificationData);
                    } else {
                        $this->logger->warning("No se pudo enviar el comprobante para este cliente" . PHP_EOL);
                    }

                } catch (\Exception $Exception) {
                    $this->logger->error($Exception->getCode() . ' ' . $Exception->getMessage());
                }
            }

        }

        // $messageBody = $this->messageTextFactory->createBody($notificationData);
        // if (! $messageBody) {
        //     $this->logger->info('No text configured for event: ' . $notificationData->eventName);
        //     return;
        // }

    }

    /*
     * Notify to client about Invoice Overdue
     */
    public function notifyOverDue(NotificationData $notificationData): void
    {
        $this->logger->debug("***Se notifica al cliente que la factura de su servicio está vencida***" . PHP_EOL);

        // $notification_client_data = $notificationData->clientData; //array con los datos del cliente

        // $notification_client_data_export = json_encode($notification_client_data);
        // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);
        //$this->logger->debug("Creando instancia callbell ".PHP_EOL);
        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        // the "exportFormat" key must be defined in plugin's manifest file, see the link above
        $IPServer = $config['ipserver'];
        $UCRMAPIToken = $config['apitoken'];
        $CallBellAPIToken = $config['tokencallbell'];

        $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
        //$this->logger->debug(" instancia callbell creada".PHP_EOL);
        //$clientPhoneNumber = $this->validarNumeroTelefono($this->clientPhoneNumber->getUcrmClientNumber($notificationData));
        $clientPhoneNumber = $this->clientPhoneNumber->getUcrmClientNumber($notificationData);
        $this->logger->debug("Numero de cel obtenido " . $clientPhoneNumber . PHP_EOL);

        if (empty($clientPhoneNumber)) {
            $this->logger->warning('No se encontró un teléfono celular válido para el cliente:  ' . $notificationData->clientId);
            return;
        } else {

            try {
                //$this->logger->debug(sprintf('llego al llamado de sendPaymentNotificationWhatsApp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
                //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
                //$this->sendWhatsApp($notificationData, $clientSmsNumber);

                $client_callbell_api->sendOverdueNotificationWhatsApp($clientPhoneNumber, $notificationData);

            } catch (HttpException $httpException) {
                //$this->logger->debug('Ocurrio un error en el try catch');
                $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
            }
        }

        // $messageBody = $this->messageTextFactory->createBody($notificationData);
        // if (! $messageBody) {
        //     $this->logger->info('No text configured for event: ' . $notificationData->eventName);
        //     return;
        // }

    }

    /*
     * Update the client's data at CallBell
     */
    public function onlyUpdate(NotificationData $notificationData, $phoneToUpdate = null, $updateEmail = false): void
    {
        //$this->logger->info("Se enviará una actualización a Callbell " . PHP_EOL);

        $notification_client_data = $notificationData->clientData; //array con los datos del cliente

        // $notification_client_data_export = json_encode($notification_client_data);
        // $this->logger->info("Valor de notification client data export: " . $notification_client_data_export . PHP_EOL);

        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        // the "exportFormat" key must be defined in plugin's manifest file, see the link above
        $IPServer = $config['ipserver'];
        $UCRMAPIToken = $config['apitoken'];
        $CallBellAPIToken = $config['tokencallbell'];
        $StripeToken = $config['tokenstripe'];

        $attributes = $notificationData->clientData['attributes']; //Obtener los atributos del cliente
        // Variable para almacenar los valores de los atributos que comienzan con "clabe"

        // Iterar sobre los atributoss
        foreach ($attributes as $attribute) {
            // Verificar si la "key" comienza con "stripe"
            if (strpos($attribute['key'], 'stripe') === 0) {
                // Agregar el valor al array $clabeValues
                $customerStripeID = $attribute['value'];
            } else if (strpos($attribute['key'], 'clabe') === 0) { // Verificar si la "key" comienza con "clabe"
                // Agregar el valor al array $clabeValues
                $clabeInterbancaria = $attribute['value'];
            }

        }

        if ($updateEmail) {
            $contacts = $notificationData->clientData['contacts'] ?? []; //Obtener los contactos que tiene el cliente para buscar el email

            foreach ($contacts as $contact) {

                $types = $contact['types'] ?? []; //Obtener los tipos de contactos del cliente
                foreach ($types as $type) {

                    if ($type['name'] == 'WhatsApp') { //Si el tipo de contacto es Whatsapp

                        $client_email = $contact['email']; //Asignar el correo del cliente a la variable
                        break;
                    }
                }

            }
            $this->logger->info("Se procesaron los contactos para revisar el o los email" . PHP_EOL);

            $stripe = new \Stripe\StripeClient($StripeToken); //Instancia de la clase manejadora de clientes para la API de Stripe

            if ($client_email !== null && $customerStripeID !== null) {
                $this->logger->info("Se actualizara el correo del cliente en Stripe: " . $client_email . PHP_EOL);
                $stripe->customers->update($customerStripeID, ['email' => $client_email]); //Actualiza el correo electrónico del cliente en la plataforma de Stripe en su correspondiente "customer Stripe ID"
            }
        }

        $clientPhoneNumber = $this->validarNumeroTelefono($phoneToUpdate); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"

        if (empty($clientPhoneNumber)) {
            $this->logger->warning('No se encontró un teléfono celular válido para el cliente: ' . $notificationData->clientId);
            return;
        } else {

            try {
                //$this->logger->debug(sprintf('llego al llamado de sendwhatsapp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
                //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
                //$this->sendWhatsApp($notificationData, $clientSmsNumber);

                //$client_callbell_api->sendMessageWhatsApp($clientPhoneNumber, $notificationData);
                $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
                $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
                //$this->logger->debug('Se hizo la petición al callbell para obtener el uuid' . PHP_EOL);
                $client_callbell_api->patchWhatsapp($response_getContactCallBell, $notificationData, $clabeInterbancaria);

            } catch (HttpException $httpException) {
                //$this->logger->debug('Ocurrio un error en el try catch');
                $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
            }
        }

        // $notificationData_export = var_export($notificationData, true);
        // $this->logger->debug('valor de notificationdata: ' . $notificationData_export);

        // $messageBody = $this->messageTextFactory->createBody($notificationData);
        // if (! $messageBody) {
        //     $this->logger->info('No text configured for event: ' . $notificationData->eventName);
        //     return;
        // }

    }

    /*
     * Update de status of service at CallBell
     */
    public function onlyUpdateService(NotificationData $notificationData, $phoneToUpdate): void
    {
        //$this->logger->info("Se enviará una actualización del estado del servicio a Callbell, estado del servicio: ".$notificationData->serviceData['status'] . PHP_EOL);
        $this->logger->info(json_encode($notificationData) . PHP_EOL);

        //$clientID = $notificationData->extraData['entity']['clientId'];

        //$this->logger->info("client id " .$clientID. PHP_EOL);

        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        // the "exportFormat" key must be defined in plugin's manifest file, see the link above
        $IPServer = $config['ipserver'];
        $UCRMAPIToken = $config['apitoken'];
        $CallBellAPIToken = $config['tokencallbell'];

        $clientPhoneNumber = $this->validarNumeroTelefono($phoneToUpdate); //Obtiene el número de celular del cliente que sea del tipo de contacto "WhatsApp"
        //$this->logger->info("Número de telefono obtenido para actualizar:" .$clientPhoneNumber. PHP_EOL);

        if (empty($clientPhoneNumber)) {
            $this->logger->warning('No se encontró un teléfono celular válido para el cliente:  ' . $notificationData->clientId);
            return;
        } else {

            try {
                //$this->logger->debug(sprintf('llego al llamado de sendwhatsapp con client_id: %s y número de celular: %s', $notificationData->clientId, $clientPhoneNumber));
                //$this->sendMessage($notificationData, $clientSmsNumber, $messageBody);
                //$this->sendWhatsApp($notificationData, $clientSmsNumber);

                $client_callbell_api = new ClientCallBellAPI($UCRMAPIToken, $IPServer, $CallBellAPIToken);
                $response_getContactCallBell = json_decode($client_callbell_api->getContactWhatsapp($clientPhoneNumber), true);
                $client_callbell_api->patchServiceStatusWhatsApp($response_getContactCallBell, $notificationData);

            } catch (HttpException $httpException) {
                //$this->logger->debug('Ocurrio un error en el try catch');
                $this->logger->error($httpException->getCode() . ' ' . $httpException->getMessage());
            }
        }

    }

    /**
     * implement in subclass with the specific messaging provider
     * @see TwilioNotifierFacade::sendMessage()
     */
    abstract protected function sendMessage(
        NotificationData $notificationData,
        string $clientSmsNumber,
        string $messageBody
    ): void;

    //     /**
    //      * implement in subclass with the specific messaging provider
    //      * @see TwilioNotifierFacade::sendWhatsApp()
    //      */
    //     abstract protected function sendWhatsApp(
    //         NotificationData $notificationData,
    //         string $clientSmsNumber
    //     ): void;

    function validarNumeroTelefono($telefono)
    {
        // Eliminar espacios y guiones
        $telefono = preg_replace('/\s+|-/', '', $telefono);

        // Eliminar caracteres no numéricos, excepto el '+' si está al principio
        $telefono = preg_replace('/(?!^\+)[^0-9]/', '', $telefono);

        // Verificar si el número comienza con "+1" o "1" y tiene 11 dígitos en total
        if (
            (substr($telefono, 0, 2) === "+1" && strlen($telefono) === 12) ||
            (substr($telefono, 0, 1) === "1" && strlen($telefono) === 11)
        ) {
            return $telefono;
        }

        // Si el número tiene exactamente 10 dígitos, agregar el prefijo "521"
        if (strlen($telefono) === 10) {
            return "521" . $telefono;
        }

        // Si el número tiene más de 10 dígitos, verificar que comience con "521"
        if (strlen($telefono) > 10) {
            if (substr($telefono, 0, 2) === "521" && strlen($telefono) === 12) {
                return $telefono;
            } else {
                // Si no comienza con "52", tomar los últimos 10 dígitos y agregar el prefijo "52"
                return "521" . substr($telefono, -10);
            }
        }

        // Si no cumple con ninguna de las condiciones anteriores, retornar cadena vacía
        return '';
    }

    function patchClientCustomAttribute($clientId, $attributeId, $value): bool
    {
        $logger = \Ubnt\UcrmPluginSdk\Service\PluginLogManager::create();
        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        $ucrmBaseUri = $config['ipserver'];
        $authToken = $config['apitoken'];

        $ucrmBaseUri = 'https://' . $ucrmBaseUri . '/crm/api/v1.0/';
        $clientguzz = new Client(); //instancia de cliente GuzzleHttp para consumir API UISP CRM

        $json_data_patch = '{
                                        "attributes": [
                                          {
                                            "value": "' . $value . '",
                                            "customAttributeId":' . $attributeId . '
                                          }
                                        ]
    
                                      }'; //JSON para hacer patch de los custom fields del cliente en el UISCP CRM

        try {
            //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM
            $responseCRM = $clientguzz->patch(
                $ucrmBaseUri . 'clients/' . $clientId,
                [
                    'headers' => [
                        'X-Auth-Token' => $authToken,
                        'Content-Type' => 'application/json',
                    ],
                    'body' => $json_data_patch,
                    'verify' => false, // Deshabilitar la verificación del certificado SSL
                ],

            );
            //evaluar el código de respuesta HTTP y si es 200 se retorna true
            if ($responseCRM->getStatusCode() === 200) {
                $this->logger->info("Se actualizó el custom attribute del cliente " . $clientId . PHP_EOL);
                return true; // Return true if patch is successful
            } else {
                $this->logger->info("Error al hacer el patch al CRM: " . $responseCRM->getStatusCode() . PHP_EOL);
                return false; // Return false if patch fails
            }


        } catch (\GuzzleHttp\Exception\GuzzleException $error) {
            $this->logger->info("Error al hacer el patch al CRM: " . $error->getMessage() . PHP_EOL);
            return false; // Return false if patch fails
        }

    }
    function getVaultCredentials($dataToSearch): string
    {

        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        $ucrmBaseUri = $config['ipserver'];
        $crmAuthToken = $config['apitoken'];
        $unmsAuthToken = $config['unmsApiToken'];

        if ($ucrmBaseUri === '172.16.5.134') { //opción solo para el servidor de pruebas
            return 'gYAIEK:Be}SK*01z5+/V';
        }

        $unmsBaseUri = 'https://' . $ucrmBaseUri . '/nms/api/v2.1/';
        $ucrmBaseUri = 'https://' . $ucrmBaseUri . '/crm/api/v1.0/';
        //$authToken = '7adc9198-50b1-41d0-9bfa-d4946902ed89';

        // Crear una instancia del cliente Guzzle
        $clientUnms = new Client([
            'base_uri' => $unmsBaseUri,
            'verify' => false, // Deshabilitar la verificación del certificado SSL
        ]);

        $clientUcrm = new Client([
            'base_uri' => $ucrmBaseUri,
            'verify' => false, // Deshabilitar la verificación del certificado SSL
        ]);

        //validar si dataToSearch es una dirección IP o una dirección MAC
        if (filter_var($dataToSearch, FILTER_VALIDATE_IP)) {

            // La variable es una dirección IP válida
            //$logger->appendLog('Consulta por dirección IP: ' . $dataToSearch);
            $this->logger->info('Consulta por dirección IP: ' . $dataToSearch . PHP_EOL);


            if ($ucrmBaseUri === '172.16.5.134') { //opción solo para el servidor de pruebas
                return 'gYAIEK:Be}SK*01z5+/V';
            }

            $IpAddressClientId = filter_var($dataToSearch, FILTER_VALIDATE_IP);

            try {
                $responseSitesByIP = $clientUnms->request('GET', 'sites/search?query=' . $dataToSearch . '&count=1&page=1', [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);

                if ($responseSitesByIP->getStatusCode() === 200) {

                    $datasSitesByIP = json_decode((string) $responseSitesByIP->getBody(), true);
                    $jsonDevicesBySite = json_encode($datasSitesByIP, JSON_PRETTY_PRINT);
                    //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio

                    if (isset($datasSitesByIP[0])) {
                        $siteId = $datasSitesByIP[0]['id'];
                        // print_r('ID DEL SITIO: ' . $siteId . PHP_EOL); // ID del sitio
                    } else {

                        $this->logger->error('No se encontró ningún sitio para la IP proporcionada: ' . $dataToSearch . PHP_EOL);
                        return 'Error: No se encontró ningún sitio para la IP proporcionada: ' . $dataToSearch; // Return early if no site is found
                    }

                } else {

                    $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseSitesByIP->getStatusCode() . PHP_EOL);
                    return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseSitesByIP->getStatusCode(); // Return early if the request fails
                }

                $devicesBySiteId = $clientUnms->request('GET', 'devices?siteId=' . $siteId, [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);

                if ($devicesBySiteId->getStatusCode() === 200) {
                    $dataDevicesBySite = json_decode((string) $devicesBySiteId->getBody(), true);
                    $jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
                    //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio
                    $deviceID = null;

                    foreach ($dataDevicesBySite as $device) {
                        if (isset($device['ipAddress'])) {
                            $ipAddress = explode('/', $device['ipAddress'])[0]; // Obtener solo la IP sin la máscara
                            if ($ipAddress === $IpAddressClientId) {
                                $deviceID = $device['identification']['id'];
                                break; // Salir del ciclo si se encuentra la IP
                            }
                        } else {
                            $this->logger->error('No se encontró la IP del dispositivo en la respuesta de la API.' . PHP_EOL);
                            return 'Error: No se encontró la IP del dispositivo en la respuesta de la API.'; // Return early if the IP is not found
                        }
                    }

                    if ($deviceID == null) {
                        $this->logger->error('No se encontró el dispositivo con la IP proporcionada: ' . $IpAddressClientId . PHP_EOL);
                        return 'Error: No se encontró el dispositivo con la IP proporcionada: ' . $IpAddressClientId; // Return early if no device is found
                    }

                } else {
                    $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $devicesBySiteId->getStatusCode() . PHP_EOL);
                    return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $devicesBySiteId->getStatusCode(); // Return early if the request fails
                }

                $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $deviceID . '/credentials', [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);

                if ($responsePasswordVault->getStatusCode() === 200) {
                    $dataPasswordVault = json_decode((string) $responsePasswordVault->getBody(), true);
                    // $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
                    //print_r($jsonPasswordVault . PHP_EOL); //Credenciales del dispositivo

                    if (isset($dataPasswordVault['credentials'][0]['password'])) {
                        $dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
                    } else {
                        $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
                        return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
                    }
                    return $dataPasswordVault;

                } else {
                    $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
                    return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
                }

            } catch (RequestException $requestException) {
                // Manejar errores de la solicitud, si hay error 404 entonces responder que no se encontró niguna IP asociada a alguna antena o dispositivo de red
                if ($requestException->hasResponse()) {
                    $response = $requestException->getResponse();
                    $statusCode = $response->getStatusCode();
                    $reason = $response->getReasonPhrase();

                    if ($statusCode == 404) {
                        $this->logger->error('No se encontró el cliente con la dirección IP proporcionada: ' . $IpAddressClientId . PHP_EOL);
                        return 'Error: No se encontró el cliente con la dirección IP proporcionada: ' . $IpAddressClientId; // Return early if the client is not found
                    }
                    return 'Error: ' . $reason; // Return early if the request fails
                } else {
                    $this->logger->error('Error al realizar la solicitud: ' . $requestException->getMessage() . PHP_EOL);
                    return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                }

            }

        } else if (preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $dataToSearch)) {
            // La variable es una dirección MAC válida

            $this->logger->info('Consulta por dirección MAC: ' . $dataToSearch . PHP_EOL);

            if ($ucrmBaseUri === '172.16.5.134') { //opción solo para el servidor de pruebas
                return 'gYAIEK:Be}SK*01z5+/V';
            }

            try {
                // //para mandarla al endpoint de dispositivos por MAC se necesita convertir la cadena de la direccion mac en un formato como el siguiente ejemplo: para la dirección mac 60:22:32:c8:b2:c3 quedaría como 60%3A22%3A32%3Ac8%3Ab2%3Ac3
                // $dataToSearch = str_replace(':', '%3A', $dataToSearch);
                // $logger->appendLog('Consulta por dirección MAC: ' . $dataToSearch );
                $responseDeviceByMAC = $clientUnms->request('GET', 'devices/mac/' . $dataToSearch, [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);

                if ($responseDeviceByMAC->getStatusCode() === 200) {

                    $dataDeviceByMAC = json_decode((string) $responseDeviceByMAC->getBody(), true);
                    $jsonDeviceByMac = json_encode($dataDeviceByMAC, JSON_PRETTY_PRINT);
                    // print_r($jsonDeviceByMac . PHP_EOL); //Devices por ID del sitio
                    //$logger->appendLog($jsonDeviceByMac.PHP_EOL);

                    //Ejemplo de $responseDeviceByMac en json: {"id":"84c8a581-154c-41db-81d5-a1b1c9ede411","type":"airMax","series":"AC"}
                    //obtener el id del dispositivo y si no existe el id del dispositivo entonces devolver un mensaje de error
                    if (isset($dataDeviceByMAC['id'])) {
                        $deviceId = $dataDeviceByMAC['id'];
                        // print_r('ID DEL DISPOSITIVO: ' . $deviceId . PHP_EOL); // ID del dispositivo
                    } else {
                        $this->logger->error('No se encontró el dispositivo con la dirección MAC proporcionada: ' . $dataToSearch . PHP_EOL);
                        return 'Error: No se encontró el dispositivo con la dirección MAC proporcionada: ' . $dataToSearch; // Return early if no device is found
                    }

                }

                $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $deviceId . '/credentials', [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);

                if ($responsePasswordVault->getStatusCode() === 200) {
                    $dataPasswordVault = json_decode((string) $responsePasswordVault->getBody(), true);

                    if (isset($dataPasswordVault['credentials'][0]['password'])) {
                        $dataPasswordVault = $dataPasswordVault['credentials'][0]['password'];
                    } else {
                        $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
                        return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
                    }
                    return $dataPasswordVault;

                } else {
                    $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
                    return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
                }

            } catch (RequestException $requestException) {
                // Manejar errores de la solicitud, si hay error 404 entonces responder que no se encontró niguna MAC asociada a alguna antena o dispositivo de red
                if ($requestException->hasResponse()) {
                    $response = $requestException->getResponse();
                    $statusCode = $response->getStatusCode();
                    $reason = $response->getReasonPhrase();

                    if ($statusCode == 404) {
                        $this->logger->error('No se encontró ninguna antena de cliente o dispositivo en la red con la dirección MAC proporcionada: ' . $dataToSearch . PHP_EOL);
                        return 'Error: No se encontró ninguna antena de cliente o dispositivo en la red con la dirección MAC proporcionada: ' . $dataToSearch; // Return early if the client is not found
                    }
                    $this->logger->error('Error: ' . $reason . PHP_EOL);
                    return 'Error: ' . $reason; // Return early if the request fails
                } else {
                    $this->logger->error('Error al realizar la solicitud: ' . $requestException->getMessage() . PHP_EOL);
                    return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                }

            }

        } else {
            // La variable no es una dirección IP válida, se asume que es un ID
            $IpAddressClientId = filter_var($dataToSearch, FILTER_SANITIZE_NUMBER_INT);
            //print ('Consulta por ID: ' . $dataToSearch . PHP_EOL);
            $this->logger->info('Consulta por ID: ' . $dataToSearch . PHP_EOL);


            try {
                //Obtener id del sitio por medio del servicio
                $responseServices = $clientUcrm->get('clients/services?clientId=' . $IpAddressClientId, [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                        'Content-Type: application/json',
                    ],
                ]);

            } catch (RequestException $requestException) {
                // Manejar errores de la solicitud
                if ($requestException->hasResponse()) {
                    $response = $requestException->getResponse();
                    $statusCode = $response->getStatusCode();
                    $reason = $response->getReasonPhrase();
                    //si el statusCode es 404 significa que no se encontró el cliente
                    if ($statusCode == 404) {
                        $this->logger->error('No se encontró el cliente con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
                        return 'Error: No se encontró el cliente con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
                    }
                    return 'Error: ' . $reason; // Return early if the request fails

                } else {
                    $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                    return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                }

            }

            if ($responseServices->getStatusCode() === 200) {

                $dataServices = json_decode($responseServices->getBody()->getContents(), true);

                if (isset($dataServices[0])) {
                    $unmsSiteID = $dataServices[0]['unmsClientSiteId']; // Example: 9c6798f3-0254-4e5b-bc3b-9da82fe16e46
                } else {
                    $this->logger->error('No se encontraron servicios para el cliente proporcionado: ' . $IpAddressClientId . PHP_EOL);
                    return "Error: No se encontraron servicios para el cliente proporcionado: " . $IpAddressClientId; // Return early if no services are found
                }

            } else {
                $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseServices->getStatusCode() . PHP_EOL);
                return "Error: En la solicitud. Código de estado HTTP: " . $responseServices->getStatusCode();
            }

            try {
                $responseDevicesBySite = $clientUnms->request('GET', 'devices?siteId=' . $unmsSiteID, [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);
            } catch (RequestException $requestException) {
                // Manejar errores de la solicitud
                if ($requestException->hasResponse()) {
                    $response = $requestException->getResponse();
                    $statusCode = $response->getStatusCode();
                    $reason = $response->getReasonPhrase();
                    //si el statusCode es 404 significa que no se encontró el cliente
                    if ($statusCode == 404) {
                        $this->logger->error('No se encontró el devicie con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
                        return 'Error: No se encontró el devicie con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
                    }
                    $this->logger->error('Error: ' . $reason . PHP_EOL);
                    return 'Error: ' . $reason; // Return early if the request fails

                } else {
                    $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                    return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                }

            }

            if ($responseDevicesBySite->getStatusCode() === 200) {

                $dataDevicesBySite = json_decode($responseDevicesBySite->getBody()->getContents(), true);
                $jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
                //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio

                //id del device al que está conectado el cliente
                if (isset($dataDevicesBySite[0])) {
                    //verificar con iiset si existe la clave 'identification' y 'apDevice' en el primer elemento del array
                    if (isset($dataDevicesBySite[0]['identification']) && isset($dataDevicesBySite[0]['attributes']['apDevice'])) {
                        $idClientDevice = $dataDevicesBySite[0]['identification']['id'];
                        $deviceID = $dataDevicesBySite[0]['attributes']['apDevice']['id'];
                    } else {
                        $this->logger->error('No se encontró el dispositivo con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
                        return "Este cliente es un repetidor."; // Return early if the key is not found
                    }

                } else {
                    $this->logger->error('No se encontraron dispositivos para el sitio proporcionado: ' . $unmsSiteID . PHP_EOL);
                    return "Error: No se encontraron dispositivos para el sitio proporcionado."; // Return early if no devices are found
                }

            } else {
                $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
                return "Error: Falla en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode();
            }

            try {
                $responseDevicesBySite = $clientUnms->request('GET', 'devices/' . $deviceID, [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);
            } catch (RequestException $requestException) {
                // Manejar errores de la solicitud
                if ($requestException->hasResponse()) {
                    $response = $requestException->getResponse();
                    $statusCode = $response->getStatusCode();
                    $reason = $response->getReasonPhrase();
                    //si el statusCode es 404 significa que no se encontró el cliente
                    if ($statusCode == 404) {
                        $this->logger->error('No se encontró el device con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
                        return 'Error: No se encontró el device con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
                    }
                    return 'Error: ' . $reason; // Return early if the request fails

                } else {
                    $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                    return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                }

            }

            if ($responseDevicesBySite->getStatusCode() === 200) {

                $dataDevices = json_decode($responseDevicesBySite->getBody()->getContents(), true);
                $jsonDevices = json_encode($dataDevices, JSON_PRETTY_PRINT);
                //print_r($jsonDevices . PHP_EOL);

                try {
                    //print_r('ID del device al que está conectado el cliente: ' . $idDevice . PHP_EOL);
                    $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $idClientDevice . '/credentials', [
                        'headers' => [
                            'X-Auth-Token' => $unmsAuthToken,
                        ],
                    ]);
                } catch (RequestException $requestException) {
                    // Manejar errores de la solicitud
                    if ($requestException->hasResponse()) {
                        $response = $requestException->getResponse();
                        $statusCode = $response->getStatusCode();
                        $reason = $response->getReasonPhrase();
                        //si el statusCode es 404 significa que no se encontró el cliente
                        if ($statusCode == 404) {
                            $this->logger->error('No se encontró el device con el ID proporcionado: ' . $IpAddressClientId . PHP_EOL);
                            return 'Error: No se encontró el device con el ID proporcionado: ' . $IpAddressClientId; // Return early if the client is not found
                        }
                        $this->logger->error('Error: ' . $reason . PHP_EOL);
                        return 'Error: ' . $reason; // Return early if the request fails

                    } else {
                        $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                        return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                    }
                }

                if ($responsePasswordVault->getStatusCode() === 200) {
                    $dataPasswordVault = json_decode($responsePasswordVault->getBody()->getContents(), true);
                    $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
                    if (isset($dataPasswordVault['credentials'][0]['password'])) {
                        $passwordVault = $dataPasswordVault['credentials'][0]['password'];
                        return $passwordVault;
                    } else {
                        $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
                        return "Error: No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
                    }

                } else {
                    $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
                    return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
                }

            } else {
                $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
                return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode(); // Return early if the request fails

            }

        }

    }
    function getVaultCredentialsByClientId($clientId): string
    {

        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        $ipServer = $config['ipserver'];
        $crmAuthToken = $config['apitoken'];
        $unmsAuthToken = $config['unmsApiToken'];

        if ($ipServer === '172.16.5.134') { //opción solo para el servidor de pruebas
            return 'gYAIEK:Be}SK*01z5+/V';
        }

        $unmsBaseUri = 'https://' . $ipServer . '/nms/api/v2.1/';
        $ucrmBaseUri = 'https://' . $ipServer . '/crm/api/v1.0/';
        //$authToken = '7adc9198-50b1-41d0-9bfa-d4946902ed89';

        // Crear una instancia del cliente Guzzle
        $clientUnms = new Client([
            'base_uri' => $unmsBaseUri,
            'verify' => false, // Deshabilitar la verificación del certificado SSL
        ]);

        $clientUcrm = new Client([
            'base_uri' => $ucrmBaseUri,
            'verify' => false, // Deshabilitar la verificación del certificado SSL
        ]);


        $this->logger->debug('Consulta por ID: ' . $clientId . PHP_EOL);


        try {
            //Obtener id del sitio por medio del servicio
            $responseServices = $clientUcrm->get('clients/services?clientId=' . $clientId, [
                'headers' => [
                    'X-Auth-Token' => $crmAuthToken,
                    'Content-Type: application/json',
                ],
            ]);

        } catch (RequestException $requestException) {
            // Manejar errores de la solicitud
            if ($requestException->hasResponse()) {
                $response = $requestException->getResponse();
                $statusCode = $response->getStatusCode();
                $reason = $response->getReasonPhrase();
                //si el statusCode es 404 significa que no se encontró el cliente
                if ($statusCode == 404) {
                    $this->logger->error('No se encontró el cliente con el ID proporcionado: ' . $clientId . PHP_EOL);
                    return 'No se encontró el cliente con el ID proporcionado: ' . $clientId; // Return early if the client is not found
                }
                return 'Error: ' . $reason; // Return early if the request fails

            } else {
                $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
            }

        }

        if ($responseServices->getStatusCode() === 200) {

            $dataServices = json_decode($responseServices->getBody()->getContents(), true);

            if (isset($dataServices[0])) {
                $unmsSiteID = $dataServices[0]['unmsClientSiteId']; // Example: 9c6798f3-0254-4e5b-bc3b-9da82fe16e46
            } else {
                $this->logger->error('No se encontraron servicios para el cliente proporcionado: ' . $clientId . PHP_EOL);
                return "No se encontraron servicios para el cliente proporcionado: " . $clientId; // Return early if no services are found
            }

        } else {
            $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseServices->getStatusCode() . PHP_EOL);
            return "Error: En la solicitud. Código de estado HTTP: " . $responseServices->getStatusCode();
        }

        try {
            $responseDevicesBySite = $clientUnms->request('GET', 'devices?siteId=' . $unmsSiteID, [
                'headers' => [
                    'X-Auth-Token' => $unmsAuthToken,
                ],
            ]);
        } catch (RequestException $requestException) {
            // Manejar errores de la solicitud
            if ($requestException->hasResponse()) {
                $response = $requestException->getResponse();
                $statusCode = $response->getStatusCode();
                $reason = $response->getReasonPhrase();
                //si el statusCode es 404 significa que no se encontró el cliente
                if ($statusCode == 404) {
                    $this->logger->error('No se encontró el device con el ID proporcionado: ' . $clientId . PHP_EOL);
                    return 'No se encontró el device con el ID proporcionado: ' . $clientId; // Return early if the client is not found
                }
                $this->logger->error('Error: ' . $reason . PHP_EOL);
                return 'Error: ' . $reason; // Return early if the request fails

            } else {
                $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
            }

        }

        if ($responseDevicesBySite->getStatusCode() === 200) {

            $dataDevicesBySite = json_decode($responseDevicesBySite->getBody()->getContents(), true);
            $jsonDevicesBySite = json_encode($dataDevicesBySite, JSON_PRETTY_PRINT);
            //print_r($jsonDevicesBySite . PHP_EOL); //Devices por ID del sitio

            //id del device al que está conectado el cliente
            if (isset($dataDevicesBySite[0])) {
                //verificar con iiset si existe la clave 'identification' y 'apDevice' en el primer elemento del array
                if (isset($dataDevicesBySite[0]['identification']) && isset($dataDevicesBySite[0]['attributes']['apDevice'])) {
                    $idClientDevice = $dataDevicesBySite[0]['identification']['id'];
                    $deviceID = $dataDevicesBySite[0]['attributes']['apDevice']['id'];
                } else {
                    $this->logger->error('No se encontró el dispositivo con el ID proporcionado: ' . $clientId . PHP_EOL);
                    return "Este cliente es un repetidor."; // Return early if the key is not found
                }

            } else {
                $this->logger->error('No se encontraron dispositivos para el sitio proporcionado: ' . $unmsSiteID . PHP_EOL);
                return "No se encontraron dispositivos para el sitio proporcionado."; // Return early if no devices are found
            }

        } else {
            $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
            return "Error: Falla en la solicitud. Código de estado HTTP: " . $responseDevicesBySite->getStatusCode();
        }

        try {
            $responseDevicesBySite = $clientUnms->request('GET', 'devices/' . $deviceID, [
                'headers' => [
                    'X-Auth-Token' => $unmsAuthToken,
                ],
            ]);
        } catch (RequestException $requestException) {
            // Manejar errores de la solicitud
            if ($requestException->hasResponse()) {
                $response = $requestException->getResponse();
                $statusCode = $response->getStatusCode();
                $reason = $response->getReasonPhrase();
                //si el statusCode es 404 significa que no se encontró el cliente
                if ($statusCode == 404) {
                    $this->logger->error('No se encontró el device con el ID proporcionado: ' . $clientId . PHP_EOL);
                    return 'No se encontró el dispositivo de red con el ID proporcionado: ' . $clientId; // Return early if the client is not found
                }
                return 'Error: ' . $reason; // Return early if the request fails

            } else {
                $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
            }

        }

        if ($responseDevicesBySite->getStatusCode() === 200) {

            $dataDevices = json_decode($responseDevicesBySite->getBody()->getContents(), true);
            $jsonDevices = json_encode($dataDevices, JSON_PRETTY_PRINT);
            //print_r($jsonDevices . PHP_EOL);

            try {
                //print_r('ID del device al que está conectado el cliente: ' . $idDevice . PHP_EOL);
                $responsePasswordVault = $clientUnms->request('GET', 'vault/' . $idClientDevice . '/credentials', [
                    'headers' => [
                        'X-Auth-Token' => $unmsAuthToken,
                    ],
                ]);
            } catch (RequestException $requestException) {
                // Manejar errores de la solicitud
                if ($requestException->hasResponse()) {
                    $response = $requestException->getResponse();
                    $statusCode = $response->getStatusCode();
                    $reason = $response->getReasonPhrase();
                    //si el statusCode es 404 significa que no se encontró el cliente
                    if ($statusCode == 404) {
                        $this->logger->error('No se encontró el device con el ID proporcionado: ' . $clientId . PHP_EOL);
                        return 'No se encontró el dispositivo de red con el ID proporcionado: ' . $clientId; // Return early if the client is not found
                    }
                    $this->logger->error('Error: ' . $reason . PHP_EOL);
                    return 'Error: ' . $reason; // Return early if the request fails

                } else {
                    $this->logger->error('Error: ' . $requestException->getMessage() . PHP_EOL);
                    return 'Error: ' . $requestException->getMessage(); // Return early if the request fails
                }
            }

            if ($responsePasswordVault->getStatusCode() === 200) {
                $dataPasswordVault = json_decode($responsePasswordVault->getBody()->getContents(), true);
                $jsonPasswordVault = json_encode($dataPasswordVault, JSON_PRETTY_PRINT);
                if (isset($dataPasswordVault['credentials'][0]['password'])) {
                    $passwordVault = $dataPasswordVault['credentials'][0]['password'];
                    return $passwordVault;
                } else {
                    $this->logger->error('No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida.' . PHP_EOL);
                    return "No se encontró una contraseña en la bóveda para la antena de este cliente, es altamente probable que conserve una contraseña conocida."; // Return early if the password is not found
                }

            } else {
                $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode() . PHP_EOL);
                return 'Error: Falla en la solicitud. Código de estado HTTP: ' . $responsePasswordVault->getStatusCode(); // Return early if the request fails
            }

        } else {
            $this->logger->error('Falla en la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode() . PHP_EOL);
            return 'Error: Falla en  la solicitud. Código de estado HTTP: ' . $responseDevicesBySite->getStatusCode(); // Return early if the request fails

        }



    }

    function comparePasswords($passwordVault, $passwordAntenaClienteCRM): string
    {
        $erroresVaultPrefix = [
                'Error:',
                'No se encon',
                'Falla en',
            ];

        // Validar si la contraseña de la antena del cliente en el CRM es igual a la contraseña de la antena del cliente en el Vault y de ser iguales devolver la contraseña del vault
        if ($passwordAntenaClienteCRM === $passwordVault) {
            $this->logger->debug('La contraseña de la antena del cliente en el CRM
                es igual a la contraseña de la antena del cliente en el Vault.' . PHP_EOL);
            return $passwordVault;
        } else {
            //si no son iguales entonces validar si alguna de las contraseñas no contiene un prefijo de error para decidir cuál devolver; si 

            
            if (!empty($passwordAntenaClienteCRM) && !array_filter($erroresVaultPrefix, fn($prefix) => str_starts_with($passwordAntenaClienteCRM, $prefix))) { //verificar que la contraseña del CRM no comience con ninguno de los prefijos de error o esté vacía
                $this->logger->debug('La contraseña de la antena del cliente en el CRM será la que se envíe al instalador.' . PHP_EOL);
                return $passwordAntenaClienteCRM;
            } elseif (!empty($passwordVault) && !array_filter($erroresVaultPrefix, fn($prefix) => str_starts_with($passwordVault, $prefix))) { //verificar que la contraseña del vault no comience con ninguno de los prefijos de error o esté vacía
                $this->logger->debug('La contraseña de la antena del cliente en el Vault será la que se envíe al instalador.' . PHP_EOL);
                return $passwordVault;
            } else {
                //asignar la variable con un texto de advertencia sobre que ninguna de las contraseñas es válida para ser enviada al instalador
                $this->logger->debug('Ninguna de las contraseñas de la antena es válida para ser enviada al instalador.' . PHP_EOL);
                return '⚠️ Probar una contraseña conocida como Siip.567 etc. ya que no se encontró una contraseña en el UISP Vault ni en el CRM.';
            }
        }
    }

}
