<?php

namespace Daniv04\HaciendaPackage\Providers\Hacienda;

use Daniv04\HaciendaPackage\Providers\Contracts\ProviderInterface;
use Daniv04\HaciendaPackage\Data\ProviderResponse;
use DateTime;
use Daniv04\HaciendaPackage\Providers\Hacienda\Transformer\HaciendaTransformer;
use Illuminate\Support\Facades\Http;
use Daniv04\HaciendaPackage\Services\XmlGenerator\XmlGeneratorService;
use Daniv04\HaciendaPackage\Services\Hacienda\XmlSignerService;
use Daniv04\HaciendaPackage\Services\Hacienda\Idp\HaciendaIdpService;
use Daniv04\HaciendaPackage\Services\Hacienda\Idp\HaciendaIdpException;
use Daniv04\HaciendaPackage\Services\KeyGeneratorService;
use Illuminate\Http\Client\Response;
use Daniv04\HaciendaPackage\Providers\Hacienda\Data\HaciendaDto;
use Daniv04\HaciendaPackage\Providers\Hacienda\Data\IdentificationData;


class HaciendaProvider implements ProviderInterface
{
    public function __construct(
        private XmlGeneratorService $xmlGenerator,
        private XmlSignerService $xmlSigner,
        private HaciendaIdpService $idpService,
        private KeyGeneratorService $keyGenerator,
    ) {}

    public function sendDocument(array $payload, string $consecutiveNumber): ProviderResponse
    {
        //Vars for consecutive key
        $docType       = $payload['Clave']['TipoComprobante'];
        $establishment = $payload['Clave']['Sucursal'];
        $terminal      = $payload['Clave']['Terminal'];

        //Vars for unique key
        $date         = $payload['Encabezado']['FechaEmision'] ?? (new DateTime())->format('Y-m-d\TH:i:sP');
        $securityCode = $this->keyGenerator->generateSecurityCode($consecutiveNumber . $date);
        $dateParsed   = $this->keyGenerator->parseDateToArray($date);
        $emisorID     = $payload['Emisor']['Identificacion']['Numero'];
        $idType       = $payload['Emisor']['Identificacion']['Tipo'];
        $situation    = $payload['Encabezado']['SituacionComprobante'];

        $consecutiveKey = $this->keyGenerator->generateConsecutiveKey($docType, $consecutiveNumber, $establishment, $terminal);
        $uniqueKey      = $this->keyGenerator->generateUniqueKey($dateParsed, $emisorID, $idType, $consecutiveKey, $situation, $securityCode);
        $dealer         = config('hacienda.provider_id');

        $transformedData = HaciendaTransformer::transformDocument($payload, $consecutiveKey, $uniqueKey, $dealer);

        if(config('hacienda.hacienda_idp.environment') === 'prod') {
            $baseUrl   = config('hacienda.api_base_url_prod');
        } else {
            $baseUrl   = config('hacienda.api_base_url_stag');
        }
        $methodUrl = config('hacienda.api_url_recepcion');
        $url       = $baseUrl . $methodUrl;

        try {
            // Generate Hacienda-compliant XML
            $xmlString = $this->xmlGenerator->generateXml($transformedData);

            // Sign XML with XAdES-EPES
            $signedXml = $this->xmlSigner->sign($xmlString);

            // Base64-encode the signed XML
            $comprobanteXml = base64_encode($signedXml);

            // Build the DTO for Hacienda's reception API
            $callbackUrl = route('hacienda.webhook');
            
            $emisorIdentification = new IdentificationData($idType, $emisorID);
            $dto = new HaciendaDto($uniqueKey, $date, $emisorIdentification, $comprobanteXml,$callbackUrl);

            if (isset($payload['Receptor']['Identificacion'])) {
                $receptorId = $payload['Receptor']['Identificacion'];
                $dto->setReceptor(new IdentificationData($receptorId['Tipo'], $receptorId['Numero']));
            }

            // Authenticate and POST to Hacienda
            $token = $this->idpService->getAccessToken();
            /** @var Response $response */
            $response = Http::withToken($token)->post($url, $dto->toArray());

            if (in_array($response->status(), [201, 202])) {
                return ProviderResponse::success(
                    documentKey: $uniqueKey,
                    sentAt: $date,
                    signedXml: $comprobanteXml,
                    raw: ['location' => $response->header('Location')]
                );
            }

            if ($response->status() === 400) {
                return ProviderResponse::failed(
                    errorMessage: $response->header('X-Error-Cause') ?? 'Validation error',
                    retriable: false,
                    raw: $response->json()
                );
            }

            return ProviderResponse::failed(
                errorMessage: 'Unexpected HTTP status: ' . $response->status(),
                retriable: true,
                raw: $response->json()
            );

        } catch (HaciendaIdpException $e) {
            return ProviderResponse::failed(
                errorMessage: 'Hacienda authentication error: ' . $e->getMessage(),
                retriable: true,
            );
        } catch (\Exception $e) {
            return ProviderResponse::failed(
                errorMessage: 'Error sending document: ' . $e->getMessage(),
                retriable: true,
                raw: ['trace' => $e->getTraceAsString()]
            );
        }
    }

    public function getDocumentStatus(array $documentKey): array
    {
        
        return [];
    }
}
