<?php
/**
 * SIGTAP/RNDS – Detalhar Procedimento (produção)
 * Compatível com PHP 7.4 e 8.x
 *
 * Uso rápido:
 *   $r = sigtapDetalharProcedimento('0203010027', ['DESCRICAO']);
 *   if ($r['ok']) { print_r($r['dados']); } else { echo $r['erro']; }
 */
function sigtapDetalharProcedimento(
    string $codigoProcedimento,
    array $categorias = ['DESCRICAO'],
    array $paginacao = ['registroInicial'=>1, 'quantidadeRegistros'=>20, 'totalRegistros'=>null],
    string $endpoint = ''
): array {
    // ===== Config padrão PRODUÇÃO =====
    $endpointProd = 'https://servicos.saude.gov.br/sigtap/ProcedimentoService/v1'; // ajuste se seu WSDL indicar outra URL
    $username     = 'SIGTAP.PUBLICO';
    $password     = 'sigtap#2015public';

    if ($endpoint === '') {
        $endpoint = $endpointProd;
    }

    // Sanitiza paginação
    $registroInicial     = (int)($paginacao['registroInicial'] ?? 1);
    $quantidadeRegistros = (int)($paginacao['quantidadeRegistros'] ?? 20);
    $totalRegistros      = $paginacao['totalRegistros'] ?? null;

    // ===== Namespaces =====
    $NS_soap  = 'http://www.w3.org/2003/05/soap-envelope';
    $NS_wsse  = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd';
    $NS_wsu   = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd';
    $NS_proc  = 'http://servicos.saude.gov.br/sigtap/v1/procedimentoservice';
    $NS_proc1 = 'http://servicos.saude.gov.br/schema/sigtap/procedimento/v1/procedimento';
    $NS_det   = 'http://servicos.saude.gov.br/wsdl/mensageria/sigtap/v1/detalheadicional';
    $NS_pag   = 'http://servicos.saude.gov.br/wsdl/mensageria/v1/paginacao';

    // ===== Monta SOAP 1.2 com DOM (robusto para PHP 7.4/8.x) =====
    $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = false;

    $env = $dom->createElementNS($NS_soap, 'soap:Envelope');
    $env->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:proc',  $NS_proc);
    $env->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:proc1', $NS_proc1);
    $env->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:det',   $NS_det);
    $env->setAttributeNS('http://www.w3.org/2000/xmlns/','xmlns:pag',   $NS_pag);
    $dom->appendChild($env);

    $header = $dom->createElement('soap:Header'); $env->appendChild($header);
    $sec    = $dom->createElementNS($NS_wsse, 'wsse:Security'); $header->appendChild($sec);

    $ut = $dom->createElementNS($NS_wsse, 'wsse:UsernameToken');
    $ut->setAttributeNS($NS_wsu, 'wsu:Id', 'UsernameToken-'.bin2hex(random_bytes(6)));
    $sec->appendChild($ut);

    $u = $dom->createElementNS($NS_wsse, 'wsse:Username', $username);
    $p = $dom->createElementNS($NS_wsse, 'wsse:Password', $password);
    $p->setAttribute('Type','http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText');
    $ut->appendChild($u); $ut->appendChild($p);

    $body = $dom->createElement('soap:Body'); $env->appendChild($body);
    $req  = $dom->createElementNS($NS_proc, 'proc:requestDetalharProcedimento'); $body->appendChild($req);
    $req->appendChild($dom->createElementNS($NS_proc1, 'proc1:codigoProcedimento', $codigoProcedimento));

    if (!empty($categorias)) {
        $detalhes = $dom->createElementNS($NS_proc, 'proc:DetalhesAdicionais');
        foreach ($categorias as $cat) {
            $nodeDet = $dom->createElementNS($NS_det, 'det:DetalheAdicional');
            $nodeDet->appendChild($dom->createElementNS($NS_det, 'det:categoriaDetalheAdicional', strtoupper(trim($cat))));
            $pag = $dom->createElementNS($NS_det, 'det:Paginacao');
            $pag->appendChild($dom->createElementNS($NS_pag, 'pag:registroInicial', (string)$registroInicial));
            $pag->appendChild($dom->createElementNS($NS_pag, 'pag:quantidadeRegistros', (string)$quantidadeRegistros));
            if ($totalRegistros !== null) {
                $pag->appendChild($dom->createElementNS($NS_pag, 'pag:totalRegistros', (string)$totalRegistros));
            }
            $nodeDet->appendChild($pag);
            $detalhes->appendChild($nodeDet);
        }
        $req->appendChild($detalhes);
    }

    $xml = $dom->saveXML();

    // ===== cURL com otimizações e retries =====
    $headers = [
        'Content-Type: application/soap+xml; charset=utf-8; action="requestDetalharProcedimento"',
        'Accept: application/soap+xml, text/xml, */*',
        'Accept-Encoding: gzip, deflate',
        'Connection: keep-alive',
        'User-Agent: SIGTAP-ClientePHP/1.0'
    ];

    $try = 0; $maxTry = 3; $waitBaseMs = 250;
    $resp = ['ok'=>false,'http'=>0,'erro'=>null,'xml'=>$xml,'xmlResposta'=>null,'dados'=>null];

    while ($try < $maxTry) {
        $try++;
        $ch = curl_init($endpoint);
        curl_setopt_array($ch, [
            CURLOPT_POST            => true,
            CURLOPT_HTTPHEADER      => $headers,
            CURLOPT_POSTFIELDS      => $xml,
            CURLOPT_RETURNTRANSFER  => true,
            CURLOPT_ENCODING        => '', // permite gzip/deflate
            CURLOPT_CONNECTTIMEOUT  => 10,
            CURLOPT_TIMEOUT         => 30,
            CURLOPT_SSL_VERIFYPEER  => false,
            CURLOPT_SSL_VERIFYHOST  => 2,
            CURLOPT_HTTP_VERSION    => defined('CURL_HTTP_VERSION_2TLS') ? CURL_HTTP_VERSION_2TLS : CURL_HTTP_VERSION_1_1,
        ]);

        $bodyResp = curl_exec($ch);
        $err      = curl_error($ch);
        $http     = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($bodyResp === false) {
            $resp['http'] = $http;
            $resp['erro'] = "Erro de transporte: $err";
        } elseif ($http >= 500) {
            $resp['http'] = $http;
            $resp['erro'] = "HTTP $http do serviço (erro temporário).";
        } else {
            // Temos resposta
            $resp['http'] = $http;
            $resp['xmlResposta'] = $bodyResp;

            if ($http < 200 || $http >= 300) {
                $resp['erro'] = "HTTP $http recebido do serviço.";
            }

            // Parse SOAP
            $sx = @simplexml_load_string($bodyResp);
            if ($sx !== false) {
                $sx->registerXPathNamespace('soap', $NS_soap);
                $sx->registerXPathNamespace('proc', $NS_proc);
                $sx->registerXPathNamespace('proc1',$NS_proc1);
                $sx->registerXPathNamespace('det',  $NS_det);

                $fault = $sx->xpath('//soap:Fault');
                if ($fault && count($fault)>0) {
                    $resp['erro'] = 'SOAP Fault retornado pelo serviço.';
                } else {
                    // Extração básica para caso DESCRICAO esteja presente
                    // (ajuste conforme sua necessidade; mantém genérico)
                    $descNodes = $sx->xpath('//*[local-name()="descricao" or local-name()="descricaoDetalhada"]');
                    $descricao = null;
                    if ($descNodes && isset($descNodes[0])) {
                        $descricao = trim((string)$descNodes[0]);
                    }

                    $resp['dados'] = [
                        'codigoProcedimento' => $codigoProcedimento,
                        'descricao'          => $descricao,
                    ];
                    if ($http >= 200 && $http < 300) {
                        $resp['ok'] = true;
                        $resp['erro'] = null;
                    }
                }
            } else {
                $resp['erro'] = $resp['erro'] ?: 'XML de resposta inválido.';
            }

            break; // temos resposta significativa; sai do loop
        }

        // backoff entre tentativas (apenas para erros de transporte/5xx)
        if ($try < $maxTry) {
            usleep(($waitBaseMs * $try) * 1000);
        }
    }

    return $resp;
}

/* ===== Exemplo mínimo (executa sempre, inclusive via navegador) ===== */
if (basename(__FILE__) === basename($_SERVER['SCRIPT_FILENAME'])) {
    header('Content-Type: text/plain; charset=utf-8');
    $r = sigtapDetalharProcedimento('0301010072', ['DESCRICAO']);
    echo "HTTP: {$r['http']}\n";
    echo "OK: " . ($r['ok'] ? 'true' : 'false') . "\n";
    if ($r['erro']) { echo "ERRO: {$r['erro']}\n"; }
    if ($r['dados']) { echo "DADOS:\n"; print_r($r['dados']); }
    if (!$r['ok'] && $r['xmlResposta']) {
        echo "\n--- Trecho da resposta ---\n";
        echo substr($r['xmlResposta'], 0, 1500), "\n";
    }
}
