<?php
namespace App\Http\Controllers\Invoicing;

use App\Http\Controllers\Controller;
use App\Http\Requests\Invoicing\PaymentComplementRequest;
use App\Http\Requests\Invoicing\InvoiceCancellationRequest;
use App\Http\Requests\Invoicing\MultiPaymentComplementRequest;

use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;
use Carbon\Carbon;
use Throwable;

use Barryvdh\DomPDF\Facade\Pdf as PDF;
use SimpleSoftwareIO\QrCode\Facades\QrCode;

use Illuminate\Support\Facades\Mail;
use App\Mail\Invoices\EmailPaymentCFDI;

use App\Models\User;
use App\Models\Environment\Business;
use App\Models\Invoicing\TaxInvoice;
use App\Models\Invoicing\TaxPayment;
use App\Models\Invoicing\TaxPaymentDoc;

use App\Enums\Invoicing\InvoiceStatus;
use App\Enums\Invoicing\InvoiceCancellationStatus;

use App\Helpers\Environment\SystemFeaturesHelper;
use App\Helpers\Environment\SystemLimitsHelper;
use App\Helpers\Support\SequenceControlHelper;
use App\Helpers\Support\PdfResourcesHelper;

use App\Services\Facturapi\FacturapiPaymentService;

class TaxPaymentController extends Controller
{
  //* Constructor
    public function __construct(
        protected FacturapiPaymentService $facturapi_payments
    ) {
        $this->middleware(['auth', 'role:administrador,gerente,recepcionista']);
    }

  //* Basic CRUD
    public function invoicePaymentHistory($id) {
        if(request()->ajax()){
            $data = TaxInvoice::where('id', $id)
                ->with([
                    'receptor', 'receptor.taxSystem',
                    'taxFormat', 'latestTaxPaymentDoc',
                    'taxPaymentDocs.taxPayment', 'taxPaymentDocs.taxPayment.paymentForm', 'taxPaymentDocs.taxPayment.taxFormat'
                ])->first();

            return response()->json([
                'data' => $data,
                'stamping_limit_status' => SystemLimitsHelper::getStampingLimitStatus()
            ]);
        }

        return view('errors.404');
    }

    public function certify(PaymentComplementRequest $request) {
      // Validate Stamp Limit
        SystemLimitsHelper::abortIfStampingLimitReached();

      // Validate Data
        $validated = $request->validated();

      // Start Transaction
        try {
            $result = DB::transaction(function () use ($validated) {
              // Load invoice parent
                $invoice = TaxInvoice::with(['taxItems', 'latestTaxPaymentDoc', 'taxPaymentDocs'])->findOrFail($validated['invoice_id']);
                    if (empty($invoice->sat_uuid) || $invoice->status->value !== InvoiceStatus::Valid->value) {
                        throw ValidationException::withMessages([
                            'on_save.invoice' => ['La factura debe estar timbrada para poder registrar un complemento de pago.'],
                        ]);
                    }

              // Recalculate balances & Installment number
                $latest_payment = $invoice->latestTaxPaymentDoc;
                $previous_balance = $latest_payment ? (float)$latest_payment->remaining_balance : (float)$invoice->total;
                $amount_paid = (float)$validated['amount_paid'];
                    if ($amount_paid <= 0 || $amount_paid > $previous_balance)
                        throw ValidationException::withMessages([
                            'on_save.amount' => ['El monto excede el saldo pendiente o es inválido.'],
                        ]);

                $remaining_balance = round($previous_balance - $amount_paid, 2);
                $installment_number = ($invoice->taxPaymentDocs?->count() ?? 0) + 1;


                $third_party_account = (object) $validated['third_party'] ?? null;

              // Create Certified Payment Complement
                $payment = TaxPayment::create([
                    'client_id'     => $invoice->client_id,
                    'tax_format_id'     => $validated['tax_format_id'],
                    'tax_branch_id'     => $validated['tax_branch_id'],
                    "serial_consecutive" => SequenceControlHelper::nextInvoiceSerialConsecutive("P", $validated['tax_branch_id'], $validated['tax_format_id']),

                    'cfdi_use'      => $validated['cfdi_use'] ?? $invoice->cfdi_use,
                    'payment_form'  => $validated['payment_form'],
                    'currency'      => $validated['currency'],
                    'payment_date'  => $validated['payment_date'],
                    'third_party_account'  => $third_party_account,

                    'exchange_rate' => $validated['exchange_rate'] ?? 1.00,
                    'amount_total'  => $amount_paid,

                    'status' => InvoiceStatus::Pending->value,
                ]);

                // Compare exchange_rate (Inherit Contrast) - This process is important for render the payment history
                $invoice_currency = $invoice->currency;
                $payment_currency = $validated['currency'];

                $current_exchange_rate_invoice = floatval($validated['invoice_exchange_rate']); // Tipo de Cambio actual de la Factura padre
                $current_exchange_rate = floatval($validated ['exchange_rate']); // Tipo de Cambio del Complemento de Pago

                if($invoice_currency != $payment_currency){
                    $current_exchange_rate = $current_exchange_rate_invoice;
                }

              // Create Relation with Original invoice
                $payment_doc = TaxPaymentDoc::create([
                    'tax_payment_id'     => $payment->id,
                    'invoice_id'         => $invoice->id,
                    'invoice_uuid'       => $invoice->sat_uuid,

                    'installment_number' => $installment_number,
                    'currency'           => $validated['currency'],

                    'previous_balance'   => $previous_balance,
                    'amount_paid'        => $amount_paid,
                    'remaining_balance'  => $remaining_balance,
                    'exchange_rate'      => $current_exchange_rate ?? 1.00,
                ]);

              // Save in Facturapi
                $result = $this->facturapi_payments->createWithXml($payment, [$payment_doc], []);

                $this->mergeFacturapiData($payment, $result);

              // Increase Stamp Counter
                SystemLimitsHelper::incrementStampLimitCounter('stamped');

              // Return Processed Data
                return [
                    'message' => '¡Complemento timbrado con Éxito!',
                    'invoice_id' => $invoice->id,
                    'payment_id' => $payment->id,
                    'remaining_balance' => $remaining_balance,
                ];
            }, 3); // In case of a DeadLock (or loss of connection), please try again up to three times.

            return response()->json([
                'success' => $result['message'],
                'invoice_id' => $result['invoice_id'],
                'payment_id' => $result['payment_id'],
                'remaining_balance' => $result['remaining_balance'],
                'stamping_limit_status' => SystemLimitsHelper::getStampingLimitStatus(),
            ]);
        } catch (ValidationException $ve) {
            throw $ve;
        }
    }

    public function show(Request $request, $id) {
      // Load Payment + Related Documents
        $tax_payment = TaxPayment::with(['taxPaymentDocs.taxInvoice'])->findOrFail($id);
        if(!in_array($tax_payment->status, [InvoiceStatus::Valid, InvoiceStatus::Canceled]))
            return redirect()->route('invoices.index');

      // Related Documents
        $payment_docs = $tax_payment->taxPaymentDocs;

      // Complementary Data
        $issuer = Business::first();

        $plane_date = Carbon::parse($tax_payment->payment_date)->format('YmdHis');
        $payment_format_serie = ($tax_payment->taxFormat?->serie ?? "P")."-{$tax_payment->serial_consecutive}";
        $doc_name = "{$tax_payment->receptor->tax_id}-{$payment_format_serie}-{$plane_date}";

      // Create QR
        $qrBase64 = base64_encode(QrCode::format('png')->size(150)->generate($tax_payment->verification_url));
        $qr_stamp = "data:image/png;base64,$qrBase64";

      // Build PDF
        $fallback_url = public_path('images/harsi_logo.png');
        $img_path  = $tax_payment->taxFormat?->url_logo ?? optional(User::first())->profile_photo;

        $tax_logo = PdfResourcesHelper::domPDFImageRender($img_path, $fallback_url);
        $view = SystemFeaturesHelper::getFeatureStatus("sat_format_invoices")
            ? 'invoicing.payment-complements.pdf.standard.show'
            : 'invoicing.payment-complements.pdf.show';

        $pdf = PDF::loadView($view, [
            'tax_payment' => $tax_payment,
            'payment_docs'  => $payment_docs,
            'payment_format_serie' => $payment_format_serie,

            'issuer' => $issuer,
            'title' => $doc_name,
            'logo_src' => $tax_logo,
            'qr_stamp' => $qr_stamp,
        ])->setPaper('letter')->setOptions([
            'defaultFont' => 'sans-serif',
            'isHtml5ParserEnabled' => true,
            'isRemoteEnabled'      => false
        ]);

      // Return PDF
        if ((bool) $request->query('download'))
            return $pdf->download("$doc_name.pdf", ['Attachment' => false]);
        else
            return $pdf->stream("$doc_name.pdf", ['Attachment' => false]);
    }

    public function downloadXml($id) {
        $tax_payment = TaxPayment::findOrFail($id);

        if( !in_array($tax_payment->status, [InvoiceStatus::Canceled, InvoiceStatus::Valid]) )
            return redirect()->route('invoices.index');

        if (!$tax_payment->xml_path || !Storage::disk('public')->exists($tax_payment->xml_path))
            abort(404, 'XML not Found.');

        // Leer archivo real
        $xml_content = Storage::disk('public')->get($tax_payment->xml_path);

        // Nombre de archivo para descarga
        $file_name = basename($tax_payment->xml_path);

        // Forzar descarga
        return response()->streamDownload(function () use ($xml_content) {
            echo $xml_content;
        }, $file_name, [
            'Content-Type' => 'application/xml',
        ]);
    }

    public function sendPaymentCfdiByEmail($id, Request $request) {
        $validated = $request->validate([
            'emails.to'    => ['required', 'email:rfc'],
            'emails.cc'    => ['array'],
            'emails.cc.*'  => ['nullable', 'email:rfc'],
        ]);

        try {
          // Validate Invoice Status
            $tax_payment = TaxPayment::findOrFail($id);

            if($tax_payment->status != InvoiceStatus::Valid)
                return redirect()->route('invoices.index');

          // Complementary Data
            $business = Business::first();

          // Emails
            $to = $validated['emails']['to'];
            $cc = array_filter($validated['emails']['cc'] ?? []);

            Mail::to($to)->cc($cc)->send(new EmailPaymentCFDI($tax_payment, $business));

            return response()->json([
                'success' => true,
                'message' => __('common_responses_and_messages')['email_sent_successfully'],
            ]);
        } catch (\Exception $e) {
            Log::error("Error al enviar el CFDI del Complemento de Pago #$id: " . $e->getMessage());

            return response()->json([
                'success' => false,
                'message' => __('common_responses_and_messages')['email_not_sent'],
            ], 500);
        }
    }

    public function searchBySatUuid(Request $request) {
        $value = trim((string) $request->input('q', '')); // Valor consultado
        $page = max(1, (int) $request->input('page', 1)); // Cantidad de paginas a mostrar
        $perPage = 20; // Limite de resultados por pagina

        // Se cachea temporalmente la consulta para evitar re-consultas iguales o similares
        $cacheKey = "tax_payment_uuid:q={$value}:page={$page}:per={$perPage}";
        $data = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($value, $page, $perPage) {
            $query = TaxPayment::query(); // Query Builder

            if ($value !== '') {
                // Busca por SAT UUID (exacta primero o por prefijo)
                $query->where(function ($w) use ($value) {
                    $w->where('sat_uuid', 'like', $value.'%')
                        ->where('status', InvoiceStatus::Valid->value);
                });
            }

            $total = (clone $query)->count(); // Cantidad de registros retornados
            $rows = $query->orderByRaw("sat_uuid = ? desc", [$value]) // Prioriza match exacto
                            ->orderBy('sat_uuid')
                            ->skip(($page - 1) * $perPage)
                            ->take($perPage)
                            ->get(['sat_uuid', 'id']);

            return ['total' => $total, 'rows'  => $rows];
        });

        // Retornar en Formato util para Select2
        return response()->json([
            'results' => $data['rows']->map(fn ($r) => [
                'id'   => $r->id,
                'text' => $r->sat_uuid,
            ]),
            'pagination' => ['more' => ($page * $perPage) < $data['total']],
        ]);
    }

    public function cancel(InvoiceCancellationRequest $request, $id) {
      // Validate Stamp Limit
        SystemLimitsHelper::abortIfStampingLimitReached();

      // Validate Request
        $validated = $request->validated();
        $tax_payment = TaxPayment::findOrFail($id);

      // Validate Invoice Data
        if ($tax_payment->status !== InvoiceStatus::Valid)
            return redirect()->route('invoices.index');

        if (!$tax_payment->facturapi_payment_id)
            throw ValidationException::withMessages([
                'invoice' => [__('entity_forms')['tax_payment']['messages']['cancel_complement_not_allowed']],
            ]);

      // Cancel Invoice
        try {
            $result = DB::transaction(function () use ($tax_payment, $validated) {
              // Save in Facturapi
                $response = $this->facturapi_payments->cancel(
                    $tax_payment->facturapi_payment_id,
                    [
                        'motive' => $validated['cancel_motive'],

                        // Required in Motivo 01
                        'substitution_invoice' => array_key_exists("substitution_invoice_id", $validated)
                            ? TaxInvoice::find($validated['substitution_invoice_id'])?->facturapi_payment_id
                            : null,
                    ]
                );

                // Increment Stamped Counter
                SystemLimitsHelper::incrementStampLimitCounter('cancelled');

              // Mark cancellation as requested locally
                $tax_payment->cancellation_status = InvoiceCancellationStatus::Pending;

              // Payment complement still valid until SAT confirms
                $tax_payment->status = InvoiceStatus::Valid;

              // Save intent
                $tax_payment->cancel_motive = $validated['cancel_motive'];
                $tax_payment->substitution_invoice_id = $validated['substitution_invoice_id'] ?? null;

              // Audit payload
                $tax_payment->response_payload = $response;
                $tax_payment->save();

                return [
                    'status' => $tax_payment->status->value,
                    'cancellation_status' => $tax_payment->cancellation_status->value,
                ];
            });

            return response()->json([
                'success' => true,
                // 'data'    => $result,
                'message' => $result['cancellation_status'] === InvoiceCancellationStatus::Pending->value
                    ? __('entity_forms')['tax_payment']['messages']['cancel_complement_pending']
                    : __('common_responses_and_messages')['updated_successfully'],

                // Stamped status
                'stamping_limit_status' => SystemLimitsHelper::getStampingLimitStatus(),
            ]);
        } catch (ValidationException $ve) {
            throw $ve;
        }
    }

  //* Multi-Payments Functions
    public function getInvoicesForMultiPayments(Request $request){
        try{
          //* Validate Request
            $request->validate([
                'client_id' => ['required', 'integer']
            ]);

          //* Get PPD invoices that Bellow to specified receptor & have remaining balances
            $invoices = TaxInvoice::query()->with(['receptor','latestTaxPaymentDoc'])
                ->where('client_id', $request->client_id)
                ->whereNotIn('status', [ InvoiceStatus::Draft, InvoiceStatus::Canceled ])
                ->where('payment_method', 'PPD')
                ->orderBy('date', 'asc')->get();

          //* Format Invoice Data
            $formatted_invoices = $invoices->map(function ($invoice){
              // Compute balances
                $total = (float) ($invoice->total ?? 0);
                $remaining_balance = (float) (
                    $invoice?->latestTaxPaymentDoc?->remaining_balance
                    ?? $total
                );

                $amount_paid = $total - $remaining_balance;

              // Parse data to return
                return[
                    'id'                => $invoice->id,
                    'folio'             => $invoice->serial_consecutive,
                    'serie'             => $invoice?->taxFormat?->serie,
                    'date'              => $invoice->date,
                    'currency'          => $invoice->currency,
                    'exchange_rate'     => $invoice->exchange_rate,
                    'total'             => $total,
                    'amount_paid'       => $amount_paid,
                    'remaining_balance' => $remaining_balance,
                    'payment_method'    => $invoice->payment_method,
                    'invoice_type'      => $invoice->invoice_type,
                ];
            })->filter(fn($invoice) => $invoice['remaining_balance'] > 0)
                ->values();

            return response()->json([
                'success' => true,
                'data' => $formatted_invoices
            ]);
        }catch(Throwable $th){
            return response()->json([
                'success' => false,
                'message' => $th->getMessage()
            ], 500);
        }
    }

    public function getDetailsOnInvoicesForMultiPayments(Request $request){
        try{
          //* Validate Request
            $request->validate([
                'invoice_ids' => ['required', 'array'],
                'invoice_ids.*' => ['integer']
            ]);

          //* Search Invoices
            $invoices = TaxInvoice::query()
                ->with([ // Load relations
                  // Receiver
                    'receptor', 'receptor.taxSystem',

                  // Invoice Relations
                    'taxFormat',

                  // Payment Context
                    'latestTaxPaymentDoc',

                  // Previous Payments
                    'taxPaymentDocs', 'taxPaymentDocs.taxPayment',
                    'taxPaymentDocs.taxPayment.paymentForm', 'taxPaymentDocs.taxPayment.taxFormat',
                ])

                // Filters
                ->whereIn('id', $request->invoice_ids)
                ->where('payment_method', 'PPD')
                ->where('status', '!=', InvoiceStatus::Draft)
                ->where('status', '!=', InvoiceStatus::Canceled)
                ->orderBy('date', 'asc')->get();

          //* Transform Data
            $formatted_invoices = $invoices->map(function ($invoice){
              // Compute balances
                $total = (float) ($invoice->total ?? 0);
                $remaining_balance = (float) (
                    $invoice?->latestTaxPaymentDoc?->remaining_balance
                    ?? $total
                );

                $amount_paid = $total - $remaining_balance;

              // Map payment history
                $payment_history = $invoice->taxPaymentDocs->map(
                    function ($payment_doc){
                        return [
                            'id'                    => $payment_doc->id,
                            'installment_number'    => $payment_doc->installment_number,
                            'previous_balance'      => (float) $payment_doc->previous_balance,
                            'amount_paid'           => (float) $payment_doc->amount_paid,
                            'remaining_balance'     => (float) $payment_doc->remaining_balance,
                            'currency'              => $payment_doc->currency,
                            'exchange_rate'         => $payment_doc->exchange_rate,
                            'tax_payment'           => [
                                'id'                => $payment_doc?->taxPayment?->id,
                                'payment_date'      => $payment_doc?->taxPayment?->payment_date,
                                'payment_form'      => $payment_doc?->taxPayment?->payment_form,
                                'status'            => $payment_doc?->taxPayment?->status,
                            ]
                        ];
                    }
                ) -> values();

              // Parse data to Return
                return [
                    // Basic Identification
                    'id'            => $invoice->id,
                    'folio'         => $invoice->serial_consecutive,
                    'serie'         => $invoice->taxFormat?->serie,
                    'invoice_type'  => $invoice->invoice_type,
                    'tax_branch_id' => $invoice->tax_branch_id,
                    'sat_uuid'      => $invoice->sat_uuid,

                    // Receiver
                    'receiver' => [
                        'id'            => $invoice?->receptor?->id,
                        'legal_name'    => $invoice?->receptor?->legal_name,
                        'tax_id'        => $invoice?->receptor?->tax_id,
                        'cfdi_use'      => $invoice?->receptor?->cfdi_use,
                        'tax_system'    => $invoice?->receptor?->taxSystem?->item_key
                    ],

                    // Final Context
                    'currency'      => $invoice->currency,
                    'exchange_rate' => $invoice->exchange_rate,
                    'payment_method'=> $invoice->payment_method,
                    'payment_form'  => $invoice->payment_form,

                    // Totals
                    'subtotal'      => (float) $invoice->subtotal,
                    'taxes_total'   => (float) $invoice->taxes_total,
                    'total'         => $total,

                    // Payment Status
                    'amount_paid'   => $amount_paid,
                    'remaining_balance' => $remaining_balance,

                    // Dates
                    'date'          => $invoice->date,
                    'due_date'      => $invoice->due_date,

                    // Payment History
                    'payments_history' => $payment_history,
                ];
            })

            // Filtramos facturas completamente pagadas
            ->filter( fn($invoice) =>
                $invoice['remaining_balance'] > 0
            )->values();

         //* Response
            return response()->json([
                'success'   => true,
                'data'      => $formatted_invoices
            ]);

        }catch(Throwable $th){
            return response()->json([
                'success'   => false,
                'message'   => $th->getMessage()
            ], 500);
        }
    }

    public function certifyMultiple(MultiPaymentComplementRequest $request){
      //* Validations
        // Validate Stamp Limit
        SystemLimitsHelper::abortIfStampingLimitReached();

        // Validate Request
        $validated = $request->validated();

      //* Start Transaction
        try{
          // Certify each payment per invoice
            $result = DB::transaction(function () use ($validated){
              // Validate Documents
                if(
                    empty( $validated['documents'] ) ||
                    !is_array( $validated['documents'] )
                ){
                    throw ValidationException::withMessages([
                        'documents' => ['No se encontraron documentos relacionados.']
                    ]);
                }

              // Use the first one to inherit the client data
                $first_invoice = TaxInvoice::findOrFail($validated['documents'][0]['invoice_id']);

              // Create main taxPayment
                $payment = TaxPayment::create([
                    'client_id'             => $first_invoice->client_id,
                    'tax_format_id'         => $validated['tax_format_id'],
                    'tax_branch_id'         => $validated['tax_branch_id'],
                    'serial_consecutive'    => SequenceControlHelper::nextInvoiceSerialConsecutive("P", $validated['tax_branch_id'], $validated['tax_format_id']),

                    'cfdi_use'              => $validated['cfdi_use'] ?? $first_invoice->cfdi_use,
                    'payment_form'          => $validated['payment_form'],
                    'currency'              => $validated['currency'],
                    'payment_date'          => $validated['payment_date'],
                    'exchange_rate'         => $validated['exchange_rate'] ?? 1.00,
                    'amount_total'          => $validated['amount'], // Monto Global

                    'status'                => InvoiceStatus::Pending->value,
                ]);

              // Create Related Documents
                $payment_docs = [];

                foreach($validated['documents'] as $doc_data){
                  // Load Invoice parents
                    $invoice = TaxInvoice::with(['taxItems', 'latestTaxPaymentDoc', 'taxPaymentDocs'])->findOrFail($doc_data['invoice_id']);
                        if(empty($invoice->sat_uuid) || $invoice->status->value !== InvoiceStatus::Valid->value){
                            throw ValidationException::withMessages([
                                'on_save.invoice' => [ "La factura {$invoice->folio} debe estar timbrada para poder registrar un complemento de pago."],
                            ]);
                        }

                  // Recalculate values
                    $latest_payment = $invoice->latestTaxPaymentDoc;
                    $previous_balance = $latest_payment ? (float) $latest_payment->remaining_balance : (float) $invoice->total;
                    $amount_paid = (float) $doc_data['amount_paid'];

                    // Validate Amounts
                        if($amount_paid <= 0 || $amount_paid > $previous_balance)
                            throw ValidationException::withMessages([
                                'on_save.amount'    => ["El monto  pagado de la factura {$invoice->folio} es invalido."],
                            ]);

                    // Calculate remaining balance & installment number
                        $remaining_balance = round($previous_balance - $amount_paid, 2);
                        $installment_number = ($invoice->taxPaymentDocs->count() ?? 0) + 1;

                  // Compare exchange_rate (Inherit Contrast) - This process is important for render the payment history
                    $invoice_currency = $invoice->currency;
                    $payment_currency = $validated['currency'];

                    $invoice_exchange_rate = floatval($invoice->exchange_rate ?? 1);
                    $current_exchange_rate = floatval($validated['exchange_rate'] ?? 1);

                    if($invoice_currency != $payment_currency)
                        $current_exchange_rate = $invoice_exchange_rate;

                  // Create Relation with Original Invoice
                    $payment_doc = TaxPaymentDoc::create([
                        'tax_payment_id'    => $payment->id,
                        'invoice_id'        => $invoice->id,
                        'invoice_uuid'      => $invoice->sat_uuid,

                        'installment_number' => $installment_number,
                        'currency'          => $validated['currency'],

                        'previous_balance'  => $previous_balance,
                        'amount_paid'       => $amount_paid,
                        'remaining_balance' => $remaining_balance,
                        'exchange_rate'     => $current_exchange_rate ?? 1.00,
                    ]);

                    $payment_docs[] = $payment_doc;
                }

              // Save in Facturapi
                $facturapi_result = $this->facturapi_payments->createWithXml($payment, $payment_docs, []);

              // Merge data with SAT
                $this->mergeFacturapiData($payment, $facturapi_result);

              // Increase Stamp Counter
                SystemLimitsHelper::incrementStampLimitCounter('stamped');

              // Return process data
                return[
                    'message'       => '¡Complemento timbrado con éxito!',
                    'tax_payment_id'    => $payment->id,
                    'documents_processed'   => count($payment_docs),
                    'payment_docs'  => collect($payment_docs)->map(function ($doc) {
                        return [
                            'tax_payment_doc_id'    => $doc->id,
                            'tax_payment_id'        => $doc->tax_payment_id,
                            'invoice_id'            => $doc->invoice_id,
                            'amount_paid'           => $doc->amount_paid,
                            'remaining_balance'     => $doc->remaining_balance,
                            'installment_number'     => $doc->installment_number,
                        ];
                    })->values(),
                ];
            }, 3); // In case of a DeadLock try again up to three times.

          // Return results
            return response() -> json([
                'success' => $result['message'],
                'tax_payment_id' => $result['tax_payment_id'],
                'documents_processed' => $result['documents_processed'],
                'payment_docs' => $result['payment_docs'],
                'stamping_limit_status' => SystemLimitsHelper::getStampingLimitStatus(),
            ]);

        }catch(ValidationException $ve){
            throw $ve;
        }catch(Throwable $th){
            Log::error('ERROR MULTIPAYMENT CERTIFICATION', [
                'message' => $th->getMessage(), 'line' => $th->getLine(), 'file' => $th->getFile(),
            ]);

            return response()->json([
                'success' => false, 'type'  => 'system',
                'errors' => [
                    'general' => ['Ocurrió un error al generar el complemento múltiple.']
                ]
            ], 500);
        }
    }

  //* Support Functions
    public function mergeFacturapiData(TaxPayment $payment, array $facturapi_response) {
      // Parse Response
        $response = (object) $facturapi_response;

      // Save XML
        // Build Name
        $plane_date = Carbon::parse($payment->payment_date)->format('YmdHis');
        $payment_format_serie = ($payment->taxFormat?->serie ?? "P")."-{$payment->serial_consecutive}";

        $filename = trim(
            implode('-', array_filter([$payment->receptor->tax_id, $payment_format_serie, $plane_date])),
            '-'
        ) . '.xml';

        $file_path = 'payments/xml/' . $filename;

        // Save file
        $xml = $response->xml ?? null;
            if (is_array($xml))
                $xml = $xml['content'] ?? null;

        if (is_string($xml) && trim($xml) !== '') {
            $xml = trim($xml, "\"");
            $xml = stripcslashes($xml);
            $xml = html_entity_decode($xml);

            Storage::disk('public')->put($file_path, $xml);
            $payment->xml_path = $file_path;
        }

      // Update local payload
        $payment->facturapi_payment_id   = $response->invoice['id'] ?? null;
        $payment->certification_date     = $response->invoice['stamp']['date'] ?? null;
        $payment->sat_uuid               = $response->invoice['uuid'] ?? null;
        $payment->cfdi_seal              = $response->invoice['stamp']['signature'] ?? null;
        $payment->sat_seal               = $response->invoice['stamp']['sat_signature'] ?? null;
        $payment->sat_cert_number        = $response->invoice['stamp']['sat_cert_number'] ?? null;
        $payment->tfd_original_string    = $response->invoice['stamp']['complement_string'] ?? null;
        $payment->verification_url     = $response->invoice['verification_url'] ?? null;
        $payment->request_payload        = $response->payload ?? null;
        $payment->response_payload       = $response->invoice ?? null;
        $payment->status = InvoiceStatus::Valid->value;

        $payment->save();

        return;
    }

}

