<?php

namespace App\Services;

use NFePHP\Common\Certificate;
use NFePHP\MDFe\Make;
use NFePHP\MDFe\Tools;
use NFePHP\MDFe\Complements;
use NFePHP\MDFe\Common\Standardize;
use NFePHP\DA\MDFe\Damdfe;

class MDFeService
{
    private $tools;
    private $tpAmb = 2; // 1=Produção, 2=Homologação

    /**
     * Log personalizado
     */
    private function log($message)
    {
        $logFile = __DIR__ . "/../../logs/mdfe_debug.log";
        if (!is_dir(dirname($logFile))) {
            mkdir(dirname($logFile), 0755, true);
        }
        $timestamp = date('Y-m-d H:i:s');
        file_put_contents($logFile, "[$timestamp] $message" . PHP_EOL, FILE_APPEND);
        error_log($message);
    }

    /**
     * Criar estrutura de diretórios
     */
    private function criarEstruturaDiretorios($cnpj)
    {
        $basePath = __DIR__ . "/../../arquivos/{$cnpj}/mdfe";
        $anoMes = date('Y_m');

        $diretorios = [
            "{$basePath}/xml/{$anoMes}/assinados",
            "{$basePath}/pdf/{$anoMes}/emitidos"
        ];

        foreach ($diretorios as $dir) {
            if (!is_dir($dir)) {
                mkdir($dir, 0755, true);
            }
        }
    }

    /**
     * Carregar certificado e Tools
     */
    private function loadTools($cnpj, $uf)
    {
        $certificadoPath = __DIR__ . "/../../certificados/empresas/{$cnpj}/{$cnpj}.pfx";

        if (!file_exists($certificadoPath)) {
            throw new \Exception("Certificado não encontrado: {$certificadoPath}");
        }

        $configCertificado = require __DIR__ . '/../../config_certificado.php';
        $certificate = \App\Core\CertificateHelper::loadPfx($certificadoPath, $configCertificado['senha_certificado']);

        // Configuração para Tools
        $config = [
            "atualizacao" => date('Y-m-d H:i:s'),
            "tpAmb" => $this->tpAmb,
            "razaosocial" => "Razao Social",
            "siglaUF" => $uf,
            "cnpj" => $cnpj,
            "schemes" => "PL_MDFe_300a",
            "versao" => '3.00'
        ];

        $this->tools = new Tools(json_encode($config), $certificate);

        $this->log("✅ Tools configurado para UF: {$uf}, Ambiente: " . ($this->tpAmb == 1 ? 'Produção' : 'Homologação'));
    }

    /**
     * Emitir MDF-e
     */
    public function emitir($dados)
    {
        try {
            $this->log("🚚 EMISSÃO REAL DE MDF-e");

            // Normalizar dados
            if (isset($dados['mdfe'])) {
                $dados['numero'] = $dados['mdfe']['numero'] ?? $dados['numero'] ?? '1';
                $dados['serie'] = $dados['mdfe']['serie'] ?? $dados['serie'] ?? '001';
                $dados['data_emissao'] = date('Y-m-d H:i:s');
            }

            $cnpj = preg_replace('/[^0-9]/', '', $dados['emitente']['cnpj']);
            $this->criarEstruturaDiretorios($cnpj);

            // Carregar Tools
            $this->loadTools($cnpj, $dados['emitente']['estado']);

            // Gerar XML usando Make
            $make = new Make();
            $this->montarXML($make, $dados);

            $xml = $make->getXML();
            $this->log("✅ XML gerado");

            // Assinar
            $xmlAssinado = $this->tools->signMDFe($xml);
            $this->log("✅ XML assinado");

            // Enviar para SEFAZ
            $idLote = str_pad($dados['numero'], 15, '0', STR_PAD_LEFT);
            $response = $this->tools->sefazEnviaLote([$xmlAssinado], $idLote, 1); // Síncrono

            $this->log("📥 Resposta SEFAZ recebida");

            // Processar resposta
            $st = new Standardize($response);
            $std = $st->toStd();

            // Verificar se é resposta síncrona direta ou protocolo
            $cStat = null;
            $xMotivo = null;
            $chaveAcesso = null;
            $nProt = null;

            if (isset($std->protMDFe->infProt->cStat)) {
                // Resposta com protocolo (autorizado)
                $cStat = $std->protMDFe->infProt->cStat;
                $xMotivo = $std->protMDFe->infProt->xMotivo;
                $chaveAcesso = $std->protMDFe->infProt->chMDFe;
                $nProt = $std->protMDFe->infProt->nProt;
            } elseif (isset($std->cStat)) {
                // Resposta direta do lote (pode ser rejeição)
                $cStat = $std->cStat;
                $xMotivo = $std->xMotivo;
            }

            if ($cStat) {
                if (in_array($cStat, ['100', '150'])) {
                    // Autorizado!
                    $this->log("✅ MDF-e AUTORIZADO! Chave: {$chaveAcesso}, Protocolo: {$nProt}");

                    // Adicionar protocolo ao XML
                    $xmlProtocolado = Complements::toAuthorize($xmlAssinado, $response);
                    $this->log("📋 XML Protocolado gerado");

                    // Salvar
                    $xmlPath = $this->salvarXML($xmlProtocolado, $cnpj, $chaveAcesso);
                    $pdfPath = $this->gerarPDF($xmlProtocolado, $cnpj, $chaveAcesso);

                    return [
                        'success' => true,
                        'numero' => $dados['numero'],
                        'serie' => $dados['serie'],
                        'chave_acesso' => $chaveAcesso,
                        'protocolo' => $nProt,
                        'cStat' => $cStat,
                        'xml_path' => $xmlPath,
                        'pdf_path' => $pdfPath,
                        'data_emissao' => $dados['data_emissao'],
                        'message' => 'MDF-e emitido com sucesso'
                    ];
                } else {
                    // Rejeitado
                    $this->log("❌ Rejeitado: [{$cStat}] {$xMotivo}");
                    return [
                        'success' => false,
                        'numero' => $dados['numero'],
                        'serie' => $dados['serie'],
                        'cStat' => $cStat,
                        'error' => "MDF-e rejeitado [{$cStat}]: {$xMotivo}"
                    ];
                }
            }

            throw new \Exception('Resposta inválida da SEFAZ');

        } catch (\Exception $e) {
            $this->log("❌ ERRO: " . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Montar XML usando Make
     */
    private function montarXML($make, $dados)
    {
        // TAG ide
        $std = new \stdClass();
        $std->cUF = $this->getCodigoUF($dados['emitente']['estado']);
        $std->tpAmb = $this->tpAmb;
        $std->tpEmit = $dados['tipo_emitente'] ?? 1;
        $std->tpTransp = $dados['tipo_transportador'] ?? null;
        $std->mod = 58;
        $std->serie = intval($dados['serie']);
        $std->nMDF = intval($dados['numero']);
        $std->cMDF = str_pad(rand(1, 99999999), 8, '0', STR_PAD_LEFT);
        $std->cDV = 0;
        $std->modal = $dados['modal'] ?? 1;
        $std->dhEmi = date('Y-m-d\TH:i:sP');
        $std->tpEmis = 1;
        $std->procEmi = 0;
        $std->verProc = '1.0';
        $std->UFIni = $dados['uf_inicio'];
        $std->UFFim = $dados['uf_fim'];
        $make->tagide($std);

        // TAG emit
        $std = new \stdClass();
        $std->CNPJ = preg_replace('/[^0-9]/', '', $dados['emitente']['cnpj']);
        $std->IE = preg_replace('/[^0-9]/', '', $dados['emitente']['inscricao_estadual']);
        $std->xNome = $dados['emitente']['nome'];
        $std->xFant = $dados['emitente']['nome_fantasia'] ?? $dados['emitente']['nome'];
        $make->tagemit($std);

        // TAG enderEmit
        $std = new \stdClass();
        $std->xLgr = $dados['emitente']['endereco'];
        $std->nro = $dados['emitente']['numero'];
        $std->xBairro = $dados['emitente']['bairro'];
        $std->cMun = $this->getCodigoMunicipio($dados['emitente']['cidade']);
        $std->xMun = $dados['emitente']['cidade'];
        $std->CEP = preg_replace('/[^0-9]/', '', $dados['emitente']['cep']);
        $std->UF = $dados['emitente']['estado'];
        $std->fone = preg_replace('/[^0-9]/', '', $dados['emitente']['telefone'] ?? '');
        $std->email = $dados['emitente']['email'] ?? '';
        $make->tagenderEmit($std);

        // TAG veicTracao (cria automáticamente rodo e infModal)
        $veiculo = $dados['veiculo'];
        $std = new \stdClass();
        $std->cInt = $veiculo['codigo_interno'] ?? null;
        $std->placa = $veiculo['placa'];
        $std->RENAVAM = $veiculo['renavam'] ?? null;
        $std->tara = $veiculo['tara'];
        $std->capKG = $veiculo['capacidade_kg'];
        $std->capM3 = $veiculo['capacidade_m3'] ?? null;

        // Proprietário do veículo
        if (isset($veiculo['proprietario'])) {
            $prop = new \stdClass();
            if (isset($veiculo['proprietario']['cpf'])) {
                $prop->CPF = preg_replace('/[^0-9]/', '', $veiculo['proprietario']['cpf']);
            } else {
                $prop->CNPJ = preg_replace('/[^0-9]/', '', $veiculo['proprietario']['cnpj']);
            }
            $prop->RNTRC = $veiculo['proprietario']['rntrc'];
            $prop->xNome = $veiculo['proprietario']['nome'];
            $prop->IE = preg_replace('/[^0-9]/', '', $veiculo['proprietario']['inscricao_estadual']);
            $prop->UF = $veiculo['proprietario']['uf'];
            $prop->tpProp = $veiculo['proprietario']['tipo_proprietario'] ?? '0';
            $std->prop = $prop;
        }

        $std->tpRod = $veiculo['tipo_rodado'] ?? '03';
        $std->tpCar = $veiculo['tipo_carroceria'] ?? '02';
        $std->UF = $veiculo['uf'];

        // Adicionar condutores dentro do veículo
        $std->condutor = [];
        foreach ($dados['condutores'] as $condutor) {
            $c = new \stdClass();
            $c->xNome = $condutor['nome'];
            $c->CPF = preg_replace('/[^0-9]/', '', $condutor['cpf']);
            $std->condutor[] = $c;
        }

        $make->tagveicTracao($std);

        // TAG infPercurso - UFs intermediárias do percurso (obrigatório se UFIni != UFFim)
        if ($dados['uf_inicio'] != $dados['uf_fim']) {
            // Adicionar UFs intermediárias (exemplo: PE -> SP passa pela BA e MG)
            $ufsPercurso = ['BA', 'MG']; // Simplificado - idealmente deveria ser informado no JSON
            foreach ($ufsPercurso as $ufPer) {
                $std = new \stdClass();
                $std->UFPer = $ufPer;
                $make->taginfPercurso($std);
            }
        }

        // TAG infDoc - Municípios de carregamento
        foreach ($dados['municipios_carregamento'] as $mun) {
            $std = new \stdClass();
            $std->cMunCarrega = $mun['codigo_municipio'];
            $std->xMunCarrega = $mun['nome'];
            $make->taginfMunCarrega($std);
        }

        // TAG infMunDescarga
        foreach ($dados['municipios_descarregamento'] as $mun) {
            $std = new \stdClass();
            $std->cMunDescarga = $mun['codigo_municipio'];
            $std->xMunDescarga = $mun['nome'];
            $make->taginfMunDescarga($std);

            if (isset($mun['nfes'])) {
                foreach ($mun['nfes'] as $nfe) {
                    $std = new \stdClass();
                    $std->chNFe = $nfe['chave_acesso'];
                    $make->taginfNFe($std);
                }
            }
        }

        // TAG tot
        $tot = $dados['totalizadores'];
        $std = new \stdClass();
        $std->qNFe = $tot['quantidade_nfe'] ?? 0;
        $std->qCTe = $tot['quantidade_cte'] ?? 0;
        $std->qMDFe = $tot['quantidade_mdfe'] ?? 0;
        $std->vCarga = number_format($tot['valor_carga'], 2, '.', '');
        $std->cUnid = $tot['codigo_unidade'] ?? '01';
        $std->qCarga = number_format($tot['peso_carga'], 4, '.', '');
        $make->tagtot($std);

        // TAG infAdic
        if (isset($dados['informacoes_complementares'])) {
            $std = new \stdClass();
            $std->infCpl = $dados['informacoes_complementares'];
            $make->taginfAdic($std);
        }

        $this->log("✅ Tags montadas com sucesso");
    }

    /**
     * Salvar XML
     */
    private function salvarXML($xml, $cnpj, $chaveAcesso)
    {
        $anoMes = date('Y_m');
        $xmlPath = __DIR__ . "/../../arquivos/{$cnpj}/mdfe/xml/{$anoMes}/assinados/{$chaveAcesso}.xml";
        file_put_contents($xmlPath, $xml);
        $this->log("✅ XML salvo: {$xmlPath}");
        return "/pontti_nfe/arquivos/{$cnpj}/mdfe/xml/{$anoMes}/assinados/{$chaveAcesso}.xml";
    }

    /**
     * Gerar PDF
     *
     * NOTA: Geração de PDF do MDF-e temporariamente desabilitada devido a problema
     * na biblioteca NFePHP\DA\MDFe\Damdfe. O XML autorizado é salvo normalmente.
     */
    private function gerarPDF($xml, $cnpj, $chaveAcesso)
    {
        $this->log("ℹ️ Geração de PDF do MDF-e desabilitada temporariamente");
        $this->log("   XML autorizado salvo com sucesso, PDF pode ser gerado posteriormente");
        return null;

        // Código comentado temporariamente
        /*
        try {
            $anoMes = date('Y_m');
            $damdfe = new Damdfe($xml);
            $pdf = $damdfe->render();
            $pdfPath = __DIR__ . "/../../arquivos/{$cnpj}/mdfe/pdf/{$anoMes}/emitidos/MDFe_{$chaveAcesso}.pdf";
            file_put_contents($pdfPath, $pdf);
            $this->log("✅ PDF gerado: {$pdfPath}");
            return "/pontti_nfe/arquivos/{$cnpj}/mdfe/pdf/{$anoMes}/emitidos/MDFe_{$chaveAcesso}.pdf";
        } catch (\Exception $e) {
            $this->log("⚠️ Não foi possível gerar PDF: " . $e->getMessage());
            return null;
        }
        */
    }

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

    /**
     * Obter código do município
     */
    private function getCodigoMunicipio($cidade)
    {
        $municipios = [
            'Recife' => 2611606,
            'São Paulo' => 3550308
        ];
        return $municipios[$cidade] ?? 9999999;
    }

    /**
     * Encerrar MDF-e
     */
    public function encerrar($dados)
    {
        try {
            $this->log("🏁 ENCERRANDO MDF-e");

            $chaveAcesso = $dados['chave_acesso'];
            $cnpj = preg_replace('/[^0-9]/', '', $dados['cnpj']);
            $protocolo = $dados['protocolo'];

            // Carregar Tools
            $this->loadTools($cnpj, $dados['uf_encerramento']);

            // Gerar XML do evento de encerramento
            $dtEnc = new \DateTime($dados['data_encerramento'] ?? 'now');

            $cUF = $this->getCodigoUF($dados['uf_encerramento']);
            $cMunDesc = $dados['municipio_encerramento']['codigo'];
            $dtEncStr = $dtEnc->format('Y-m-d');

            $this->log("🔧 Gerando evento de encerramento");
            $this->log("   UF: {$cUF}, Município: {$cMunDesc}, Data: {$dtEncStr}");
            $xml = $this->tools->sefazEncerra($chaveAcesso, $protocolo, $cUF, $cMunDesc, $dtEncStr);

            $this->log("✅ Evento gerado e enviado");

            // Processar resposta
            $st = new Standardize($xml);
            $std = $st->toStd();

            if (isset($std->infEvento->cStat)) {
                $cStat = $std->infEvento->cStat;
                $xMotivo = $std->infEvento->xMotivo;

                if (in_array($cStat, ['135', '136'])) {
                    // Encerrado com sucesso
                    $this->log("✅ MDF-e ENCERRADO! [{$cStat}] {$xMotivo}");

                    $nProtEvento = $std->infEvento->nProt ?? null;

                    return [
                        'success' => true,
                        'chave_acesso' => $chaveAcesso,
                        'protocolo_encerramento' => $nProtEvento,
                        'cStat' => $cStat,
                        'xMotivo' => $xMotivo,
                        'message' => 'MDF-e encerrado com sucesso'
                    ];
                } else {
                    // Erro
                    $this->log("❌ Erro ao encerrar: [{$cStat}] {$xMotivo}");
                    return [
                        'success' => false,
                        'chave_acesso' => $chaveAcesso,
                        'cStat' => $cStat,
                        'error' => "Erro ao encerrar [{$cStat}]: {$xMotivo}"
                    ];
                }
            }

            throw new \Exception('Resposta inválida da SEFAZ');

        } catch (\Exception $e) {
            $this->log("❌ ERRO: " . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Cancelar MDF-e
     */
    public function cancelar($dados)
    {
        try {
            $this->log("❌ CANCELANDO MDF-e");

            $chaveAcesso = $dados['chave_acesso'];
            $cnpj = preg_replace('/[^0-9]/', '', $dados['cnpj']);
            $protocolo = $dados['protocolo'];
            $justificativa = $dados['justificativa'];

            // Validar justificativa
            if (strlen($justificativa) < 15) {
                throw new \Exception('Justificativa deve ter no mínimo 15 caracteres');
            }

            // Carregar Tools
            $uf = substr($chaveAcesso, 0, 2); // Extrair UF da chave
            $ufSigla = array_search($uf, [
                'AC' => 12, 'AL' => 27, 'AP' => 16, 'AM' => 13, 'BA' => 29,
                'CE' => 23, 'DF' => 53, 'ES' => 32, 'GO' => 52, 'MA' => 21,
                'MT' => 51, 'MS' => 50, 'MG' => 31, 'PA' => 15, 'PB' => 25,
                'PR' => 41, 'PE' => 26, 'PI' => 22, 'RJ' => 33, 'RN' => 24,
                'RS' => 43, 'RO' => 11, 'RR' => 14, 'SC' => 42, 'SP' => 35,
                'SE' => 28, 'TO' => 17
            ]);

            $this->loadTools($cnpj, $ufSigla ?: 'PE');

            $this->log("🔧 Gerando evento de cancelamento");
            $this->log("   Justificativa: {$justificativa}");

            $xml = $this->tools->sefazCancela($chaveAcesso, $protocolo, $justificativa);

            $this->log("✅ Evento gerado e enviado");

            // Processar resposta
            $st = new Standardize($xml);
            $std = $st->toStd();

            if (isset($std->infEvento->cStat)) {
                $cStat = $std->infEvento->cStat;
                $xMotivo = $std->infEvento->xMotivo;

                if (in_array($cStat, ['135', '136'])) {
                    // Cancelado com sucesso
                    $this->log("✅ MDF-e CANCELADO! [{$cStat}] {$xMotivo}");

                    $nProtEvento = $std->infEvento->nProt ?? null;

                    return [
                        'success' => true,
                        'chave_acesso' => $chaveAcesso,
                        'protocolo_cancelamento' => $nProtEvento,
                        'cStat' => $cStat,
                        'xMotivo' => $xMotivo,
                        'message' => 'MDF-e cancelado com sucesso'
                    ];
                } else {
                    // Erro
                    $this->log("❌ Erro ao cancelar: [{$cStat}] {$xMotivo}");
                    return [
                        'success' => false,
                        'chave_acesso' => $chaveAcesso,
                        'cStat' => $cStat,
                        'error' => "Erro ao cancelar [{$cStat}]: {$xMotivo}"
                    ];
                }
            }

            throw new \Exception('Resposta inválida da SEFAZ');

        } catch (\Exception $e) {
            $this->log("❌ ERRO: " . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }

    /**
     * Incluir Condutor no MDF-e
     */
    public function incluirCondutor($dados)
    {
        try {
            $this->log("👤 INCLUINDO CONDUTOR NO MDF-e");

            $chaveAcesso = $dados['chave_acesso'];
            $cnpj = preg_replace('/[^0-9]/', '', $dados['cnpj']);

            // Validar condutor
            if (!isset($dados['condutor']['nome']) || !isset($dados['condutor']['cpf'])) {
                throw new \Exception('Dados do condutor (nome e CPF) são obrigatórios');
            }

            // Carregar Tools
            $uf = substr($chaveAcesso, 0, 2);
            $ufSigla = array_search($uf, [
                'AC' => 12, 'AL' => 27, 'AP' => 16, 'AM' => 13, 'BA' => 29,
                'CE' => 23, 'DF' => 53, 'ES' => 32, 'GO' => 52, 'MA' => 21,
                'MT' => 51, 'MS' => 50, 'MG' => 31, 'PA' => 15, 'PB' => 25,
                'PR' => 41, 'PE' => 26, 'PI' => 22, 'RJ' => 33, 'RN' => 24,
                'RS' => 43, 'RO' => 11, 'RR' => 14, 'SC' => 42, 'SP' => 35,
                'SE' => 28, 'TO' => 17
            ]);

            $this->loadTools($cnpj, $ufSigla ?: 'PE');

            $this->log("🔧 Gerando evento de inclusão de condutor");
            $this->log("   Condutor: {$dados['condutor']['nome']} - CPF: {$dados['condutor']['cpf']}");

            $condutor = new \stdClass();
            $condutor->xNome = $dados['condutor']['nome'];
            $condutor->CPF = preg_replace('/[^0-9]/', '', $dados['condutor']['cpf']);

            $xml = $this->tools->sefazIncluirCondutor($chaveAcesso, $condutor);

            $this->log("✅ Evento gerado e enviado");

            // Processar resposta
            $st = new Standardize($xml);
            $std = $st->toStd();

            if (isset($std->infEvento->cStat)) {
                $cStat = $std->infEvento->cStat;
                $xMotivo = $std->infEvento->xMotivo;

                if (in_array($cStat, ['135', '136'])) {
                    // Incluído com sucesso
                    $this->log("✅ CONDUTOR INCLUÍDO! [{$cStat}] {$xMotivo}");

                    $nProtEvento = $std->infEvento->nProt ?? null;

                    return [
                        'success' => true,
                        'chave_acesso' => $chaveAcesso,
                        'protocolo_evento' => $nProtEvento,
                        'cStat' => $cStat,
                        'xMotivo' => $xMotivo,
                        'condutor' => $dados['condutor'],
                        'message' => 'Condutor incluído com sucesso'
                    ];
                } else {
                    // Erro
                    $this->log("❌ Erro ao incluir condutor: [{$cStat}] {$xMotivo}");
                    return [
                        'success' => false,
                        'chave_acesso' => $chaveAcesso,
                        'cStat' => $cStat,
                        'error' => "Erro ao incluir condutor [{$cStat}]: {$xMotivo}"
                    ];
                }
            }

            throw new \Exception('Resposta inválida da SEFAZ');

        } catch (\Exception $e) {
            $this->log("❌ ERRO: " . $e->getMessage());
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
}