<?php

declare(strict_types=1);

namespace SmsNotifier;

use Psr\Log\LogLevel;
use SmsNotifier\Facade\PluginNotifierFacade;
use SmsNotifier\Facade\PluginOxxoNotifierFacade;
use SmsNotifier\Facade\TwilioNotifierFacade;
use SmsNotifier\Factory\NotificationDataFactory;
use SmsNotifier\Service\Logger;
use SmsNotifier\Service\OptionsManager;
use SmsNotifier\Service\PluginDataValidator;
use Twilio\Exceptions\TwilioException;
use Ubnt\UcrmPluginSdk\Service\UcrmApi;

class Plugin
{
    /**
     * @var Logger
     */
    private $logger;

    /**
     * @var OptionsManager
     */
    private $optionsManager;

    /**
     * @var PluginDataValidator
     */
    private $pluginDataValidator;

    /**
     * @var PluginNotifierFacade
     */
    private $pluginNotifierFacade;
    /**
     * @var PluginOxxoNotifierFacade
     */
    private $pluginOxxoNotifierFacade;
    /**
     * @var TwilioNotifierFacade
     */
    private $notifierFacade;

    /**
     * @var NotificationDataFactory
     */
    private $notificationDataFactory;

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

    public function __construct(
        Logger $logger,
        OptionsManager $optionsManager,
        PluginDataValidator $pluginDataValidator,
        TwilioNotifierFacade $notifierFacade,
        PluginNotifierFacade $pluginNotifierFacade,
        PluginOxxoNotifierFacade $pluginOxxoNotifierFacade,
        NotificationDataFactory $notificationDataFactory
    ) {
        $this->logger                   = $logger;
        $this->optionsManager           = $optionsManager;
        $this->pluginDataValidator      = $pluginDataValidator;
        $this->notifierFacade           = $notifierFacade;
        $this->pluginNotifierFacade     = $pluginNotifierFacade;
        $this->pluginOxxoNotifierFacade = $pluginOxxoNotifierFacade;
        $this->notificationDataFactory  = $notificationDataFactory;
        $config = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create()->loadConfig();
        $ipServer = $config['ipserver'] ?? 'localhost';
        $apiUrl = "https://$ipServer/crm/api/v1.0/";
        $client = new \GuzzleHttp\Client([
            'base_uri' => $apiUrl,
            'verify' => false,
        ]);
        $this->ucrmApi = new UcrmApi($client, $config['apitoken'] ?? '');
    }

    public function run(): void
    {
        if (PHP_SAPI === 'fpm-fcgi' || PHP_SAPI === 'cgi-fcgi' || PHP_SAPI === 'apache2handler') {
            $this->processHttpRequest();
        } elseif (PHP_SAPI === 'cli') {
            $this->processCli();
        } else {
            $this->logger->error('SAPI desconocido: ' . PHP_SAPI . '. Intentando procesar como HTTP.');
            $this->processHttpRequest();
        }
    }

    private function processCli(): void
    {
        if ($this->pluginDataValidator->validate()) {
            $this->logger->info('Validating config');
            $this->optionsManager->load();
        }
    }

    private function processHttpRequest(): void
    {
        $pluginData = $this->optionsManager->load();
        if ($pluginData->logging_level || $pluginData->debugMode) {
            $this->logger->setLogLevelThreshold(LogLevel::DEBUG);
        }

        $userInput = file_get_contents('php://input');

        // DEBUG TEMPORAL

        $this->logger->debug('Payload recibido: ' . $userInput . PHP_EOL);

        if (! $userInput) {
            $this->logger->warning('No se recibió input en la petición HTTP.');
            return;
        }

        $jsonData = @json_decode((string)$userInput, true, 50);

        if (! isset($jsonData['uuid'])) {
            $this->logger->info('No UUID found in the webhook data');
            //$this->logger->error('JSON error: ' . json_last_error_msg());

            //return;

            // Maneja el evento del webhook externo
            if ($jsonData) {
                switch ($jsonData['type']) {
                    case 'customer_cash_balance_transaction.created':
                        if ($jsonData['data']['object']['type'] === 'funded') {
                            $this->logger->info('Evento de transferencia de un cliente recibido: ' . json_encode($jsonData) . PHP_EOL);
                            $this->pluginNotifierFacade->createPaymentIntent($jsonData);
                        }

                        if ($jsonData['data']['object']['type'] === 'applied_to_payment') {
                            $this->logger->info('Se aplicó el saldo en Stripe de un pago: ' . json_encode($jsonData) . PHP_EOL);
                            $this->pluginNotifierFacade->registerPaymentFromWebhook($jsonData);
                        } elseif ($jsonData['data']['object']['type'] === 'unapplied_from_payment') {
                            //ejemplo de json para transferencia de dinero cancelada: {"id":"evt_1RlEGgEFY1WEUtgR6Bp2DzDP","object":"event","api_version":"2023-10-16","created":1752606717,"data":{"object":{"id":"ccsbtxn_1RlEGfEFY1WEUtgRv8jAUGmE","object":"customer_cash_balance_transaction","created":1752606717,"currency":"mxn","customer":"cus_PetN1dhr4rx0kX","ending_balance":18000,"livemode":false,"net_amount":18000,"type":"unapplied_from_payment","unapplied_from_payment":{"payment_intent":"pi_3RlDPdEFY1WEUtgR1JBgNhTQ"}}},"livemode":false,"pending_webhooks":2,"request":{"id":"req_954mskVBfAI0jn","idempotency_key":"749518f6-baa0-4ae9-99e4-8029a35719aa"},"type":"customer_cash_balance_transaction.created"}
                            $paymentIntentId = $jsonData['data']['object']['unapplied_from_payment']['payment_intent'];
                            //Se canceló una transferencia de dinero, imprimir que se canceló y además el monto neto
                            $this->logger->warning('Evento de transferencia cancelada para el pago: ' . $paymentIntentId . PHP_EOL);
                            $this->logger->warning('Monto neto de la transferencia cancelada: ' . $jsonData['data']['object']['net_amount'] . PHP_EOL);
                        }
                        break;
                    case 'payout.failed':
                        $this->logger->info('Evento de transferencia fallida encontrado: ' . json_encode($jsonData) . PHP_EOL);
                        //imprimir detalles del fallo
                        $this->logger->info('Detalles del fallo: ' . json_encode($jsonData));
                        break;
                    case 'payment_intent.partially_funded':
                        $this->logger->info('Evento de pago parcialmente financiado encontrado: ' . json_encode($jsonData) . PHP_EOL);
                        //imprimir detalles del evento o pago
                        $this->logger->info('Detalles del evento: ' . json_encode($jsonData));
                        break;
                    case 'inbound_payment.payment_attempt':
                        //$this->logger->info('Evento de Pago de OXXO recibido: ' . json_encode($jsonData) . PHP_EOL);
                        break;
                    case 'cash_balance.funds_available':
                        $this->logger->info('Evento de Pago de fondos disponibles recibido: ' . json_encode($jsonData) . PHP_EOL);
                        break;
                    case 'payment_intent.succeeded':
                        $this->logger->info('Evento de pago exitoso (Stripe PI) recibido.');
                        if (isset($jsonData['data']['object'])) {
                            $this->pluginNotifierFacade->registerPaymentFromIntent($jsonData['data']['object']);
                        }
                        break;
                    case 'oxxo.retrieve':
                        $this->logger->info('Evento de recuperación de orden OXXO recibido');
                        $orderId = $jsonData['order_id'] ?? null;

                        if ($orderId) {
                            $status = $this->pluginOxxoNotifierFacade->getOxxoOrderStatus($orderId);
                            $this->logger->debug("Estado recuperado para Orden #$orderId: " . json_encode($status));

                            header('Content-Type: application/json');
                            echo json_encode($status);
                        } else {
                            $this->logger->warning('Solicitud de oxxo.retrieve sin order_id');
                            echo json_encode(['error' => 'missing_order_id']);
                        }
                        return; // Terminar ejecución aquí
                        break;
                    case 'oxxo.request':
                        $this->logger->info('Evento de solicitud de referencia de OXXO recibido (Async Flow)');

                        // 1. Obtener datos de Stripe (OXXO Reference, URL, etc.)
                        $stripeResult = $this->pluginOxxoNotifierFacade->createStripeReference($jsonData, $jsonData['amount'] ?? null);

                        if ($stripeResult['hasError'] ?? false) {
                            $this->logger->error('Error generando referencia Stripe: ' . json_encode($stripeResult));
                            header('Content-Type: application/json');
                            echo json_encode([
                                'oxxo_reference' => '',
                                'url' => '',
                                'error' => $stripeResult['data']['error'] ?? 'stripe_error',
                                'status' => 'failed'
                            ]);
                            exit;
                        }

                        $oxxoData = $stripeResult['data'];

                        // 2. Crear Orden (Sync) para obtener ID
                        // Ahora pasamos $oxxoData que SI tiene clientID, clientFullName, etc.
                        $responseOxxo = $this->pluginOxxoNotifierFacade->createOxxoOrder($oxxoData);

                        $orderId = $responseOxxo['order_id'] ?? null;

                        // 3. Preparar respuesta inmediata (Pending)
                        $responseArray = [
                            'oxxo_reference' => $responseOxxo['oxxo_reference'] ?? '',
                            'url' => '', // No hay URL de imagen todavía
                            'stripe_url' => $responseOxxo['url'] ?? '',
                            'voucher_image_url' => '',
                            'order_id' => $orderId,
                            'clientFullName' => $responseOxxo['clientFullName'] ?? '',
                            'clientID' => $responseOxxo['clientID'] ?? '',
                            'amount' => $responseOxxo['amount'] ?? '',
                            'error' => $responseOxxo['error'] ?? '',
                            'status' => 'generating' // Estado esperado por el bot para iniciar polling
                        ];

                        // 4. Enviar Respuesta y CERRAR Conexión
                        // Limpiamos buffers
                        while (ob_get_level() > 0) {
                            ob_end_clean();
                        }

                        header('Content-Type: application/json');
                        header('Connection: close');
                        ignore_user_abort(true); // Permitir que el script siga corriendo

                        echo json_encode($responseArray);

                        // Forzar envío al cliente
                        if (function_exists('fastcgi_finish_request')) {
                            fastcgi_finish_request();
                        } else {
                            // Fallback para servidores no FastCGI
                            header('Content-Length: ' . strlen(json_encode($responseArray)));
                            flush();
                        }

                        // 5. Trabajo en Pesado (Background)
                        if ($orderId) {
                            $this->logger->info("Iniciando generación background para orden #$orderId");
                            set_time_limit(180); // 3 minutos para Puppeteer
                            sleep(1); // Pequeña pausa para asegurar liberación del socket

                            $this->pluginOxxoNotifierFacade->generateOxxoVoucher($responseOxxo, true);

                            $this->logger->info("Generación background finalizada para orden #$orderId");
                        } else {
                            $this->logger->error("No se pudo iniciar background job: Falta order_id");
                        }

                        // Terminar proceso hijo
                        exit;
                        break;
                }
            }
            return;
        }

        $notification = $this->notificationDataFactory->getObject($jsonData);
        $this->logger->debug('Evento recibido: ' . $notification->eventName);

        if ($notification->changeType === 'test') {

            $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
            $config        = $configManager->loadConfig();

            $this->logger->info('Webhook test successful.');

            return;
        } else if ($notification->changeType === 'paperless.update') {
            //imprimir el webhook json
            $this->logger->info('Webhook de paperless update: ' . json_encode($jsonData) . PHP_EOL);
        }
        // if (!$notification->clientId) {
        //     $this->logger->warning('No client specified, cannot notify them.');

        //     return;
        // }

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

        try {

            if ($notification->eventName === 'payment.add') {

                $result = json_encode($notification);
                $this->logger->debug('Notification encodificado en JSON:' . $result . PHP_EOL);

                // [MOVED] Attempt to patch method ID only if it comes as "Stripe Credit Card" (catch-all)
                //$this->pluginNotifierFacade->ensureStripePaymentAttribute($notification); (Removed from top)

                $payment_method_id = $notification->paymentData['methodId'];
                $payment_method = '';

                switch ($payment_method_id) {
                    case '11721cdf-a498-48be-903e-daa67552e4f6':
                        $payment_method = 'Cheque';
                        if ($config['checkPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '6efe0fa8-36b2-4dd1-b049-427bffc7d369':
                        $payment_method = 'Efectivo';
                        if ($config['cashPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '4145b5f5-3bbc-45e3-8fc5-9cda970c62fb':
                        $payment_method = 'Transferencia bancaria';
                        if ($config['bankTransferPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '78e84000-9b5b-44a4-8367-da43df86ce34':
                        $payment_method = 'PayPal';
                        if ($config['paypalPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '6da98bb9-6df7-4c41-8608-5cdd7fde7d5d':
                        $payment_method = 'Tarjeta de crédito PayPal';
                        if ($config['creditCardPaypalPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '1dd098fa-5d63-4c8d-88b7-3c27ffbbb6ae':
                        // [NEW] Logic to patch method ID based on metadata
                        $this->pluginNotifierFacade->ensureStripePaymentAttribute($notification);

                        // Check if Method ID was updated in memory to OXXO or Transfer
                        $patchedMethodId = $notification->paymentData['methodId'];

                        if ($patchedMethodId === 'b01c0b35-b42c-48d9-9ad9-ea6591adfbbb') {
                            // It is OXXO Pay
                            $payment_method = 'OXXO Pay';
                            if ($config['oxxoPayPaymentMethodId'] ?? false) {
                                $this->notifierFacade->verifyPaymentActionToDo($notification);
                            }
                        } elseif ($patchedMethodId === '4145b5f5-3bbc-45e3-8fc5-9cda970c62fb') {
                            // It is Bank Transfer
                            $payment_method = 'Transferencia bancaria';
                            if ($config['bankTransferPaymentMethodId'] ?? false) {
                                $this->notifierFacade->verifyPaymentActionToDo($notification);
                            }
                        } else {
                            // Default: Credit Card Stripe
                            $payment_method = 'Tarjeta de crédito Stripe';
                            if ($config['creditCardStripePaymentMethodId'] ?? false) {
                                $this->notifierFacade->verifyPaymentActionToDo($notification);
                            }
                        }
                        break;
                    case 'b9e1e9d1-5c7b-41d2-b6b2-3e568d700290':
                        $payment_method = 'Suscripción de Stripe (tarjeta de crédito)';
                        if ($config['stripeSubscriptionCreditCardPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '939f7701-00b7-4676-9b1e-17afb268c8ba':
                        $payment_method = 'Suscripción de PayPal';
                        if ($config['paypalSubscriptionPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '1c963e35-df24-444d-95d2-12592d5107e8':
                        $payment_method = 'MercadoPago';
                        if ($config['mercadopagoPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case 'd8c1eae9-d41d-479f-aeaf-38497975d7b3':
                        $payment_method = 'Personalizado';
                        if ($config['customPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '72271b72-5c0a-45e2-94d1-cdf4d7cf10e2':
                        $payment_method = 'Cortesía';
                        if ($config['courtesyPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case 'b01c0b35-b42c-48d9-9ad9-ea6591adfbbb':
                        $payment_method = 'OXXO Pay';
                        if ($config['oxxoPayPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '4145b5f5-3bbc-45e3-8fc5-9cda970c62fb':
                        $payment_method = 'Transferencia bancaria';
                        if ($config['bankTransferPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    case '93814765-66a1-4c7d-a777-05c18fd6aab3':
                        $payment_method = 'Tarjeta de crédito/débito';
                        if ($config['creditDebitCardPaymentMethodId'] ?? false) {
                            $this->notifierFacade->verifyPaymentActionToDo($notification);
                        }
                        break;
                    default:
                        $payment_method = 'Desconocido';
                        break;
                }
            } else if ($notification->eventName === 'payment.delete' || $notification->eventName === 'payment.unmatch' || $notification->eventName === 'payment.edit') {
                $this->logger->info("Procesando evento " . $notification->eventName . " para client: " . ($notification->clientId ?? 'unknown'));
                if ($notification->clientId) {
                    $this->notifierFacade->verifyClientActionToDo($notification);
                }
            } else if ($notification->eventName === 'client.edit') {
                $this->logger->info('Procesando evento client.edit para entityId: ' . ($jsonData['entityId'] ?? 'unknown'));
                $this->logger->debug('Payload completo client.edit: ' . json_encode($jsonData));

                try {
                    $clientID = $jsonData['entityId'];
                    if (!$this->pluginNotifierFacade) {
                        $this->logger->error('Falla crítica: pluginNotifierFacade no está inicializado.');
                    } else {
                        $this->logger->info('Llamando a updatePasswordAntenaIfNeeded para cliente: ' . $clientID);
                        $this->pluginNotifierFacade->updatePasswordAntenaIfNeeded((int)$clientID, $jsonData);
                        // $this->lcdf4d7cf10e2ogger->info('Llamada finalizada exitosamente.');
                    }
                } catch (\Throwable $e) {
                    $this->logger->error('ERROR FATAL procesando client.edit: ' . $e->getMessage());
                    $this->logger->error('Trace: ' . $e->getTraceAsString());
                }

                //ejemplo de json_data: {"uuid":"17e043a7-03b5-4312-ab81-a7818124a77e","changeType":"edit","entity":"client","entityId":"158","eventName":"client.edit","extraData":{"entity":{"id":158,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"23 San Luis","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37804","fullAddress":"San Luis 23, Guadalupe, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-01-06T00:00:00-0600","leadConvertedAt":"2025-02-09T03:15:49-0600","companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Luis","lastName":"Guti\u00e9rrez","username":null,"contacts":[{"id":162,"clientId":158,"email":null,"phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#2196f3","addressGpsLat":21.153272,"addressGpsLon":-100.9134508,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"entityBeforeEdit":{"id":158,"userIdent":null,"previousIsp":null,"isLead":true,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"23 San Luis","street2":null,"city":"Dolores Hidalgo Cuna de la Independencia Nacional","countryId":173,"stateId":null,"zipCode":"37804","fullAddress":"San Luis 23, Guadalupe, Dolores Hidalgo Cuna de la Independencia Nacional, Gto., M\u00e9xico","invoiceStreet1":null,"invoiceStreet2":null,"invoiceCity":null,"invoiceStateId":null,"invoiceCountryId":null,"invoiceZipCode":null,"invoiceAddressSameAsContact":true,"note":null,"sendInvoiceByPost":null,"invoiceMaturityDays":null,"stopServiceDue":null,"stopServiceDueDays":null,"organizationId":1,"tax1Id":null,"tax2Id":null,"tax3Id":null,"registrationDate":"2025-01-06T00:00:00-0600","leadConvertedAt":null,"companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Luis","lastName":"Guti\u00e9rrez","username":null,"contacts":[{"id":162,"clientId":158,"email":null,"phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[],"invitationEmailSentDate":null,"avatarColor":"#2196f3","addressGpsLat":21.153272,"addressGpsLon":-100.9134508,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":false,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false}}}

                $entity = $notification->clientData ?? null;
                if ($entity) {
                    $entityBeforeEdit = $jsonData['extraData']['entityBeforeEdit'] ?? null;

                    if (isset($entity['isLead'])) {
                        $isLeadBefore = $entityBeforeEdit['isLead'] ?? null;
                        $isLeadAfter  = $entity['isLead'];

                        if ($isLeadBefore === true && $isLeadAfter === false) {
                            $this->logger->info("El cliente $clientID cambió de potencial a cliente. Iniciando creación automática en Stripe...");
                            $this->pluginNotifierFacade->createStripeClient($notification, 'CREAR CLIENTE STRIPE', false);
                        }
                    }

                    $tags       = $entity['tags'] ?? [];
                    $tagsBefore = $entityBeforeEdit['tags'] ?? [];

                    $clabeTagExistsBefore = false;
                    $stripeTagExistsBefore = false;
                    $passwordAntenaTagExistsBefore = false;

                    $clabeTagExists = false;
                    $stripeTagExists = false;
                    $passwordAntenaTagExists = false;

                    foreach ($tagsBefore as $tag) {
                        if (($tag['name'] ?? '') === 'CREAR CLABE STRIPE') $clabeTagExistsBefore = true;
                        if (($tag['name'] ?? '') === 'CREAR CLIENTE STRIPE') $stripeTagExistsBefore = true;
                        if (($tag['name'] ?? '') === 'OBTENER PASSWORD ANTENA') $passwordAntenaTagExistsBefore = true;
                    }

                    foreach ($tags as $tag) {
                        if (($tag['name'] ?? '') === 'CREAR CLABE STRIPE') $clabeTagExists = true;
                        if (($tag['name'] ?? '') === 'CREAR CLIENTE STRIPE') $stripeTagExists = true;
                        if (($tag['name'] ?? '') === 'OBTENER PASSWORD ANTENA') $passwordAntenaTagExists = true;
                    }

                    if ($clabeTagExists && !$clabeTagExistsBefore) {
                        $this->logger->debug('La etiqueta CREAR CLABE STRIPE se agregó al cliente o está presente');
                        $this->pluginNotifierFacade->createStripeClient($notification, 'CREAR CLABE STRIPE', true);
                    }

                    if ($stripeTagExists && !$stripeTagExistsBefore) {
                        $this->logger->debug('La etiqueta CREAR CLIENTE STRIPE se agregó al cliente o está presente');
                        $this->pluginNotifierFacade->createStripeClient($notification, 'CREAR CLIENTE STRIPE', false);
                    }

                    if ($passwordAntenaTagExists && !$passwordAntenaTagExistsBefore) {
                        $this->logger->debug('La etiqueta OBTENER PASSWORD ANTENA se agregó al cliente o está presente');
                        $this->pluginNotifierFacade->processClientPasswordAntenna((int)$clientID, $entity);
                    }

                    // Automatización: Sincronizar cambios de Nombre o Email con Stripe
                    if ($entityBeforeEdit) {
                        $nameBefore = trim(($entityBeforeEdit['firstName'] ?? '') . ' ' . ($entityBeforeEdit['lastName'] ?? ''));
                        if (empty($nameBefore)) $nameBefore = $entityBeforeEdit['companyName'] ?? '';

                        $nameAfter = trim(($entity['firstName'] ?? '') . ' ' . ($entity['lastName'] ?? ''));
                        if (empty($nameAfter)) $nameAfter = $entity['companyName'] ?? '';

                        $emailBefore = null;
                        foreach ($entityBeforeEdit['contacts'] ?? [] as $contact) {
                            if ($contact['isBilling'] || $contact['isContact']) {
                                $emailBefore = $contact['email'] ?? null;
                                if ($emailBefore) break;
                            }
                        }

                        $emailAfter = null;
                        foreach ($entity['contacts'] ?? [] as $contact) {
                            if ($contact['isBilling'] || $contact['isContact']) {
                                $emailAfter = $contact['email'] ?? null;
                                if ($emailAfter) break;
                            }
                        }

                        if ($nameBefore !== $nameAfter || $emailBefore !== $emailAfter) {
                            $this->logger->info("Detectado cambio en datos básicos del cliente $clientID. Sincronizando con Stripe...");
                            $this->pluginNotifierFacade->syncStripeCustomerData((int)$clientID, $nameAfter, $emailAfter);
                        }
                    }
                } else {
                    $this->logger->warning('Los datos del cliente no pudieron recuperarse en clientData');
                }

                try {
                    $this->logger->info("Refrescando datos del cliente $clientID desde UCRM antes de sincronizar con CallBell...");
                    $refreshedClientData = $this->ucrmApi->get("clients/$clientID");
                    if ($refreshedClientData) {
                        $notification->clientData = $refreshedClientData;
                    }
                } catch (\Exception $e) {
                    $this->logger->warning("No se pudieron refrescar los datos del cliente $clientID para CallBell: " . $e->getMessage());
                }

                $this->notifierFacade->verifyClientActionToDo($notification);
            } else if ($notification->eventName === 'client.add') {
                $this->logger->debug('Se agregó un nuevo cliente');
                $this->logger->debug('Valor de json_data: ' . json_encode($jsonData));
            } else if ($notification->eventName === 'service.edit') {
                $this->logger->debug('Se editó el servicio a un  cliente' . PHP_EOL);
                $this->notifierFacade->verifyServiceActionToDo($notification);
                //ejemplo de json_data: {"uuid":"06d281ca-d78e-4f0a-a282-3a6b77d25da0","changeType":"edit","entity":"service","entityId":"155","eventName":"service.edit","extraData":{"entity":{"id":155,"prepaid":false,"clientId":171,"status":1,"name":"Basico 300","fullAddress":"Campeche 56, Dolores Hidalgo, 37800","street1":"Campeche 56","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1572461,"addressGpsLon":-100.9377137,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2025-05-21T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2025-05-21T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"359cb58d-e64f-453a-890e-23d5abb4f116","attributes":[],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]},"entityBeforeEdit":{"id":155,"prepaid":false,"clientId":171,"status":1,"name":"Basico 300","fullAddress":"Campeche 56, Dolores Hidalgo, 37800","street1":"Campeche 56","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","note":null,"addressGpsLat":21.1572461,"addressGpsLon":-100.9377137,"servicePlanId":6,"servicePlanPeriodId":26,"price":300,"hasIndividualPrice":false,"totalPrice":300,"currencyCode":"MXN","invoiceLabel":null,"contractId":null,"contractLengthType":1,"minimumContractLengthMonths":null,"activeFrom":"2025-05-21T00:00:00-0600","activeTo":null,"contractEndDate":null,"discountType":0,"discountValue":null,"discountInvoiceLabel":"Descuento","discountFrom":null,"discountTo":null,"tax1Id":null,"tax2Id":null,"tax3Id":null,"invoicingStart":"2025-05-21T00:00:00-0600","invoicingPeriodType":1,"invoicingPeriodStartDay":1,"nextInvoicingDayAdjustment":10,"invoicingProratedSeparately":true,"invoicingSeparately":false,"sendEmailsAutomatically":null,"useCreditAutomatically":true,"servicePlanName":"Basico 300","servicePlanPrice":300,"servicePlanPeriod":1,"servicePlanType":"Internet","downloadSpeed":8,"uploadSpeed":8,"hasOutage":false,"unmsClientSiteStatus":null,"fccBlockId":null,"lastInvoicedDate":null,"unmsClientSiteId":"359cb58d-e64f-453a-890e-23d5abb4f116","attributes":[],"addressData":null,"suspensionReasonId":null,"serviceChangeRequestId":null,"setupFeePrice":null,"earlyTerminationFeePrice":null,"downloadSpeedOverride":null,"uploadSpeedOverride":null,"trafficShapingOverrideEnd":null,"trafficShapingOverrideEnabled":false,"servicePlanGroupId":null,"suspensionPeriods":[],"surcharges":[]}}}
                $clientID = $jsonData['extraData']['entity']['clientId'] ?? $notification->clientId ?? null;
                if ($clientID) {
                    $this->pluginNotifierFacade->updatePasswordAntenaIfNeeded((int)$clientID, $jsonData);
                } else {
                    $this->logger->warning('No se pudo resolver el ID de cliente en service.edit para updatePasswordAntenaIfNeeded');
                }
            } else if ($notification->eventName === 'service.suspend') {
                $this->logger->debug('Se suspendió el servicio a un  cliente' . PHP_EOL);
                $this->notifierFacade->verifyServiceActionToDo($notification);
            } else if ($notification->eventName === 'service.suspend_cancel') {
                $this->logger->debug('Se reactivó el servicio a un  cliente' . PHP_EOL);
                $this->notifierFacade->verifyServiceActionToDo($notification);
            } else if ($notification->eventName === 'service.postpone') {
                $this->logger->debug('Se pospuso la suspención del servicio a un  cliente' . PHP_EOL);
                $this->notifierFacade->verifyServiceActionToDo($notification);
            } else if ($notification->eventName === 'invoice.near_due') {
                $this->logger->debug('Factura casi por vencer' . PHP_EOL);
                $this->notifierFacade->notifyOverDue($notification);
            } else if ($notification->eventName === 'invoice.overdue') {
                $this->logger->debug('Factura vencida' . PHP_EOL);
                $result = json_encode($notification);
                $this->logger->debug('datos del notification para el invoice overdue:' . $result . PHP_EOL);
                $this->notifierFacade->notifyOverDue($notification);
            } else if ($notification->eventName === 'invoice.add') {
                $this->logger->debug('Adición de Factura' . PHP_EOL);
                $result = json_encode($notification);
                $this->logger->debug('datos del notification para el invoice add:' . $result . PHP_EOL);

                $accountBalance = $notification->clientData['accountBalance'];
                //$invoiceAmountPaid = $notification->invoiceData['amountPaid'];
                $this->logger->debug("Account Balance: " . $accountBalance . PHP_EOL);
                // $this->logger->debug("Pago hecho con la factura: " . $invoiceAmountPaid . PHP_EOL);
                $this->notifierFacade->verifyInvoiceActionToDo($notification);
            } else if ($notification->eventName === 'invoice.edit') {
                $this->logger->debug('Edición de Factura' . PHP_EOL);
                $this->notifierFacade->verifyInvoiceActionToDo($notification);
            } else if ($notification->eventName === 'invoice.add_draft') {
                $this->logger->debug('Adición de borrador de Factura' . PHP_EOL);
                $this->notifierFacade->verifyInvoiceActionToDo($notification);
            } else if ($notification->eventName === 'invoice.draft_approved') {
                $this->logger->debug('Aprobación de Factura' . PHP_EOL);
                $this->notifierFacade->verifyInvoiceActionToDo($notification);
            } else if ($notification->eventName === 'invoice.delete') {
                $this->logger->debug('Eliminación de Factura' . PHP_EOL);
                $this->notifierFacade->verifyInvoiceActionToDo($notification);
            } else if ($notification->eventName === 'job.add') {
                $this->logger->debug('Se ha agregado un nuevo trabajo');
                $title         = $jsonData['extraData']['entity']['title'] ?? '';
                $title         = '[NOTIFICACION-PENDIENTE]' . $title;
                $responsePatch = $this->ucrmApi->patch('scheduling/jobs/' . $jsonData['entityId'], [
                    'title' => $title,
                ]);
                $this->logger->debug('Respuesta de la API al agregar el trabajo: ' . json_encode($responsePatch));
            } else if ($notification->eventName === 'job.edit') {
                $this->logger->debug('Se actualiza un trabajo' . PHP_EOL);
                // $this->logger->debug('Valor de json_data: ' . json_encode($jsonData));

                // Validar que 'extraData' existe y contiene las claves necesarias
                if (
                    isset($jsonData['extraData']['entityBeforeEdit']) &&
                    isset($jsonData['extraData']['entity'])
                ) {
                    $entityBeforeEdit = $jsonData['extraData']['entityBeforeEdit'];
                    $entity           = $jsonData['extraData']['entity'];

                    $this->logger->debug('Validando claves dentro de entityBeforeEdit y entity');

                    // Validar que 'assignedUserId' existe en ambas entidades
                    if (array_key_exists('assignedUserId', $entityBeforeEdit) && array_key_exists('assignedUserId', $entity)) {
                        // $this->logger->debug('Los datos entityBeforeEdit y entity contienen el campo assignedUserId');

                        $assignedUserIdBefore = $entityBeforeEdit['assignedUserId'];
                        $assignedUserIdAfter  = $entity['assignedUserId'];
                        $dateBefore           = $entityBeforeEdit['date'];
                        $dateAfter            = $entity['date'];
                        $statusBefore         = $entityBeforeEdit['status'];
                        $statusAfter          = $entity['status'];
                        $title                = $entityBeforeEdit['title'];
                        $pendingPrefix        = '[NOTIFICACION-PENDIENTE]'; // Prefijo para trabajos pendientes de notificación
                        $currentTitle         = $entity['title'] ?? '';     // Obtener el título actual

                        //Valores de status y su significado: 0 = abierto, 1= En curso, 2 = Cerrado

                        if ($statusAfter == 1) {
                            $isNewActivation = ($statusBefore == 0 && $statusAfter == 1);
                            $isTechChange = ($assignedUserIdBefore != null && $assignedUserIdAfter != $assignedUserIdBefore && $dateBefore === $dateAfter);
                            $isReprogramming = ($assignedUserIdBefore != null && $assignedUserIdBefore === $assignedUserIdAfter && $dateBefore != $dateAfter);
                            $isBothChange = ($assignedUserIdBefore != null && $assignedUserIdAfter != $assignedUserIdBefore && $dateBefore != $dateAfter);
                            $isDeassignment = ($assignedUserIdBefore != null && $assignedUserIdAfter === null);

                            if ($isNewActivation) {
                                $this->logger->debug('Trabajo iniciado o asignado: Notificando...');
                                $this->notifierFacade->verifyJobActionToDo($jsonData, false, false);
                            } else if ($isTechChange) {
                                $this->logger->debug('Cambio de técnico sin reprogramación');
                                $this->notifierFacade->verifyJobActionToDo($jsonData, false, true);
                            } else if ($isReprogramming) {
                                $this->logger->debug('Reprogramación sin cambio de técnico');
                                $this->notifierFacade->verifyJobActionToDo($jsonData, true, false);
                            } else if ($isBothChange) {
                                $this->logger->debug('Reprogramación y cambio de técnico');
                                $this->notifierFacade->verifyJobActionToDo($jsonData, true, true);
                            } else if ($isDeassignment) {
                                $this->logger->debug('Técnico desasignado');
                                $this->notifierFacade->verifyJobActionToDo($jsonData, null, true);
                            } else {
                                $this->logger->debug('Edición de trabajo "En curso" sin cambios de fecha o técnico relevantes para notificación');
                            }
                        }
                    } else {
                        $this->logger->warning('El campo assignedUserId no existe en entityBeforeEdit o entity');
                    }
                } else {
                    $this->logger->warning('Los datos entityBeforeEdit o entity no están presentes en extraData');
                }
            }

            //$this->notifierFacade->update($notification);
        } catch (TwilioException $exception) {
            $this->logger->error($exception->getMessage());
        } catch (\Exception $ex) {
            $this->logger->error($ex->getMessage());
            $this->logger->info($ex->getTraceAsString());
        }
    }
}
