<?php

declare(strict_types=1);

namespace SmsNotifier\Facade;

use Attribute;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use SmsNotifier\Data\NotificationData;
use SmsNotifier\Factory\MessageTextFactory;
use SmsNotifier\Service\Logger;
use SmsNotifier\Service\SmsNumberProvider;
use GuzzleHttp\Client;
use Ubnt\UcrmPluginSdk\Service\UcrmApi;


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

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

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

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

    protected $stripeCustomAttributeID;
    protected $clabeInterbancariaBanamexID;

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

    /*
     * Creates a PaymentIntent in Stripe for a Customer
     */
    public function createPaymentIntent($event_json)
    {
        $this->logger->info("Iniciando creación de PaymentIntent en Stripe." . PHP_EOL);

        $configManager = \Ubnt\UcrmPluginSdk\Service\PluginConfigManager::create();
        $config = $configManager->loadConfig();
        $StripeToken = $config['tokenstripe'];
        $idPaymentAdmin = $config['idPaymentAdminCRM']; //ID del administrador que crea el PaymentIntent
        $stripe = new \Stripe\StripeClient($StripeToken); //Token de clave privada para la API de Stripe

        // Asegurarse de que 'customer' esté presente en la estructura del evento
        if (!isset($event_json['data']['object']['customer'])) {
            $this->logger->info("Error: Invalid event structure. Customer ID not found." . PHP_EOL);
            return;
        }

        $customerId = $event_json['data']['object']['customer'];
        if (is_null($customerId)) {
            $this->logger->info("Error: Customer ID is null." . PHP_EOL);
            return;
        }

        // Validar que net_amount está presente
        if (!isset($event_json['data']['object']['net_amount'])) {
            $this->logger->info("Error: net_amount not found in event data." . PHP_EOL);
            return;
        }
        
        $amount = $event_json['data']['object']['net_amount'];
        //convertir en positivo
        if ($event_json['data']['object']['net_amount'] < 0) {
            $this->logger->warning("Error: net_amount es negativo." . PHP_EOL);
            return;

        }


        //imprimir la cantidad del PaymentIntent
        $this->logger->info("Cantidad del PaymentIntent: " . $amount . PHP_EOL);

        try {
            // Obtener información del cliente desde Stripe
            $stripeQuery = $stripe->customers->retrieve($customerId, []);
            $UCRM_clientID = $stripeQuery['metadata']['ucrm_client_id']; // ID del cliente en Ubiquiti UISP

            // Obtener información del administrador actual
            $this->ucrmApi = UcrmApi::create();
            $currentUserAdmin = $this->ucrmApi->get('users/admins', []);

            // Crear PaymentIntent
            $paymentIntent = $stripe->paymentIntents->create([
                'amount' => $amount,
                'currency' => 'mxn',
                'customer' => $customerId,
                'payment_method_types' => ['customer_balance'],
                'payment_method_data' => ['type' => 'customer_balance'],
                'confirm' => true,
                'payment_method_options' => [
                    'customer_balance' => [
                        'funding_type' => 'bank_transfer',
                        'bank_transfer' => ['type' => 'mx_bank_transfer']
                    ],
                ],
                'metadata' => [
                    'clientId' => $UCRM_clientID, // ID del cliente en Ubiquiti
                    'createdBy' => 'UCRM',
                    'paymentType' => 'card.one_time',
                    'signedInAdminId' => $idPaymentAdmin, // ID del administrador que crea el PaymentIntent
                    'tipoPago' => 'Transferencia Bancaria'
                ],
            ]);

            $this->logger->info("PaymentIntent creado: " . $paymentIntent->id . PHP_EOL);

        } catch (\Stripe\Exception\ApiErrorException $e) {
            $this->logger->info("Error creando PaymentIntent: " . $e->getMessage() . PHP_EOL);
        }
    }


    /*
     * Creates the Stripe Customer
     */
    public function createStripeClient(NotificationData $notificationData, $tagStripe = false): void
    {
        $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'];
        $StripeToken = $config['tokenstripe'];
        $baseUri = 'https://' . $IPServer . '/crm/api/v1.0/'; //endpoint  de la API REST del CRM
        $this->ucrmApi = UcrmApi::create();

        $stripe = new \Stripe\StripeClient($StripeToken); //Token de clave privada en modo prueba para la API de Stripe
        //$stripe = new \Stripe\StripeClient('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'); //Token de clave privada en modo prodcucción para la API de Stripe

        //valor de $notificationData en json
        $this->logger->info("Valor de notificationData: " . json_encode($notificationData) . PHP_EOL);

        //ejemplo de notificationData: {"uuid":"0be6fee6-db1d-4ab5-a52c-2ee87b04315e","changeType":"edit","entity":"client","entityId":170,"message":null,"clientId":170,"eventName":"client.edit","clientData":{"id":170,"userIdent":null,"previousIsp":null,"isLead":false,"clientType":1,"companyName":null,"companyRegistrationNumber":null,"companyTaxId":null,"companyWebsite":null,"street1":"San Luis 34","street2":null,"city":"Dolores Hidalgo","countryId":173,"stateId":null,"zipCode":"37800","fullAddress":"San Luis 34, Dolores Hidalgo, 37800","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-03-24T00:00:00-0600","leadConvertedAt":"2025-03-24T15:01:22-0600","companyContactFirstName":null,"companyContactLastName":null,"isActive":false,"firstName":"Charicuas","lastName":"Quinero","username":null,"contacts":[{"id":176,"clientId":170,"email":null,"phone":null,"name":null,"isBilling":true,"isContact":true,"types":[{"id":1,"name":"Billing"},{"id":2,"name":"General"}]}],"attributes":[{"id":192,"clientId":170,"customAttributeId":10,"name":"Stripe Customer ID","key":"stripeCustomerId","value":"cus_S0T9BJ4dO0p0A3","clientZoneVisible":true},{"id":193,"clientId":170,"customAttributeId":11,"name":"Clabe Interbancaria","key":"clabeInterbancaria","value":"124180302040274015","clientZoneVisible":true}],"accountBalance":0,"accountCredit":0,"accountOutstanding":0,"currencyCode":"MXN","organizationName":"SIIP Pruebas","bankAccounts":[],"tags":[{"id":5,"name":"CREARCLABESTRIPE","colorBackground":"#e30000","colorText":"#fff"}],"invitationEmailSentDate":null,"avatarColor":"#ef5350","addressGpsLat":22.00854045,"addressGpsLon":-99.0272544,"isArchived":false,"generateProformaInvoices":null,"usesProforma":false,"hasOverdueInvoice":false,"hasOutage":false,"hasSuspendedService":false,"hasServiceWithoutDevices":true,"referral":null,"hasPaymentSubscription":false,"hasAutopayCreditCard":false},"serviceData":null,"invoiceData":null,"paymentData":null}

        //obtener el id del cliente
        $clientId = $notificationData->clientData['id'];

        //si en attributes del cliente encuentra el custom field de Stripe Customer ID entonces no se vuelve a crear el cliente en Stripe
        $attributes = $notificationData->clientData['attributes'];
        $this->logger->info("Valor de attributes: " . json_encode($attributes) . PHP_EOL);
        $stripeCustomerId = null;
        foreach ($attributes as $attribute) {
            if ($attribute['key'] === 'stripeCustomerId') {
                $stripeCustomerId = $attribute['value'];
                break;
            }
        }

        $customAttributes = $this->ucrmApi->get('custom-attributes/', ['attributeType' => 'client']);//Obtener los atributos del sistema que estén vinculados a la entidad "cliente"
        //$this->logger->info("result del custom Attributes: " . json_encode($customAttributes) . PHP_EOL);


        // Verificar si se obtuvieron los atributos
        if ($customAttributes && is_array($customAttributes)) {
            foreach ($customAttributes as $attribute) {
                // Verificar si 'name' contiene la palabra 'Stripe' sin distinguir mayúsculas y minúsculas
                if (isset($attribute['name']) && stripos($attribute['name'], 'Stripe') !== false) {
                    $this->logger->info("ID correspondiente a 'Customer Stripe ID': " . $attribute['id'] . PHP_EOL);
                    $this->stripeCustomAttributeID = $attribute['id'];
                } else if (isset($attribute['name']) && stripos($attribute['name'], 'Clabe') !== false) {
                    //$this->logger->info("ID correspondiente a 'Clabe Interbancaria Banamex': " . $attribute['id'] .PHP_EOL);
                    $this->clabeInterbancariaBanamexID = $attribute['id'];
                }


            }
        } else {
            $this->logger->info("Error al obtener los atributos personalizados." . PHP_EOL);
        }

        if ($stripeCustomerId) {
            $this->logger->info("El cliente ya tiene un Stripe Customer ID: " . $stripeCustomerId . PHP_EOL);
            if ($tagStripe) {
                $tagsIds = $this->ucrmApi->get('client-tags', []);
                //ejemplo de respuesta $tagsIds: [{"id":4,"name":"EQUIPO A CREDITO","colorBackground":"#fed74a","colorText":"#444"},{"id":5,"name":"CREARCLABESTRIPE","colorBackground":"#e30000","colorText":"#fff"}]

                //obtener el ID de la etiqueta o tag llamada "CREAR CLABE STRIPE" y asiganarla a una variable $tagCrearClabeStripe basandose en el ejemplo de respuesta anterior
                $tagCrearClabeStripe = null;
                foreach ($tagsIds as $tag) {
                    if ($tag['name'] === 'CREAR CLABE STRIPE') {
                        $tagCrearClabeStripe = $tag['id'];
                        // $this->logger->info("ID de la etiqueta 'CREAR CLABE STRIPE': " . $tagCrearClabeStripe . PHP_EOL);
                        break;
                    }
                }
                if (!$tagCrearClabeStripe) {
                    $this->logger->info("No se encontró la etiqueta 'CREAR CLABE STRIPE'." . PHP_EOL);
                    return;
                }

                $this->ucrmApi->patch("clients/$clientId/remove-tag/" . $tagCrearClabeStripe);
                $this->logger->info("Se eliminó la etiqueta 'CREAR CLABE STRIPE' del cliente." . PHP_EOL);

            }
            return;
        }

        //$this->logger->info("Ya dentro del metodo Create Stripe Client " . PHP_EOL);
        //$this->sendWhatsApp('Hola Dany');


        if ($tagStripe) {
            $tagsIds = $this->ucrmApi->get('client-tags', []);
            //ejemplo de respuesta $tagsIds: [{"id":4,"name":"EQUIPO A CREDITO","colorBackground":"#fed74a","colorText":"#444"},{"id":5,"name":"CREARCLABESTRIPE","colorBackground":"#e30000","colorText":"#fff"}]

            //obtener el ID de la etiqueta o tag llamada "CREARCLABESTRIPE" y asiganarla a una variable $tagCrearClabeStripe basandose en el ejemplo de respuesta anterior
            $tagCrearClabeStripe = null;
            foreach ($tagsIds as $tag) { //revisamos los tags del cliente y si encuentra el tag de "CREARCLABESTRIPE" entonces lo asigna a la variable $tagCrearClabeStripe el valor de id
                if ($tag['name'] === 'CREAR CLABE STRIPE') {
                    $tagCrearClabeStripe = $tag['id'];
                    // $this->logger->info("ID de la etiqueta 'CREAR CLABE STRIPE': " . $tagCrearClabeStripe . PHP_EOL);
                    break;
                }
            }
            if (!$tagCrearClabeStripe) {
                $this->logger->info("No se encontró la etiqueta 'CREAR CLABE STRIPE'." . PHP_EOL);
                return;
            }
            $this->createCustomerStripe($notificationData, $stripe, $baseUri, $UCRMAPIToken);
            $this->ucrmApi->patch("clients/$clientId/remove-tag/" . $tagCrearClabeStripe);
            $this->logger->info("Se eliminó la etiqueta 'CREAR CLABE STRIPE' del cliente." . PHP_EOL);
            return;
        }






        // Verificar si la solicitud fue exitosa (código de estado 200)
        //https://172.16.5.120/crm/api/v1.0/payments?limit=1&clientId=1992&order=createdDate&direction=DESC

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

        // Asegúrate de trabajar con un objeto PHP
        $dataObject = json_decode(json_encode($notification_client_data)); // Convertir a JSON y luego decodificar como objeto

        if (!is_object($dataObject)) {
            $this->logger->info("Error: Los datos del cliente no pudieron ser procesados." . PHP_EOL);
            return;
        }

        $this->createCustomerStripe($notificationData, $stripe, $baseUri, $UCRMAPIToken);
    }

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


    function createCustomerStripe($notificationData, $stripe, $baseUri, $token): bool
    {
        $this->ucrmApi = UcrmApi::create();
        $this->logger->info("Creando el Customer Stripe" . PHP_EOL);



        $ucrm_client_id = $notificationData->clientData['id'];
        $clientCRMContacts = $notificationData->clientData['contacts'];

        $firstName = $notificationData->clientData['firstName']; //obtenemos nombre del cliente y lo almacenamos en una variable
        $lastName = $notificationData->clientData['lastName']; //obtenemos apellidos del cliente y lo almacenamos en una variable
        $this->logger->info('El cliente a procesar es : ' . $firstName . ' ' . $lastName . PHP_EOL); //impresión de control para ver el nombre del cliente a procesar en consola

        $cadenaNotificationData = json_encode($notificationData);
        $this->logger->info("Datos notificationData: " . $cadenaNotificationData . PHP_EOL);
        foreach ($clientCRMContacts as $contact) { //aquí revisamos los datos de contacto del cliente, como pueden ser uno o varios se hace uso del foreach
            $this->logger->info('Ya dentro del FOREACH!!! ' . PHP_EOL);

            $phone = ''; //variable para almacenar el número de teléfono del cliente que se mandará a su cuenta de Stripe

            foreach ($contact['types'] as $type) { //revisamos el tipo de contacto

                $this->logger->info('REVISANDO EL PRIMER CONTACTO!!! ' . PHP_EOL);
                if ($type['name'] === "WhatsApp") { //si es de tipo whatsapp..
                    //print_r("Encontré un tipo de Contacto para WhatsAapp" . PHP_EOL);
                    $phone = $contact['phone']; //se asigna como número de teléfono
                    break;
                } else {
                    $phone = $contact['phone']; //Si no encuentra un tipo de contacto como Whatsapp entonces el último número de celular obtenido es el que se envía
                }
            }
            $email = $this->validarEmail($contact['email']); //validamos el email del cliente mediante la función validarEmail para que en caso de que no esté bien formado lo ponga en blanco



        }

        $this->logger->info('ahora se procede a validar el teléfono!!! ' . PHP_EOL);

        //si la variable $phone no esta vacia o null se valida con la funcion validarNumeroTelefono
        if ($phone == '') {
            $this->logger->info('El número de teléfono está vacío o no es válido.' . PHP_EOL);
            //se manda a crear pero sin numero de teléfono
            $this->logger->info('AHORA SE MANDA A CREAR EL CLIENTE A STRIPE!!! ' . PHP_EOL);
            $result = $stripe->customers->create([
                "description" => "Cliente SIIP CRM con client_id: " . $ucrm_client_id,
                "name" => $firstName . ' ' . $lastName,
                "email" => $email,
                'preferred_locales' => ['es-419']
            ]); //aquí se contruye la petición de creación de un customer en Stripe y se consume la API

        } else {
            $phone = $this->validarNumeroTelefono($phone); //validamos y procesamos el número de celular del cliente para que se vaya a 10 dígitos ya que Stripe por si mismo les agrega el +52
            $this->logger->info('AHORA SE MANDA A CREAR EL CLIENTE A STRIPE!!! ' . PHP_EOL);
            $result = $stripe->customers->create([
                "description" => "Cliente SIIP CRM con client_id: " . $ucrm_client_id,
                "name" => $firstName . ' ' . $lastName,
                "phone" => $phone,
                "email" => $email,
                'preferred_locales' => ['es-419']
            ]); //aquí se contruye la petición de creación de un customer en Stripe y se consume la API

        }

        $this->logger->info(json_encode($result) . PHP_EOL); //imprimir respuesta de creación del cliente
        //ejemplo de respuesta de stripe cuando se crea el cliente: {"id":"cus_Rkh9CoRTpjlZUu","object":"customer","address":null,"balance":0,"created":1739250682,"currency":null,"default_source":null,"delinquent":false,"description":"Cliente SIIP CRM con client_id: 167","discount":null,"email":null,"invoice_prefix":"5017E9D3","invoice_settings":{"custom_fields":null,"default_payment_method":null,"footer":null,"rendering_options":null},"livemode":false,"metadata":[],"name":"Javier Alatorre","next_invoice_sequence":1,"phone":"4181878106","preferred_locales":["es-419"],"shipping":null,"tax_exempt":"none","test_clock":null}

        //validar si se creo el cliente con la API de Stripe $stripe->customers->create
        if (!isset($result['id'])) { //si no existe el ID del cliente en la respuesta de Stripe entonces se manda un mensaje de error
            $this->logger->info('Error al crear el cliente en Stripe: ' . json_encode($result) . PHP_EOL);

        }



        $stripe_customer_id = $result['id']; //obtenemos el customer id de Stripe recibido por medio del consumo del API y lo asignamos a una variable $stripe_customer_id
        sleep(2);
        $result2 = $stripe->customers->update(
            $stripe_customer_id,
            ['metadata' => ['ucrm_client_id' => '' . $ucrm_client_id]]
        );//aquí se contruye la petición de actualización de un customer en Stripe para agregarle los metadatos y se consume la API, requiere el ID del Customer, por eso antes lo almacenamos en la variable $stripe_customer_id

        $this->logger->info(json_encode($result2) . PHP_EOL); // imprimir respuesta de actualización del metadata del cliente
        sleep(2);
        $result3 = $stripe->customers->createFundingInstructions(
            $stripe_customer_id,
            [
                'currency' => 'mxn',
                'funding_type' => 'bank_transfer',
                'bank_transfer' => ['type' => 'mx_bank_transfer'],
            ]
        ); //aquí se contruye la petición de creación de Instrucciones de Fondeo de un customer en Stripe (O su metodo de pago como cuenta bancaria para transferencias) y se consume la API

        $this->logger->info(json_encode($result3) . PHP_EOL);  //imprimir respuesta de asignación de cuenta bancaria de transferencia

        // Acceder al valor de "clabe" para BANORTE
        $clabeInterbancaria = $result3['bank_transfer']['financial_addresses'][0]['spei']['clabe']; //Asignamos la clabe obtenida con la API de Stripe con la solicitud anterior a la variable $clabe 
        $stripeID = $this->stripeCustomAttributeID;
        $clabeInterbancariaID = $this->clabeInterbancariaBanamexID;

        $customer = $stripe->customers->update(
            $stripe_customer_id,
            [
                'metadata' => [
                    'clabe' => $clabeInterbancaria, // Nueva clabe
                ],
            ]
        );

        $this->logger->info("CLABE guardada en metadata: " . $customer->metadata->clabe . PHP_EOL);


        $json_data_patch = '{
                                        "attributes": [
                                          {
                                            "value": "' . $stripe_customer_id . '",
                                            "customAttributeId":' . $stripeID . '
                                          },
                                          {
                                            "value": "' . $clabeInterbancaria . '",
                                            "customAttributeId":' . $clabeInterbancariaID . '
                                          }
                                        ]
    
                                      }'; //JSON para hacer patch de los custom fields del cliente en el UISCP CRM, Campo para el Stripe Customer ID y la Clabe interbancaria

        //valor de $json_data_patch en json
        //$this->logger->info("Valor de json_data_patch: " . $json_data_patch . PHP_EOL);
        // try{
        //     $responsepatchCRM= $this->ucrmApi->patch("clients/$ucrm_client_id", [
        //         "attributes" => [
        //             [
        //                 "value" => $stripe_customer_id,
        //                 "customAttributeId" => $stripeID
        //             ],
        //             [
        //                 "value" => $clabeInterbancaria,
        //                 "customAttributeId" => $clabeInterbancariaID
        //             ]
        //         ]
        //     ]); //aquí se contruye la petición para hacer patch hacia el cliente en sus custom fields con la API del UISP UCRM
        //     $this->logger->info("Se actualizó el cliente en UCRM con el Stripe Customer ID y la Clabe Interbancaria." . PHP_EOL);
        //     $this->logger->info(json_encode($responsepatchCRM) . PHP_EOL); //imprimir respuesta del patch de CRM con la clabe y Customer ID Stripe
        // }catch (GuzzleException $e) {
        //     $this->logger->info("Error al hacer el patch al cliente en UCRM: " . $e->getMessage() . PHP_EOL);
        //     return false; // Return false if patch fails
        // }


        $clientguzz = new Client(); //instancia de cliente GuzzleHttp para consumir API UISP 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($baseUri . 'clients/' . $ucrm_client_id, [
                'json' => json_decode($json_data_patch, true),
                'headers' => [
                    'X-Auth-App-Key' => $token, // Cambia el nombre de la cabecera de autorización
                    'Accept' => 'application/json', // Indica que esperamos una respuesta en formato JSON
                ],
                'verify' => false,
            ]);


        } catch (GuzzleException $error) {
            $this->logger->info("Error al hacer el patch al CRM: " . $error->getMessage() . PHP_EOL);
            return false; // Return false if patch fails
        }
        $this->logger->info(json_encode($responseCRM) . PHP_EOL); //imprimir respuesta del patch de CRM con la clabe y Customer ID Stripe

        return true; // Return true if all operations succeed
    }

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

        // Eliminar caracteres no numéricos
        $telefono = preg_replace('/\D/', '', $telefono);

        // Verificar si quedan exactamente 10 dígitos
        if (strlen($telefono) === 10) {
            // Retornar el número de teléfono correctamente formateado
            return $telefono;
        } elseif (strlen($telefono) > 10) {
            // Si el número tiene más de 10 dígitos, quitar los primeros
            return substr($telefono, -10);
        } else {
            // Si el número tiene menos de 10 dígitos, retornar cadena vacía
            return '';
        }
    }

    function validarEmail($email)
    {
        $this->logger->info('SE VALIDA EL EMAIL!!! ' . PHP_EOL);
        // Utilizar la función filter_var con el filtro FILTER_VALIDATE_EMAIL para validar el email
        if (filter_var($email, FILTER_VALIDATE_EMAIL)) {
            // Si el email es válido, devolver el email
            return $email;
        } else {
            // Si el email no es válido, devolver una cadena vacía
            return '';
        }
    }

    

}
