<?php
/**
 * Mutual-TLS transport for AEAT VeriFactu.
 *
 * SOAP 1.1 is emitted explicitly so the real bytes always contain
 * Envelope/Header/Body. TLS verification is never disabled and temporary
 * certificate material is deleted in finally.
 */

if (!defined('ABSPATH')) {
    exit;
}

class VerifactuTransport
{
    public function send($xml, $module, array $expectedIdentity)
    {
        if (!extension_loaded('curl')) {
            throw new VerifactuTransportException('La extension cURL de PHP no esta activa.');
        }
        if (!extension_loaded('openssl')) {
            throw new VerifactuTransportException('La extension OpenSSL de PHP no esta activa.');
        }
        if (!extension_loaded('dom')) {
            throw new VerifactuTransportException('La extension DOM de PHP no esta activa.');
        }

        VerifactuXmlBuilder::validateXml($xml);
        $certificate = array();
        $http = array('request' => '', 'response' => '');

        try {
            $certificate = VerifactuCertificateManager::createTemporaryPem($module);
            $certificateIdentity = isset($certificate['identity']) && is_array($certificate['identity'])
                ? $certificate['identity']
                : VerifactuCertificateManager::extractFiscalIdentity($certificate['info']);
            $expectedIssuer = isset($expectedIdentity['issuer_nif'])
                ? VerifactuConfig::normalizeNif($expectedIdentity['issuer_nif'])
                : '';
            if ($expectedIssuer === '' || !hash_equals($certificateIdentity['issuer_nif'], $expectedIssuer)) {
                throw new Exception(
                    'El registro fiscal pertenece al NIF ' . ($expectedIssuer !== '' ? $expectedIssuer : '(no informado)')
                    . ', pero el certificado identifica al obligado ' . $certificateIdentity['issuer_nif']
                    . '. Se bloquea la remision para evitar enviar datos con una identidad fiscal inconsistente.'
                );
            }

            $http = VerifactuSoapHttpClient::post(
                (string) $xml,
                VerifactuConfig::getSoapEndpoint(),
                $certificate,
                'ddverifactu/' . (is_object($module) && isset($module->version) ? $module->version : '1.2.14')
            );

            return array(
                'result' => VerifactuResponseParser::parse($http['response'], $expectedIdentity),
                'request' => $http['request'],
                'response' => $http['response'],
                'http_status' => isset($http['http_status']) ? (int) $http['http_status'] : 0,
                'certificate' => isset($certificate['info']) ? $certificate['info'] : array(),
            );
        } catch (Throwable $e) {
            if ($e instanceof VerifactuTransportException) {
                throw $e;
            }
            throw new VerifactuTransportException(
                'No se ha podido completar la remision VeriFactu: ' . $e->getMessage(),
                isset($http['request']) ? (string) $http['request'] : '',
                isset($http['response']) ? (string) $http['response'] : '',
                $e,
                false
            );
        } finally {
            if (!empty($certificate)) {
                VerifactuCertificateManager::cleanup($certificate);
            }
        }
    }

    public function inspectCertificate($module)
    {
        $certificate = VerifactuCertificateManager::createTemporaryPem($module);
        try {
            return isset($certificate['info']) ? $certificate['info'] : array();
        } finally {
            VerifactuCertificateManager::cleanup($certificate);
        }
    }
}
