<?php

namespace App\Services\Facturapi;

use Illuminate\Support\Facades\Log;

use Illuminate\Validation\ValidationException;
use Facturapi\Exceptions\Facturapi_Exception;

use App\Services\Facturapi\FacturapiWrapper;

abstract class FacturapiResourceService
{
  //? General Configuration
    protected FacturapiWrapper $client;

    public function __construct(FacturapiService $facturapi)
    {
        $this->client = $facturapi->client();
    }

  //? Parent Functions
    //* General Usage
        /**
         *  Convert Facturapi's default response to a format that Laravel can process.
         *
         *  @param mixed $object Facturapi response
         *
         *  @return array Parsed response as Array
        */
        protected function toArray($object): array
        {
            return (array) json_decode(json_encode($object), true);
        }

        /**
         *  Maneja y normaliza las excepciones arrojadas por el SDK de Facturapi.
         *
         * @param  \Facturapi\Exceptions\Facturapi_Exception  $e  Excepción original lanzada por el SDK.
         * @throws ValidationException
        */
        protected function handleFacturapiException(Facturapi_Exception $e): never
        {
            // Extrae la respuesta dada por facturapi
            $rawMessage = $e->getMessage();

            // Extraer JSON embebido (si es que la respuesta viene en formato string)
            preg_match('/\{.*\}/', $rawMessage, $matches);

            // Define error structure
            $facturapiError = null;

            if (!empty($matches[0])) // Response include error
                $facturapiError = json_decode($matches[0], true);

            if (!$facturapiError || !is_array($facturapiError)) // Create custom error as default
                $facturapiError = [ "message" => $rawMessage, "status" => 400, "ok" => false ];

            // Log error
            Log::error('Facturapi Validation Error', [ 'parsed' => $facturapiError, 'original' => $rawMessage ]);

            // Return error 
            $field = $facturapiError['path'] ?? 'facturapi';
            throw ValidationException::withMessages([
                $field => [
                    $facturapiError['message'] ?? 'Error en Facturapi'
                ],
            ]);
        }

        /**
         *  Convert the data sent from the form into a valid payload for Facturapi requirements.
         */
        abstract protected function parsePayload(array $form_data): array;

    //* Tax Invoice Item/Product/Concept/Service

        /**
         * Ensure that the name of the measurement unit provided matches the length
         * required (to date) by Facturapi.
         *
         * @param string Measurement unit name to adjust
         *
         * @return string Measurement unit name adjusted to requirements
        */
        function sliceUnitName(string $unit_name): string
        {
            $sliced_text = "";
            if (strlen($unit_name) > 20) {
                $fixed_text = substr($unit_name, 0, 16);
                $sliced_text = $fixed_text . "...";
            } else {
                $sliced_text = $unit_name;
            }

            return $sliced_text;
        }

        /**
         * Convert the structure stored in BD (for tax_profile) to the format currently requested by Facturapi.
         *
         *  @param array $tax_profile Tax profile to format
         *
         *  @return array Formatted tax profile
        */
        function parseFederalTaxes(array $tax_profile): array
        {
            $taxes = [];

            // Impuestos trasladados (IVA, IEPS)
                if (!empty($tax_profile['taxes']['iva'])) {
                    $taxes[] = [
                        "type"   => "IVA",
                        "rate"   => $tax_profile['taxes']['iva']['rate'],
                        "factor" => $tax_profile['taxes']['iva']['exempt'] ? "Exento": "Tasa",
                    ];
                }

                if (!empty($tax_profile['taxes']['ieps'])) {
                    $taxes[] = [
                        "type"   => "IEPS",
                        "rate"   => $tax_profile['taxes']['ieps']['rate'],
                        "factor" => "Tasa",
                    ];
                }

            // Impuestos retenidos (ISR, IVA retenido)
                if (!empty($tax_profile['withholding_taxes']['isr'])) {
                    $taxes[] = [
                        "type"       => "ISR",
                        "rate"       => $tax_profile['withholding_taxes']['isr']['rate'],
                        "factor"     => "Tasa",
                        "withholding"=> true,
                    ];
                }

                if (!empty($tax_profile['withholding_taxes']['iva'])) {
                    $taxes[] = [
                        "type"       => "IVA",
                        "rate"       => $tax_profile['withholding_taxes']['iva']['rate'],
                        "factor"     => "Tasa",
                        "withholding"=> true,
                    ];
                }

            return $taxes;
        }

        /**
         * Convert the structure stored in BD (for local_tax_profile) to the format currently requested by Facturapi.
         *
         *  @param array $tax_profile Tax profile to format
         *
         *  @return array Formatted tax profile
        */
        function parseLocalTaxes(array $tax_profile): array
        {
            $local_taxes = [];

            // Trasladados
            if (!empty($tax_profile['transferred'])) {
                foreach ($tax_profile['transferred'] as $tax) {
                    if (empty($tax['rate']) || empty($tax['name'])) continue;

                    $local_taxes[] = [
                        "type" => $tax['name'],
                        "rate" => $tax['rate'] / 100,
                    ];
                }
            }

            // Retenidos
            if (!empty($tax_profile['withheld'])) {
                foreach ($tax_profile['withheld'] as $tax) {
                    if (empty($tax['rate']) || empty($tax['name'])) continue;

                    $local_taxes[] = [
                        "type" => $tax['name'],
                        "rate" => $tax['rate'] / 100,
                        "withholding" => true,
                    ];
                }
            }

            return $local_taxes;
        }

}
