<?php

declare(strict_types=1);

namespace App\Services\NFSe;

use Exception;

/**
 * Cliente HTTP para comunicação com API REST do Portal Nacional de NFS-e
 */
class NFSeNacionalClient
{
    private string $baseUrl;
    private ?NFSeNacionalAuthService $auth;
    private ?string $certificadoPath;
    private ?string $senhaCertificado;

    /**
     * @param NFSeNacionalAuthService|null $auth Service de autenticação OAuth2 (opcional)
     * @param bool $homologacao
     * @param string|null $certificadoPath Caminho do certificado digital (.pfx) - usado se não tiver OAuth2
     * @param string|null $senhaCertificado Senha do certificado - usado se não tiver OAuth2
     */
    public function __construct(?NFSeNacionalAuthService $auth = null, bool $homologacao = false, ?string $certificadoPath = null, ?string $senhaCertificado = null, ?string $proxyHost = null, ?int $proxyPort = null, ?string $proxyUser = null, ?string $proxyPass = null)
    {
        $this->auth = $auth;
        $this->certificadoPath = $certificadoPath;
        $this->senhaCertificado = $senhaCertificado;

        // URLs possíveis da API do Portal Nacional de NFS-e
        // Documentação: https://www.gov.br/nfse/pt-br/biblioteca/documentacao-tecnica
        // URL oficial produção: https://api.nfse.gov.br
        // URL alternativa mencionada: https://sefin.nfse.gov.br/API/SefinNacional
        // Homologação: https://api-hml.nfse.gov.br

        if ($homologacao) {
            $this->baseUrl = 'https://api-hml.nfse.gov.br';
        } else {
            // URL da API conforme Swagger: https://sefin.nfse.gov.br/SefinNacional/
            // Documentação: https://sefin.nfse.gov.br/SefinNacional/docs/index
            // BasePath: /SefinNacional/
            $this->baseUrl = 'https://sefin.nfse.gov.br/SefinNacional/';
            error_log("✅ Usando URL da API: {$this->baseUrl}");
            error_log("📚 Documentação: https://sefin.nfse.gov.br/SefinNacional/docs/index");
        }

        error_log("🔗 Portal Nacional NFS-e - Base URL configurada: {$this->baseUrl}");

        // Configurar proxy de saída se fornecido
        $this->proxyHost = $proxyHost;
        $this->proxyPort = $proxyPort;
        $this->proxyUser = $proxyUser;
        $this->proxyPass = $proxyPass;

        if ($this->proxyHost) {
            error_log("🔀 Proxy de saída configurado: {$this->proxyHost}:{$this->proxyPort}");
        }
    }

    /**
     * Emite NFS-e
     * Conforme Swagger: POST /nfse
     * Payload esperado: {"dpsXmlGZipB64": "..."} - DPS XML compactado em GZip e codificado em base64
     * Resposta: {"nfseXmlGZipB64": "...", "chaveAcesso": "...", "idDps": "..."}
     */
    public function emitirNfse(array $dadosNfse): array
    {
        // PRIMEIRO: Testar conectividade básica com a documentação Swagger
        // Se não conseguir acessar a documentação, não adianta tentar o endpoint
        $this->testarConectividade();

        // Endpoint conforme Swagger: POST /nfse
        // BasePath: /SefinNacional/
        // URL completa: https://sefin.nfse.gov.br/SefinNacional/nfse
        $url = rtrim($this->baseUrl, '/') . '/nfse';

        // Extrair host para resolução DNS
        $parsedUrl = parse_url($this->baseUrl);
        $host = $parsedUrl['host'] ?? 'sefin.nfse.gov.br';

        error_log("📡 Emitindo NFS-e via Portal Nacional");
        error_log("   Base URL: {$this->baseUrl}");
        error_log("   URL final: {$url}");
        error_log("   Host: {$host}");

        // Resolver DNS apenas para diagnóstico
        $ipResolved = $this->resolverDns($host);

        if ($ipResolved && $ipResolved !== $host) {
            error_log("✅ DNS resolvido: {$host} -> {$ipResolved}");
            error_log("ℹ️ Usando hostname diretamente (não IP) para garantir SNI correto no SSL/TLS");
        } else {
            error_log("⚠️ Não foi possível resolver DNS de {$host}. Tentando com hostname mesmo...");
        }

        // IMPORTANTE: Usar hostname diretamente, não IP
        // O servidor requer SNI (Server Name Indication) correto no SSL/TLS
        // Usar IP direto pode causar falha na negociação SSL
        // A URL já está com o hostname correto: https://sefin.nfse.gov.br/SefinNacional/nfse

        $ch = curl_init($url);

        $headers = [
            'Content-Type: application/json; charset=utf-8',
            'Accept: application/json',
            'User-Agent: Systhema-ERP/1.0',
            'Accept-Encoding: gzip, deflate',
            'Connection: keep-alive',
        ];

        // IMPORTANTE: Conforme Swagger, a API usa APENAS certificado digital (mutual TLS)
        // Não usa OAuth2! O certificado é enviado via CURLOPT_SSLCERT
        // Protocolo: TLS 1.0, TLS 1.1 e TLS 1.2 com autenticação mútua

        // Preparar payload conforme Swagger
        // A API espera: {"dpsXmlGZipB64": "..."} - DPS XML compactado em GZip e codificado em base64
        // Se $dadosNfse já tem 'dpsXmlGZipB64', usar direto
        // Senão, o NFSeNacionalService deve ter preparado isso
        $payload = $dadosNfse;
        if (!isset($dadosNfse['dpsXmlGZipB64'])) {
            error_log("⚠️ ATENÇÃO: Payload não contém 'dpsXmlGZipB64'. O NFSeNacionalService deve gerar o DPS XML primeiro.");
            error_log("⚠️ Estrutura esperada: {'dpsXmlGZipB64': 'DPS XML compactado em GZip e codificado em base64'}");
        } else {
            $dpsSize = strlen($dadosNfse['dpsXmlGZipB64']);
            error_log("✅ Payload preparado: dpsXmlGZipB64 com {$dpsSize} caracteres (base64)");
        }

        $curlOptions = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($payload),
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2, // Verificar hostname SSL (SNI será automático)
            CURLOPT_TIMEOUT => 120,
            CURLOPT_CONNECTTIMEOUT => 30, // Reduzir para detectar problemas mais rápido
            CURLOPT_DNS_CACHE_TIMEOUT => 0,
        ];

        // Configurar proxy de saída se disponível
        // IMPORTANTE: Proxy só funciona se o proxy suportar HTTPS tunneling e tiver IP liberado
        // Cloudflare NÃO funciona porque é proxy reverso (entrada), não saída
        if ($this->proxyHost && $this->proxyPort) {
            error_log("🔀 Usando proxy de saída: {$this->proxyHost}:{$this->proxyPort}");
            $curlOptions[CURLOPT_PROXY] = $this->proxyHost . ':' . $this->proxyPort;
            $curlOptions[CURLOPT_HTTPPROXYTUNNEL] = true; // Necessário para HTTPS através de proxy
            $curlOptions[CURLOPT_PROXYTYPE] = CURLPROXY_HTTP;

            if ($this->proxyUser && $this->proxyPass) {
                $curlOptions[CURLOPT_PROXYUSERPWD] = $this->proxyUser . ':' . $this->proxyPass;
                $curlOptions[CURLOPT_PROXYAUTH] = CURLAUTH_BASIC;
            }
        }

        // IMPORTANTE: Conforme Swagger, a API usa APENAS certificado digital (mutual TLS)
        // Protocolo: TLS 1.0, TLS 1.1 e TLS 1.2 com autenticação mútua
        // Certificado: ICP-Brasil, tipo A1 ou A3, CNPJ ou CPF, com "Autenticação Cliente"
        if ($this->certificadoPath && file_exists($this->certificadoPath)) {
            error_log("🔐 Usando certificado digital para autenticação mutual TLS");
            error_log("   Certificado: {$this->certificadoPath}");
            error_log("   Tamanho: " . filesize($this->certificadoPath) . " bytes");

            // Usar certificado .pfx diretamente no cURL
            $curlOptions[CURLOPT_SSLCERT] = $this->certificadoPath;
            $curlOptions[CURLOPT_SSLCERTPASSWD] = $this->senhaCertificado;
            $curlOptions[CURLOPT_SSLCERTTYPE] = 'P12';
            // Para P12, o mesmo arquivo contém cert e key
            $curlOptions[CURLOPT_SSLKEY] = $this->certificadoPath;
            $curlOptions[CURLOPT_SSLKEYPASSWD] = $this->senhaCertificado;
            $curlOptions[CURLOPT_SSLKEYTYPE] = 'P12';

            // Forçar versão TLS (conforme documentação: TLS 1.0, 1.1 e 1.2)
            // Usar TLS 1.2 que é o mais seguro e amplamente suportado
            $curlOptions[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_2;
        } else {
            error_log("⚠️ ATENÇÃO: Certificado digital não encontrado! A API requer certificado para autenticação mutual TLS.");
            error_log("   Caminho esperado: " . ($this->certificadoPath ?? 'NÃO CONFIGURADO'));
        }

        curl_setopt_array($ch, $curlOptions);

        error_log("🚀 Iniciando requisição cURL...");
        error_log("   URL: {$url}");
        error_log("   Método: POST");
        error_log("   Payload size: " . strlen(json_encode($payload)) . " bytes");
        error_log("   Timeout: 120s (conexão: 30s)");
        error_log("   Headers: " . count($headers) . " headers configurados");
        error_log("   Certificado: " . ($this->certificadoPath && file_exists($this->certificadoPath) ? 'SIM' : 'NÃO'));

        // Log dos headers (sem senhas)
        $headersLog = array_filter($headers, function ($h) {
            return stripos($h, 'password') === false && stripos($h, 'authorization') === false;
        });
        error_log("   Headers enviados: " . implode(', ', array_slice($headersLog, 0, 5)) . (count($headersLog) > 5 ? '...' : ''));

        $startTime = microtime(true);
        $response = curl_exec($ch);
        $endTime = microtime(true);
        $duration = round(($endTime - $startTime) * 1000, 2);

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $curlInfo = curl_getinfo($ch);

        error_log("📥 Resposta recebida em {$duration}ms");
        error_log("   HTTP Code: " . ($httpCode ?: 'N/A'));
        error_log("   Primary IP: " . ($curlInfo['primary_ip'] ?? 'N/A'));
        error_log("   Total Time: " . round($curlInfo['total_time'] ?? 0, 2) . "s");
        error_log("   Connect Time: " . round($curlInfo['connect_time'] ?? 0, 2) . "s");
        error_log("   SSL Verify Result: " . ($curlInfo['ssl_verify_result'] ?? 'N/A'));

        if ($error) {
            error_log("   ❌ cURL Error: {$error}");
        } else {
            error_log("   ✅ Sem erros cURL");
        }

        curl_close($ch);

        if ($error) {
            $errorDetails = "Erro cURL: $error";
            $errorDetails .= " | URL: " . $url;
            $errorDetails .= " | DNS IP: " . ($curlInfo['primary_ip'] ?? 'NÃO RESOLVIDO');
            $errorDetails .= " | HTTP Code: " . ($httpCode ?? 'N/A');

            error_log("❌ ERRO ao emitir NFS-e no Portal Nacional: {$errorDetails}");

            // Tentar resolver DNS manualmente para diagnóstico
            $host = parse_url($this->baseUrl, PHP_URL_HOST);
            $dnsResolved = @gethostbyname($host);
            $dnsInfo = ($dnsResolved === $host) ? 'DNS NÃO RESOLVIDO' : "DNS resolvido para: {$dnsResolved}";
            error_log("🔍 Diagnóstico DNS: {$dnsInfo}");

            // Se for erro de DNS e estiver em produção, tentar URL alternativa
            if (strpos($error, 'Could not resolve host') !== false || strpos($error, 'resolve') !== false) {
                $isHomologacao = strpos($this->baseUrl, 'hml') !== false || strpos($this->baseUrl, 'homolog') !== false;
                if (!$isHomologacao && $this->baseUrl === 'https://api.nfse.gov.br') {
                    error_log("⚠️ Tentando URLs alternativas...");
                    return $this->tentarUrlAlternativa($dadosNfse, '/nfse');
                }

                throw new Exception("Não foi possível conectar ao Portal Nacional de NFS-e (api.nfse.gov.br).\n\nO servidor não consegue resolver o DNS do domínio api.nfse.gov.br.\n\n🔧 Possíveis soluções:\n1. Verificar configurações de DNS do servidor\n2. Testar no servidor: nslookup api.nfse.gov.br\n3. Verificar se há proxy/firewall bloqueando\n4. Contatar administrador do servidor/hospedagem\n\n💡 Dica: Se você consegue acessar o Portal pelo navegador, o problema é específico do servidor.\n\nErro técnico: $error");
            }

            throw new Exception("Erro ao conectar ao Portal Nacional: $error");
        }

        $responseData = json_decode($response, true);

        // Conforme Swagger:
        // 201: NFS-e criada com sucesso
        // 400: Não foi possível criar a NFS-e
        // 403: Certificado digital inválido
        // 500: Falha durante processamento

        if ($httpCode === 201) {
            // Sucesso! Processar resposta
            // Resposta: {"nfseXmlGZipB64": "...", "chaveAcesso": "...", "idDps": "...", ...}
            error_log("✅ NFS-e criada com sucesso! HTTP 201");

            // Descompactar XML da NFS-e se disponível
            if (!empty($responseData['nfseXmlGZipB64'])) {
                try {
                    $xmlGzipB64 = $responseData['nfseXmlGZipB64'];
                    $xmlGzip = base64_decode($xmlGzipB64);
                    $xml = gzdecode($xmlGzip);
                    if ($xml) {
                        $responseData['nfse_xml'] = $xml;
                        error_log("✅ XML da NFS-e descompactado com sucesso");
                    }
                } catch (Exception $e) {
                    error_log("⚠️ Erro ao descompactar XML: " . $e->getMessage());
                }
            }

            return $responseData;
        } elseif ($httpCode === 400) {
            // Erro de validação/negócio
            $erroMsg = 'Não foi possível criar a NFS-e';
            if (isset($responseData['erros']) && is_array($responseData['erros'])) {
                $mensagens = [];
                foreach ($responseData['erros'] as $erro) {
                    $mensagens[] = $erro['mensagem'] ?? $erro['descricao'] ?? json_encode($erro);
                }
                $erroMsg .= ': ' . implode('; ', $mensagens);
            }
            throw new Exception($erroMsg);
        } elseif ($httpCode === 403) {
            throw new Exception("Certificado digital inválido ou fora dos padrões da NFS-e. Verifique se o certificado está correto e tem 'Autenticação Cliente'.");
        } elseif ($httpCode === 500) {
            $erroMsg = 'Falha durante o processamento do DPS';
            if (isset($responseData['erros']) && is_array($responseData['erros'])) {
                $mensagens = [];
                foreach ($responseData['erros'] as $erro) {
                    $mensagens[] = $erro['mensagem'] ?? $erro['descricao'] ?? json_encode($erro);
                }
                $erroMsg .= ': ' . implode('; ', $mensagens);
            }
            throw new Exception($erroMsg);
        } else {
            $errorMessage = $responseData['message'] ?? $responseData['error'] ?? "Erro HTTP $httpCode";
            $errorDetails = isset($responseData['errors']) ? json_encode($responseData['errors']) : '';
            throw new Exception("Erro ao emitir NFS-e: $errorMessage" . ($errorDetails ? " - Detalhes: $errorDetails" : ''));
        }
    }

    /**
     * Consulta NFS-e por número
     */
    public function consultarNfse(string $numeroNfse, ?string $codigoVerificacao = null): array
    {
        $url = $this->baseUrl . '/nfse/' . $numeroNfse;
        if ($codigoVerificacao) {
            $url .= '?codigo_verificacao=' . urlencode($codigoVerificacao);
        }

        $ch = curl_init($url);

        $headers = [
            'Accept: application/json',
        ];

        // Se tem OAuth2, adiciona token Bearer
        if ($this->auth) {
            $token = $this->auth->obterToken();
            $headers[] = 'Authorization: Bearer ' . $token;
        }

        $curlOptions = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_TIMEOUT => 30,
        ];

        // Se não tem OAuth2 mas tem certificado, usa certificado para autenticação (mutual TLS)
        if (!$this->auth && $this->certificadoPath && file_exists($this->certificadoPath)) {
            // Usar certificado .pfx diretamente no cURL
            $curlOptions[CURLOPT_SSLCERT] = $this->certificadoPath;
            $curlOptions[CURLOPT_SSLCERTPASSWD] = $this->senhaCertificado;
            $curlOptions[CURLOPT_SSLCERTTYPE] = 'P12';
            // Para P12, o mesmo arquivo contém cert e key
            $curlOptions[CURLOPT_SSLKEY] = $this->certificadoPath;
            $curlOptions[CURLOPT_SSLKEYPASSWD] = $this->senhaCertificado;
            $curlOptions[CURLOPT_SSLKEYTYPE] = 'P12';
        }

        curl_setopt_array($ch, $curlOptions);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $curlInfo = curl_getinfo($ch);
        curl_close($ch);

        if ($error) {
            $errorDetails = "Erro cURL: $error";
            $errorDetails .= " | URL: " . $url;
            $errorDetails .= " | DNS IP: " . ($curlInfo['primary_ip'] ?? 'NÃO RESOLVIDO');

            error_log("❌ ERRO ao consultar NFS-e no Portal Nacional: {$errorDetails}");

            if (strpos($error, 'Could not resolve host') !== false) {
                throw new Exception("Não foi possível conectar ao Portal Nacional de NFS-e. Verifique a conectividade. Erro: $error");
            }

            throw new Exception("Erro ao conectar ao Portal Nacional: $error");
        }

        if ($httpCode !== 200) {
            $errorData = json_decode($response, true);
            $errorMessage = $errorData['message'] ?? $errorData['error'] ?? "Erro HTTP $httpCode";
            throw new Exception("Erro ao consultar NFS-e: $errorMessage");
        }

        return json_decode($response, true);
    }

    /**
     * Cancela NFS-e
     */
    public function cancelarNfse(string $numeroNfse, string $codigoVerificacao, string $motivo): array
    {
        $ch = curl_init($this->baseUrl . '/nfse/' . $numeroNfse . '/cancelar');

        $headers = [
            'Content-Type: application/json',
            'Accept: application/json',
        ];

        // Se tem OAuth2, adiciona token Bearer
        if ($this->auth) {
            $token = $this->auth->obterToken();
            $headers[] = 'Authorization: Bearer ' . $token;
        }

        $curlOptions = [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode([
                'codigo_verificacao' => $codigoVerificacao,
                'motivo' => $motivo,
            ]),
            CURLOPT_HTTPHEADER => $headers,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_TIMEOUT => 30,
        ];

        // Se não tem OAuth2 mas tem certificado, usa certificado para autenticação (mutual TLS)
        if (!$this->auth && $this->certificadoPath && file_exists($this->certificadoPath)) {
            // Usar certificado .pfx diretamente no cURL
            $curlOptions[CURLOPT_SSLCERT] = $this->certificadoPath;
            $curlOptions[CURLOPT_SSLCERTPASSWD] = $this->senhaCertificado;
            $curlOptions[CURLOPT_SSLCERTTYPE] = 'P12';
            // Para P12, o mesmo arquivo contém cert e key
            $curlOptions[CURLOPT_SSLKEY] = $this->certificadoPath;
            $curlOptions[CURLOPT_SSLKEYPASSWD] = $this->senhaCertificado;
            $curlOptions[CURLOPT_SSLKEYTYPE] = 'P12';
        }

        curl_setopt_array($ch, $curlOptions);

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $curlInfo = curl_getinfo($ch);
        curl_close($ch);

        if ($error) {
            $errorDetails = "Erro cURL: $error";
            $errorDetails .= " | URL: " . $this->baseUrl . '/nfse/' . $numeroNfse . '/cancelar';
            $errorDetails .= " | DNS IP: " . ($curlInfo['primary_ip'] ?? 'NÃO RESOLVIDO');

            error_log("❌ ERRO ao cancelar NFS-e no Portal Nacional: {$errorDetails}");

            if (strpos($error, 'Could not resolve host') !== false) {
                throw new Exception("Não foi possível conectar ao Portal Nacional de NFS-e. Verifique a conectividade. Erro: $error");
            }

            throw new Exception("Erro ao conectar ao Portal Nacional: $error");
        }

        if ($httpCode !== 200) {
            $errorData = json_decode($response, true);
            $errorMessage = $errorData['message'] ?? $errorData['error'] ?? "Erro HTTP $httpCode";
            throw new Exception("Erro ao cancelar NFS-e: $errorMessage");
        }

        return json_decode($response, true);
    }

    /**
     * Tenta resolver DNS usando servidores DNS públicos (para contornar problema de DNS do servidor)
     */
    private function resolverDnsPublico(string $hostname): ?string
    {
        // Tentar com servidores DNS públicos primeiro (mais confiável)
        $dnsServers = ['8.8.8.8', '8.8.4.4', '1.1.1.1', '1.0.0.1'];
        foreach ($dnsServers as $dnsServer) {
            $ip = $this->resolverDnsComServidor($hostname, $dnsServer);
            if ($ip) {
                return $ip;
            }
        }

        // Fallback: métodos padrão do sistema
        $ip = @gethostbyname($hostname);
        if ($ip && $ip !== $hostname) {
            return $ip;
        }

        if (function_exists('dns_get_record')) {
            $records = @dns_get_record($hostname, DNS_A);
            if (!empty($records) && isset($records[0]['ip'])) {
                return $records[0]['ip'];
            }
        }

        return null;
    }

    /**
     * Tenta resolver DNS usando diferentes métodos
     */
    private function resolverDns(string $hostname): ?string
    {
        // Usar método público primeiro
        $ip = $this->resolverDnsPublico($hostname);
        if ($ip) {
            return $ip;
        }

        return null;
    }

    /**
     * Resolve DNS usando um servidor DNS específico
     */
    private function resolverDnsComServidor(string $hostname, string $dnsServer): ?string
    {
        // Usar nslookup via exec (se disponível)
        if (function_exists('exec')) {
            $command = "nslookup {$hostname} {$dnsServer} 2>&1";
            @exec($command, $output, $returnCode);

            if ($returnCode === 0 && !empty($output)) {
                foreach ($output as $line) {
                    if (preg_match('/Address:\s+(\d+\.\d+\.\d+\.\d+)/', $line, $matches)) {
                        $ip = $matches[1];
                        // Ignorar o IP do servidor DNS
                        if ($ip !== $dnsServer) {
                            return $ip;
                        }
                    }
                }
            }
        }

        return null;
    }

    /**
     * Tenta usar URL alternativa quando a principal falha
     */
    private function tentarUrlAlternativa(array $dadosNfse, string $endpoint): array
    {
        // URLs alternativas para testar (base URL sem endpoint)
        // URLs e endpoints alternativos para testar
        // sefin.nfse.gov.br conseguiu resolver DNS (retornou 404, não erro de DNS)
        $urlsAlternativas = [
            'https://sefin.nfse.gov.br/API/SefinNacional/nfse',
            'https://sefin.nfse.gov.br/API/SefinNacional/emitir',
            'https://sefin.nfse.gov.br/API/SefinNacional',
            'https://sefin.nfse.gov.br/api/nfse',
            'https://api.nfse.gov.br/nfse', // URL oficial (pode não resolver DNS)
        ];

        foreach ($urlsAlternativas as $urlAlt) {
            error_log("🔄 Tentando URL alternativa: {$urlAlt}");

            try {
                $ch = curl_init($urlAlt);

                $headers = [
                    'Content-Type: application/json',
                    'Accept: application/json',
                ];

                if ($this->auth) {
                    $token = $this->auth->obterToken();
                    $headers[] = 'Authorization: Bearer ' . $token;
                }

                $curlOptions = [
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_POST => true,
                    CURLOPT_POSTFIELDS => json_encode($dadosNfse),
                    CURLOPT_HTTPHEADER => $headers,
                    CURLOPT_SSL_VERIFYPEER => true,
                    CURLOPT_SSL_VERIFYHOST => 2,
                    CURLOPT_TIMEOUT => 60,
                    CURLOPT_CONNECTTIMEOUT => 30,
                ];

                if (!$this->auth && $this->certificadoPath && file_exists($this->certificadoPath)) {
                    $curlOptions[CURLOPT_SSLCERT] = $this->certificadoPath;
                    $curlOptions[CURLOPT_SSLCERTPASSWD] = $this->senhaCertificado;
                    $curlOptions[CURLOPT_SSLCERTTYPE] = 'P12';
                    $curlOptions[CURLOPT_SSLKEY] = $this->certificadoPath;
                    $curlOptions[CURLOPT_SSLKEYPASSWD] = $this->senhaCertificado;
                    $curlOptions[CURLOPT_SSLKEYTYPE] = 'P12';
                }

                curl_setopt_array($ch, $curlOptions);

                $response = curl_exec($ch);
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                $error = curl_error($ch);
                curl_close($ch);

                if (!$error && $httpCode >= 200 && $httpCode < 300) {
                    error_log("✅ URL alternativa funcionou: {$urlAlt}");
                    $responseData = json_decode($response, true);
                    if ($responseData) {
                        return $responseData;
                    }
                } else {
                    error_log("❌ URL alternativa falhou: {$urlAlt} - {$error} (HTTP {$httpCode})");
                }
            } catch (Exception $e) {
                error_log("❌ Erro ao tentar URL alternativa {$urlAlt}: " . $e->getMessage());
            }
        }

        throw new Exception("Todas as URLs testadas falharam. Não foi possível conectar ao Portal Nacional de NFS-e.");
    }

    /**
     * Tenta diferentes endpoints na mesma base URL
     */
    private function tentarEndpoints(array $dadosNfse, array $endpoints): array
    {
        // Primeiro, tentar consultar Swagger para descobrir endpoints corretos
        $this->consultarSwaggerDocs();

        foreach ($endpoints as $endpoint) {
            $url = $this->baseUrl . $endpoint;
            error_log("🔄 Tentando endpoint: {$url} (método POST)");

            try {
                $parsedUrl = parse_url($this->baseUrl);
                $host = $parsedUrl['host'] ?? parse_url($this->baseUrl, PHP_URL_HOST);

                // Resolver DNS
                $ipResolved = $this->resolverDns($host);
                if ($ipResolved && $ipResolved !== $host) {
                    $url = str_replace($host, $ipResolved, $url);
                }

                $ch = curl_init($url);

                $headers = [
                    'Content-Type: application/json',
                    'Accept: application/json',
                ];

                if ($this->auth) {
                    $token = $this->auth->obterToken();
                    $headers[] = 'Authorization: Bearer ' . $token;
                }

                $curlOptions = [
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_POST => true,
                    CURLOPT_POSTFIELDS => json_encode($dadosNfse),
                    CURLOPT_HTTPHEADER => $headers,
                    CURLOPT_SSL_VERIFYPEER => true,
                    CURLOPT_SSL_VERIFYHOST => 2,
                    CURLOPT_TIMEOUT => 60,
                    CURLOPT_CONNECTTIMEOUT => 30,
                ];

                // Se está usando IP direto (baseUrl é um IP), adicionar header Host
                if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', parse_url($this->baseUrl, PHP_URL_HOST) ?? '')) {
                    // Base URL é um IP, precisamos do hostname original
                    $originalHost = 'api.nfse.gov.br';
                    $headers[] = 'Host: ' . $originalHost;
                    $curlOptions[CURLOPT_HTTPHEADER] = $headers;
                    $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0; // Desabilitar verificação de hostname quando usar IP
                    error_log("🔧 Usando IP direto, adicionando header Host: {$originalHost}");
                } elseif ($ipResolved && $ipResolved !== $host) {
                    $headers[] = 'Host: ' . $host;
                    $curlOptions[CURLOPT_HTTPHEADER] = $headers;
                    $curlOptions[CURLOPT_SSL_VERIFYHOST] = 0;
                }

                if (!$this->auth && $this->certificadoPath && file_exists($this->certificadoPath)) {
                    $curlOptions[CURLOPT_SSLCERT] = $this->certificadoPath;
                    $curlOptions[CURLOPT_SSLCERTPASSWD] = $this->senhaCertificado;
                    $curlOptions[CURLOPT_SSLCERTTYPE] = 'P12';
                    $curlOptions[CURLOPT_SSLKEY] = $this->certificadoPath;
                    $curlOptions[CURLOPT_SSLKEYPASSWD] = $this->senhaCertificado;
                    $curlOptions[CURLOPT_SSLKEYTYPE] = 'P12';
                }

                curl_setopt_array($ch, $curlOptions);

                $response = curl_exec($ch);
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                $error = curl_error($ch);
                curl_close($ch);

                if (!$error && $httpCode >= 200 && $httpCode < 300) {
                    error_log("✅ Endpoint funcionou: {$url} (HTTP {$httpCode})");
                    $responseData = json_decode($response, true);
                    if ($responseData) {
                        return $responseData;
                    }
                } elseif ($httpCode === 404) {
                    error_log("❌ Endpoint não encontrado (404): {$url}");
                    // Se retornou 404 mas não erro de conexão, significa que o servidor existe
                    // mas o endpoint está errado - continuar testando outros
                } elseif ($httpCode === 405) {
                    error_log("⚠️ Método não permitido (405): {$url} - pode ser que o endpoint exista mas não aceite POST");
                } elseif ($httpCode === 401 || $httpCode === 403) {
                    error_log("⚠️ Endpoint encontrado mas sem autenticação/autorização (HTTP {$httpCode}): {$url}");
                    // Endpoint existe! Mas precisa de autenticação - isso é progresso
                    // Retornar erro específico sobre autenticação
                    throw new Exception("Endpoint encontrado mas requer autenticação. HTTP {$httpCode}. URL: {$url}. Verifique se o certificado digital ou OAuth2 está configurado corretamente.");
                } else {
                    error_log("❌ Endpoint falhou: {$url} - {$error} (HTTP {$httpCode})");
                    if ($httpCode > 0) {
                        // Se tem código HTTP, significa que conectou mas deu erro
                        // Pode ser que o endpoint exista mas tenha outro problema
                        error_log("💡 Servidor respondeu (HTTP {$httpCode}), endpoint pode existir mas com problema diferente");
                    }
                }
            } catch (Exception $e) {
                error_log("❌ Erro ao tentar endpoint {$url}: " . $e->getMessage());
            }
        }

        throw new Exception("Nenhum endpoint funcionou. Todos retornaram erro (404 ou outro). Verifique a documentação da API.");
    }

    /**
     * Testa conectividade básica com o servidor antes de fazer requisições
     * Tenta acessar a documentação Swagger para verificar se o servidor está acessível
     * IMPORTANTE: O servidor pode exigir certificado digital mesmo para documentação
     */
    private function testarConectividade(): void
    {
        $swaggerUrl = 'https://sefin.nfse.gov.br/SefinNacional/docs/index';

        error_log("🔍 Testando conectividade com o servidor...");
        error_log("   URL de teste: {$swaggerUrl}");

        // Primeiro, tentar sem certificado (para documentação pública)
        $ch = curl_init($swaggerUrl);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_NOBODY => true, // HEAD request apenas
            CURLOPT_TIMEOUT => 10,
            CURLOPT_CONNECTTIMEOUT => 5,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_FOLLOWLOCATION => true,
        ]);

        $startTime = microtime(true);
        $result = curl_exec($ch);
        $endTime = microtime(true);

        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        $curlInfo = curl_getinfo($ch);
        $duration = round(($endTime - $startTime) * 1000, 2);

        curl_close($ch);

        // Se falhou sem certificado, tentar COM certificado (mutual TLS pode ser obrigatório)
        if ($error && $this->certificadoPath && file_exists($this->certificadoPath)) {
            error_log("   ⚠️ Falha sem certificado. Tentando COM certificado digital (mutual TLS)...");

            $ch = curl_init($swaggerUrl);
            curl_setopt_array($ch, [
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_NOBODY => true,
                CURLOPT_TIMEOUT => 10,
                CURLOPT_CONNECTTIMEOUT => 5,
                CURLOPT_SSL_VERIFYPEER => true,
                CURLOPT_SSL_VERIFYHOST => 2,
                CURLOPT_FOLLOWLOCATION => true,
                CURLOPT_SSLCERT => $this->certificadoPath,
                CURLOPT_SSLCERTPASSWD => $this->senhaCertificado,
                CURLOPT_SSLCERTTYPE => 'P12',
                CURLOPT_SSLKEY => $this->certificadoPath,
                CURLOPT_SSLKEYPASSWD => $this->senhaCertificado,
                CURLOPT_SSLKEYTYPE => 'P12',
            ]);

            $startTime = microtime(true);
            $result = curl_exec($ch);
            $endTime = microtime(true);

            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            $error = curl_error($ch);
            $curlInfo = curl_getinfo($ch);
            $duration = round(($endTime - $startTime) * 1000, 2);

            curl_close($ch);
        }

        if ($error) {
            error_log("   ❌ Erro ao testar conectividade: {$error}");
            error_log("   ⚠️ ATENÇÃO: Não foi possível conectar ao servidor!");
            error_log("   🔍 Diagnóstico detalhado:");
            error_log("      - Connect Time: " . round($curlInfo['connect_time'] ?? 0, 2) . "s");
            error_log("      - Primary IP: " . ($curlInfo['primary_ip'] ?? 'NÃO CONECTADO'));
            error_log("      - SSL Verify Result: " . ($curlInfo['ssl_verify_result'] ?? 'N/A'));

            // Verificar se é timeout de conexão (bloqueio de IP) ou outro erro
            if (strpos($error, 'timeout') !== false && ($curlInfo['connect_time'] ?? 0) == 0) {
                error_log("   🚨 PROBLEMA IDENTIFICADO: Timeout na conexão TCP (Connect Time = 0s)");
                error_log("   🚨 Isso indica BLOQUEIO DE IP ou problema de rede/firewall");
                error_log("   💡 SOLUÇÕES POSSÍVEIS:");
                error_log("      1. Verificar se o IP do servidor está na whitelist do Portal Nacional");
                error_log("      2. Contatar suporte do Portal Nacional para liberar o IP");
                error_log("      3. Usar proxy/VPN se disponível");
                error_log("      4. Verificar configurações de firewall/proxy do servidor");
                throw new Exception("BLOQUEIO DE CONEXÃO: O servidor não está respondendo às tentativas de conexão TCP. Isso geralmente indica bloqueio de IP ou problema de rede/firewall. Contate o suporte do Portal Nacional de NFS-e para verificar se o IP do servidor está autorizado.");
            } else {
                error_log("   ⚠️ Outro tipo de erro (não é bloqueio de IP):");
                error_log("      - Problema de rede/firewall");
                error_log("      - Servidor em manutenção");
                error_log("      - Certificado digital inválido");
                throw new Exception("Não foi possível estabelecer conexão com o Portal Nacional de NFS-e. Erro: {$error}");
            }
        } else {
            error_log("   ✅ Conectividade OK! HTTP {$httpCode} em {$duration}ms");
            error_log("   ✅ Primary IP: " . ($curlInfo['primary_ip'] ?? 'N/A'));
            error_log("   ✅ Connect Time: " . round($curlInfo['connect_time'] ?? 0, 2) . "s");
        }
    }

    /**
     * Consulta documentação Swagger para descobrir endpoints corretos
     */
    private function consultarSwaggerDocs(): void
    {
        if (strpos($this->baseUrl, '/SefinNacional') === false) {
            return; // Só funciona para sefin.nfse.gov.br
        }

        $swaggerUrl = 'https://sefin.nfse.gov.br/SefinNacional/docs/index';
        $swaggerJsonUrl = 'https://sefin.nfse.gov.br/SefinNacional/docs/swagger.json';
        $swaggerYamlUrl = 'https://sefin.nfse.gov.br/SefinNacional/docs/swagger.yaml';

        $urlsParaTestar = [$swaggerJsonUrl, $swaggerYamlUrl];

        foreach ($urlsParaTestar as $urlDoc) {
            try {
                $parsedUrl = parse_url($this->baseUrl);
                $host = $parsedUrl['host'] ?? 'sefin.nfse.gov.br';

                $ipResolved = $this->resolverDns($host);
                if ($ipResolved && $ipResolved !== $host) {
                    $urlDoc = str_replace($host, $ipResolved, $urlDoc);
                }

                $ch = curl_init($urlDoc);
                curl_setopt_array($ch, [
                    CURLOPT_RETURNTRANSFER => true,
                    CURLOPT_HTTPHEADER => ['Accept: application/json'],
                    CURLOPT_TIMEOUT => 5,
                    CURLOPT_CONNECTTIMEOUT => 3,
                ]);

                if ($ipResolved && $ipResolved !== $host) {
                    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Accept: application/json', 'Host: ' . $host]);
                    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
                }

                $response = curl_exec($ch);
                $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_close($ch);

                if ($httpCode === 200 && $response) {
                    $swagger = json_decode($response, true);
                    if ($swagger && isset($swagger['paths'])) {
                        error_log("📚 Swagger encontrado! Endpoints disponíveis:");
                        foreach ($swagger['paths'] as $path => $methods) {
                            error_log("  - {$path}: " . implode(', ', array_keys($methods)));
                        }
                    }
                }
            } catch (Exception $e) {
                // Ignorar erros
            }
        }
    }
}
