<?php
namespace Modules\Fiscal\Services;

use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Tenant\TenantContext;
use PDO;
use Exception;

/**
 * Serviço para integração com SEFAZ (Consultas e Download de XML)
 */
class SEFAZService {
    private PDO $pdo;
    private string $tenantId;
    private array $endpoints = [
        'AC' => ['producao' => 'https://nfe.sefaznet.ac.gov.br/nfe/ws/services/NfeConsulta4', 'homologacao' => 'https://hml.nfe.sefaznet.ac.gov.br/nfe/ws/services/NfeConsulta4'],
        'AL' => ['producao' => 'https://nfe.sefaz.al.gov.br/ws/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.al.gov.br/ws/services/NfeConsulta4'],
        'AP' => ['producao' => 'https://nfe.sefaz.ap.gov.br/nfe/ws/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.ap.gov.br/nfe/ws/services/NfeConsulta4'],
        'AM' => ['producao' => 'https://nfe.sefaz.am.gov.br/services2/services/NfeConsulta4', 'homologacao' => 'https://homnfe.sefaz.am.gov.br/services2/services/NfeConsulta4'],
        'BA' => ['producao' => 'https://nfe.sefaz.ba.gov.br/webservices/NfeConsulta/NfeConsulta4.asmx', 'homologacao' => 'https://hnfe.sefaz.ba.gov.br/webservices/NfeConsulta/NfeConsulta4.asmx'],
        'CE' => ['producao' => 'https://nfe.sefaz.ce.gov.br/nfe4/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.ce.gov.br/nfe4/services/NfeConsulta4'],
        'DF' => ['producao' => 'https://www.nfe.fazenda.gov.br/NfeConsulta4', 'homologacao' => 'https://hom.nfe.fazenda.gov.br/NfeConsulta4'],
        'ES' => ['producao' => 'https://nfe.sefaz.es.gov.br/ws/NfeConsulta4', 'homologacao' => 'https://homologacao.nfe.sefaz.es.gov.br/ws/NfeConsulta4'],
        'GO' => ['producao' => 'https://nfe.sefaz.go.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://homolog.sefaz.go.gov.br/nfe/services/NfeConsulta4'],
        'MA' => ['producao' => 'https://nfe.sefaz.ma.gov.br/webservices/NfeConsulta4', 'homologacao' => 'https://homologacao.sefaz.ma.gov.br/webservices/NfeConsulta4'],
        'MT' => ['producao' => 'https://nfe.sefaz.mt.gov.br/nfews/v2/services/NfeConsulta4', 'homologacao' => 'https://homologacao.sefaz.mt.gov.br/nfews/v2/services/NfeConsulta4'],
        'MS' => ['producao' => 'https://nfe.sefaz.ms.gov.br/ws/NfeConsulta4', 'homologacao' => 'https://homologacao.nfe.ms.gov.br/ws/NfeConsulta4'],
        'MG' => ['producao' => 'https://nfe.fazenda.mg.gov.br/nfe2/services/NfeConsulta4', 'homologacao' => 'https://hnfe.fazenda.mg.gov.br/nfe2/services/NfeConsulta4'],
        'PA' => ['producao' => 'https://nfe.sefaz.pa.gov.br/nfe/ws/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.pa.gov.br/nfe/ws/services/NfeConsulta4'],
        'PB' => ['producao' => 'https://nfe.sefaz.pb.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.pb.gov.br/nfe/services/NfeConsulta4'],
        'PR' => ['producao' => 'https://nfe.fazenda.pr.gov.br/nfe/NFeConsulta4', 'homologacao' => 'https://homologacao.nfe.fazenda.pr.gov.br/nfe/NFeConsulta4'],
        'PE' => ['producao' => 'https://nfe.sefaz.pe.gov.br/nfe-service/services/NfeConsulta4', 'homologacao' => 'https://nfehomolog.sefaz.pe.gov.br/nfe-service/services/NfeConsulta4'],
        'PI' => ['producao' => 'https://nfe.sefaz.pi.gov.br/nfe/ws/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.pi.gov.br/nfe/ws/services/NfeConsulta4'],
        'RJ' => ['producao' => 'https://nfe.fazenda.rj.gov.br/NfeConsulta4', 'homologacao' => 'https://homologacao.nfe.fazenda.rj.gov.br/NfeConsulta4'],
        'RN' => ['producao' => 'https://nfe.set.rn.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://homologacao.nfe.set.rn.gov.br/nfe/services/NfeConsulta4'],
        'RS' => ['producao' => 'https://nfe.sefaz.rs.gov.br/ws/NfeConsulta/NfeConsulta4.asmx', 'homologacao' => 'https://nfe-homologacao.sefaz.rs.gov.br/ws/NfeConsulta/NfeConsulta4.asmx'],
        'RO' => ['producao' => 'https://nfe.sefaz.ro.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://nfehomologacao.sefaz.ro.gov.br/nfe/services/NfeConsulta4'],
        'RR' => ['producao' => 'https://nfe.sefaz.rr.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.rr.gov.br/nfe/services/NfeConsulta4'],
        'SC' => ['producao' => 'https://nfe.ssefaz.sc.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://homologacao.nfe.ssefaz.sc.gov.br/nfe/services/NfeConsulta4'],
        'SP' => ['producao' => 'https://nfe.fazenda.sp.gov.br/ws/nfeconsulta4.asmx', 'homologacao' => 'https://homologacao.nfe.fazenda.sp.gov.br/ws/nfeconsulta4.asmx'],
        'SE' => ['producao' => 'https://nfe.sefaz.se.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.se.gov.br/nfe/services/NfeConsulta4'],
        'TO' => ['producao' => 'https://nfe.sefaz.to.gov.br/nfe/services/NfeConsulta4', 'homologacao' => 'https://nfehml.sefaz.to.gov.br/nfe/services/NfeConsulta4'],
    ];

    public function __construct() {
        $this->pdo = ConnectionManager::forTenant();
        $this->tenantId = TenantContext::getTenantId();
    }

    /**
     * Consulta NFe por chave de acesso
     */
    public function consultarNFe(string $chave, string $ambiente = 'producao'): array {
        if (strlen($chave) !== 44 || !ctype_digit($chave)) {
            throw new Exception('Chave de acesso inválida. Deve ter 44 dígitos numéricos.');
        }

        // Extrair UF da chave (posições 0-1)
        $uf = substr($chave, 0, 2);
        $ufCode = $this->getUfCode($uf);

        if (!$ufCode || !isset($this->endpoints[$ufCode])) {
            throw new Exception("UF não suportada ou inválida: $uf");
        }

        $endpoint = $this->endpoints[$ufCode][$ambiente] ?? $this->endpoints[$ufCode]['producao'];

        try {
            // Construir SOAP request
            $tpAmb = $ambiente === 'homologacao' ? '2' : '1';
            $soapRequest = $this->buildConsultaSoapRequest($chave, $tpAmb);
            
            // Fazer requisição SOAP
            $xmlResponse = $this->makeSoapRequest($endpoint, $soapRequest);
            
            // Processar resposta
            return $this->parseConsultaResponse($xmlResponse, $chave);
        } catch (Exception $e) {
            throw new Exception('Erro ao consultar SEFAZ: ' . $e->getMessage());
        }
    }

    /**
     * Download XML da NFe por chave de acesso
     * Nota: Requer certificado digital para produção
     */
    public function downloadXml(string $chave, string $ambiente = 'producao'): string {
        try {
            // Primeiro consultar para obter dados
            $consulta = $this->consultarNFe($chave, $ambiente);
            
            if ($consulta['status'] !== 'autorizada') {
                throw new Exception('Nota fiscal não autorizada ou cancelada: ' . $consulta['motivo']);
            }

            // Se XML já veio na consulta, validar e retornar
            if (!empty($consulta['xml'])) {
                // Validar se é um XML válido de NFe
                $xml = $consulta['xml'];
                if ($this->validarXmlNFe($xml, $chave)) {
                    return $xml;
                }
            }

            // Tentar usar NFeDistribuicaoDFe se disponível
            try {
                $xml = $this->downloadXmlDistribuicaoDFe($chave, $ambiente);
                if ($xml) {
                    return $xml;
                }
            } catch (Exception $e) {
                // Se falhar, continuar com outros métodos
                error_log("Erro ao tentar download via NFeDistribuicaoDFe: " . $e->getMessage());
            }

            // Se não conseguir obter XML, retornar erro informativo
            throw new Exception('XML da nota fiscal não disponível. O download requer certificado digital e integração com NFeDistribuicaoDFe. Use importação manual de XML ou configure webhook para recebimento automático.');
        } catch (Exception $e) {
            throw $e;
        }
    }

    /**
     * Valida se o XML é uma NFe válida com a chave especificada
     */
    private function validarXmlNFe(string $xml, string $chave): bool {
        try {
            $dom = new \DOMDocument();
            if (!@$dom->loadXML($xml)) {
                return false;
            }

            $xpath = new \DOMXPath($dom);
            $xpath->registerNamespace('nfe', 'http://www.portalfiscal.inf.br/nfe');
            
            // Verificar se contém a chave correta
            $chaveNoXml = $xpath->query('//nfe:infNFe/@Id | //infNFe/@Id')->item(0)?->nodeValue ?? '';
            $chaveNoXml = str_replace('NFe', '', $chaveNoXml);
            
            return $chaveNoXml === $chave || !empty($chaveNoXml);
        } catch (\Exception $e) {
            return false;
        }
    }

    /**
     * Download XML usando NFeDistribuicaoDFe
     * Nota: Requer certificado digital configurado
     */
    private function downloadXmlDistribuicaoDFe(string $chave, string $ambiente = 'producao'): ?string {
        // Endpoints NFeDistribuicaoDFe
        $endpoints = [
            'producao' => 'https://www.nfe.fazenda.gov.br/NFeDistribuicaoDFe/NFeDistribuicaoDFe.asmx',
            'homologacao' => 'https://hom.nfe.fazenda.gov.br/NFeDistribuicaoDFe/NFeDistribuicaoDFe.asmx'
        ];

        $endpoint = $endpoints[$ambiente] ?? $endpoints['producao'];
        $cnpj = $this->obterCnpjEmpresa();
        
        if (empty($cnpj)) {
            throw new Exception('CNPJ da empresa não configurado');
        }

        // Construir requisição SOAP para NFeDistribuicaoDFe
        $ultNSU = $this->obterUltimoNSU($cnpj);
        $tpAmb = $ambiente === 'homologacao' ? '2' : '1';
        
        $soapRequest = $this->buildDistribuicaoDFeSoapRequest($cnpj, $ultNSU, $tpAmb);

        try {
            // Fazer requisição SOAP com certificado (se configurado)
            $xmlResponse = $this->makeSoapRequestComCertificado($endpoint, $soapRequest);
            
            // Processar resposta e buscar XML da chave
            $xml = $this->processarDistribuicaoDFeResponse($xmlResponse, $chave);
            
            if ($xml) {
                return $xml;
            }
        } catch (\Exception $e) {
            // Log do erro mas não lançar exceção (método alternativo)
            error_log("Erro ao buscar XML via NFeDistribuicaoDFe: " . $e->getMessage());
        }

        return null;
    }

    /**
     * Obtém CNPJ da empresa
     */
    private function obterCnpjEmpresa(): string {
        try {
            $stmt = $this->pdo->query('SELECT cnpj FROM empresas ORDER BY id ASC LIMIT 1');
            $empresa = $stmt->fetch(PDO::FETCH_ASSOC);
            return $empresa['cnpj'] ?? '';
        } catch (\Exception $e) {
            return '';
        }
    }

    /**
     * Obtém último NSU processado (para NFeDistribuicaoDFe)
     */
    private function obterUltimoNSU(string $cnpj): string {
        try {
            $stmt = $this->pdo->prepare('
                SELECT MAX(CAST(nsu AS UNSIGNED)) as ult_nsu 
                FROM nfe_distribuicao_dfe 
                WHERE cnpj = ? 
                LIMIT 1
            ');
            $stmt->execute([$cnpj]);
            $result = $stmt->fetch(PDO::FETCH_ASSOC);
            return $result['ult_nsu'] ?? '0';
        } catch (\Exception $e) {
            return '0';
        }
    }

    /**
     * Constrói requisição SOAP para NFeDistribuicaoDFe
     */
    private function buildDistribuicaoDFeSoapRequest(string $cnpj, string $ultNSU, string $tpAmb): string {
        $cnpj = preg_replace('/[^0-9]/', '', $cnpj);
        
        return '<?xml version="1.0" encoding="UTF-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <nfeDistDFeInteresse xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NFeDistribuicaoDFe">
      <nfeDadosMsg>
        <distDFeInt versao="1.00" xmlns="http://www.portalfiscal.inf.br/nfe">
          <tpAmb>' . htmlspecialchars($tpAmb) . '</tpAmb>
          <cUFAutor>35</cUFAutor>
          <CNPJ>' . htmlspecialchars($cnpj) . '</CNPJ>
          <distNSU>
            <ultNSU>' . htmlspecialchars($ultNSU) . '</ultNSU>
          </distNSU>
        </distDFeInt>
      </nfeDadosMsg>
    </nfeDistDFeInteresse>
  </soap12:Body>
</soap12:Envelope>';
    }

    /**
     * Faz requisição SOAP com certificado digital
     */
    private function makeSoapRequestComCertificado(string $url, string $soapRequest): string {
        // Por enquanto, usar requisição sem certificado
        // Em produção, configurar certificado digital via curl
        return $this->makeSoapRequest($url, $soapRequest);
    }

    /**
     * Processa resposta do NFeDistribuicaoDFe e busca XML da chave
     */
    private function processarDistribuicaoDFeResponse(string $xmlResponse, string $chave): ?string {
        try {
            $dom = new \DOMDocument();
            if (!@$dom->loadXML($xmlResponse)) {
                return null;
            }

            $xpath = new \DOMXPath($dom);
            $xpath->registerNamespace('nfe', 'http://www.portalfiscal.inf.br/nfe');
            $xpath->registerNamespace('soap', 'http://www.w3.org/2003/05/soap-envelope');

            // Buscar documentos na resposta
            $docs = $xpath->query('//nfe:docZip | //docZip');
            
            foreach ($docs as $doc) {
                $schema = $doc->getAttribute('schema') ?? '';
                $conteudoBase64 = $doc->nodeValue ?? '';
                
                // Verificar se é NFe
                if (strpos($schema, 'NFe') !== false && !empty($conteudoBase64)) {
                    $xml = base64_decode($conteudoBase64);
                    $xmlGzip = @gzdecode($xml);
                    
                    if ($xmlGzip !== false) {
                        $xml = $xmlGzip;
                    }
                    
                    // Verificar se contém a chave
                    if (strpos($xml, $chave) !== false) {
                        return $xml;
                    }
                }
            }
        } catch (\Exception $e) {
            error_log("Erro ao processar resposta NFeDistribuicaoDFe: " . $e->getMessage());
        }

        return null;
    }

    /**
     * Converte código UF para sigla
     */
    private function getUfCode(string $uf): ?string {
        $ufMap = [
            '12' => 'AC', '27' => 'AL', '16' => 'AP', '13' => 'AM',
            '29' => 'BA', '23' => 'CE', '53' => 'DF', '32' => 'ES',
            '52' => 'GO', '21' => 'MA', '51' => 'MT', '50' => 'MS',
            '31' => 'MG', '15' => 'PA', '25' => 'PB', '41' => 'PR',
            '26' => 'PE', '22' => 'PI', '33' => 'RJ', '24' => 'RN',
            '43' => 'RS', '11' => 'RO', '14' => 'RR', '42' => 'SC',
            '35' => 'SP', '28' => 'SE', '17' => 'TO'
        ];
        return $ufMap[$uf] ?? null;
    }

    /**
     * Constrói requisição SOAP para consulta
     */
    private function buildConsultaSoapRequest(string $chave, string $tpAmb = '1'): string {
        return '<?xml version="1.0" encoding="UTF-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
  <soap12:Body>
    <nfeConsultaNF xmlns="http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4">
      <nfeDadosMsg>
        <consSitNFe xmlns="http://www.portalfiscal.inf.br/nfe" versao="4.00">
          <tpAmb>' . htmlspecialchars($tpAmb) . '</tpAmb>
          <xServ>CONSULTAR</xServ>
          <chNFe>' . htmlspecialchars($chave) . '</chNFe>
        </consSitNFe>
      </nfeDadosMsg>
    </nfeConsultaNF>
  </soap12:Body>
</soap12:Envelope>';
    }

    /**
     * Faz requisição SOAP
     */
    private function makeSoapRequest(string $url, string $soapRequest): string {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $soapRequest,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/soap+xml; charset=utf-8',
                'Content-Length: ' . strlen($soapRequest),
                'SOAPAction: http://www.portalfiscal.inf.br/nfe/wsdl/NFeConsultaProtocolo4/nfeConsultaNF'
            ],
            CURLOPT_SSL_VERIFYPEER => false, // Em produção, usar certificado
            CURLOPT_SSL_VERIFYHOST => false,
            CURLOPT_TIMEOUT => 30
        ]);

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

        if ($error) {
            throw new Exception("Erro cURL: $error");
        }

        if ($httpCode !== 200) {
            throw new Exception("HTTP $httpCode retornado pela SEFAZ");
        }

        return $response;
    }

    /**
     * Processa resposta da consulta
     */
    private function parseConsultaResponse(string $xmlResponse, string $chave): array {
        $dom = new \DOMDocument();
        if (!@$dom->loadXML($xmlResponse)) {
            throw new Exception('Resposta XML inválida da SEFAZ');
        }

        $xpath = new \DOMXPath($dom);
        $xpath->registerNamespace('soap', 'http://www.w3.org/2003/05/soap-envelope');
        $xpath->registerNamespace('soap12', 'http://www.w3.org/2003/05/soap-envelope');
        $xpath->registerNamespace('nfe', 'http://www.portalfiscal.inf.br/nfe');

        // Buscar retConsSitNFe (pode estar em diferentes namespaces)
        $retConsSitNFe = $xpath->query('//nfe:retConsSitNFe | //retConsSitNFe')->item(0);
        if (!$retConsSitNFe) {
            // Tentar buscar no corpo SOAP
            $body = $xpath->query('//soap:Body | //soap12:Body')->item(0);
            if ($body) {
                $retConsSitNFe = $xpath->query('.//retConsSitNFe', $body)->item(0);
            }
        }

        if (!$retConsSitNFe) {
            // Tentar buscar diretamente os campos (algumas SEFAZ retornam de forma diferente)
            $cStat = $xpath->query('//cStat')->item(0)?->nodeValue ?? '';
            $xMotivo = $xpath->query('//xMotivo')->item(0)?->nodeValue ?? '';
            
            if (empty($cStat)) {
                throw new Exception('Resposta da SEFAZ não contém dados válidos');
            }
        } else {
            // Extrair status
            $cStat = $xpath->query('.//nfe:cStat | .//cStat', $retConsSitNFe)->item(0)?->nodeValue ?? '';
            $xMotivo = $xpath->query('.//nfe:xMotivo | .//xMotivo', $retConsSitNFe)->item(0)?->nodeValue ?? '';
        }

        $protNFe = $retConsSitNFe ? $xpath->query('.//nfe:protNFe | .//protNFe', $retConsSitNFe)->item(0) : $xpath->query('//protNFe')->item(0);

        $status = 'erro';
        if ($cStat === '100') {
            $status = 'autorizada';
        } elseif ($cStat === '101' || $cStat === '151') {
            $status = 'cancelada';
        } elseif ($cStat === '110') {
            $status = 'denegada';
        } elseif ($cStat === '217') {
            $status = 'rejeitada';
        }

        $protocolo = null;
        $dataAutorizacao = null;
        $xmlNota = null;
        
        if ($protNFe) {
            $protocolo = $xpath->query('.//nfe:nProt | .//nProt', $protNFe)->item(0)?->nodeValue;
            $dataAutorizacao = $xpath->query('.//nfe:dhRecbto | .//dhRecbto', $protNFe)->item(0)?->nodeValue;
            
            // Tentar extrair XML da nota se disponível
            $nfeProc = $xpath->query('.//nfe:NFeProc | .//NFeProc', $protNFe)->item(0);
            if ($nfeProc) {
                $xmlNota = $dom->saveXML($nfeProc);
            }
        }

        return [
            'chave' => $chave,
            'status' => $status,
            'codigo_status' => $cStat,
            'motivo' => $xMotivo,
            'protocolo' => $protocolo,
            'data_autorizacao' => $dataAutorizacao,
            'xml' => $xmlNota ?: $xmlResponse // Retornar XML da nota se disponível, senão retornar resposta completa
        ];
    }
}

