<?php
require_once __DIR__ . '/../Models/TermoAutorizacao.php';
require_once __DIR__ . '/CertificadoController.php';

class XmlController {
    public static function gerarXmlAssinadoBase64($dados) {
        // Validação básica dos parâmetros obrigatórios
        if (empty($dados['certificado']) || empty($dados['senha'])) {
            return json_encode(["status" => "error", "message" => "Certificado digital e senha são obrigatórios."]);
        }

       try {
    echo "Passo 1: Iniciando processo...<br>";

    $certificado = CertificadoController::carregar($dados['certificado'], $dados['senha']);
    echo "Passo 2: Certificado carregado!<br>";

    $termo = new TermoAutorizacao($dados);
    $xmlNaoAssinado = $termo->gerarXML();
    echo "Passo 3: XML gerado!<br>";

    $xmlAssinado = self::assinarXml($xmlNaoAssinado, $certificado);
    echo "Passo 4: XML assinado!<br>";

    self::validarCertificadoAssinatura($xmlAssinado, $certificado->certificate);
    echo "Passo 5: Certificado validado!<br>";

    return json_encode([
        "status" => "success",
        "xml_base64" => base64_encode($xmlAssinado)
    ]);
} catch (Exception $e) {
    die(json_encode(["status" => "error", "message" => $e->getMessage()]));
}
    }

    private static function assinarXml($xml, $certificado) {
        $doc = new DOMDocument();
        $doc->loadXML($xml);

        // Criar nó de assinatura
        $signature = $doc->createElement('Signature');
        $signature->setAttribute('xmlns', 'http://www.w3.org/2000/09/xmldsig#');
        $doc->documentElement->appendChild($signature);

        // Criar SignedInfo
        $signedInfo = $doc->createElement('SignedInfo');
        $signature->appendChild($signedInfo);

        // Definir métodos de Canonicalização e Assinatura
        $canonicalizationMethod = $doc->createElement('CanonicalizationMethod');
        $canonicalizationMethod->setAttribute('Algorithm', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
        $signedInfo->appendChild($canonicalizationMethod);

        $signatureMethod = $doc->createElement('SignatureMethod');
        $signatureMethod->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
        $signedInfo->appendChild($signatureMethod);

        // Criar referência para DigestValue
        $reference = $doc->createElement('Reference');
        $reference->setAttribute('URI', '');
        $signedInfo->appendChild($reference);

        // Criar Transforms exigidos pelo Serpro
        $transforms = $doc->createElement('Transforms');
        $reference->appendChild($transforms);

        $transformEnveloped = $doc->createElement('Transform');
        $transformEnveloped->setAttribute('Algorithm', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature');
        $transforms->appendChild($transformEnveloped);

        $transformC14N = $doc->createElement('Transform');
        $transformC14N->setAttribute('Algorithm', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
        $transforms->appendChild($transformC14N);

        // Criar DigestMethod
        $digestMethod = $doc->createElement('DigestMethod');
        $digestMethod->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmlenc#sha256');
        $reference->appendChild($digestMethod);

        // Calcular DigestValue
        $canonicalData = $doc->documentElement->C14N(true, false);
        $digestValue = base64_encode(openssl_digest($canonicalData, "sha256", true));
        $digestValueElement = $doc->createElement('DigestValue', $digestValue);
        $reference->appendChild($digestValueElement);

        // Assinar com a chave privada
        openssl_sign($signedInfo->C14N(true, false), $signatureValue, $certificado->privateKey, OPENSSL_ALGO_SHA256);
        $signatureValueElement = $doc->createElement('SignatureValue', base64_encode($signatureValue));
        $signature->appendChild($signatureValueElement);

        // Adicionar informações do certificado ao XML assinado
        $keyInfo = $doc->createElement('KeyInfo');
        $signature->appendChild($keyInfo);

        $X509Data = $doc->createElement('X509Data');
        $keyInfo->appendChild($X509Data);

        $X509Certificate = $doc->createElement('X509Certificate', CertificadoController::formatarCertificado($certificado->certificate));
        $X509Data->appendChild($X509Certificate);

        return $doc->saveXML();
    }

    private static function validarCertificadoAssinatura($xml, $certOriginal) {
        $certNoXml = CertificadoController::extrairCertificadoDoXml($xml);
        $certFormatado = CertificadoController::formatarCertificado($certOriginal);

        if ($certNoXml !== $certFormatado) {
            die(json_encode(["status" => "error", "message" => "Erro: O certificado do XML assinado NÃO corresponde ao certificado digital carregado."]));
        }
    }
}