<?php

namespace Modules\SPED\Services;

use PDO;
use Exception;

/**
 * Serviço para geração de SPED Contribuições (EFD-Contribuições)
 */
class SPEDContribuicoesService {
    private PDO $pdo;
    private string $tenantId;

    public function __construct(string $tenantId) {
        $this->tenantId = $tenantId;
        $this->pdo = \Gestoreasy\Core\Tenant\ConnectionManager::forTenant($tenantId);
    }

    /**
     * Gera arquivo SPED Contribuições
     */
    public function gerar(int $ano, int $mes, array $opcoes = []): array {
        try {
            // TODO: Implementar gerador de SPED Contribuições
            // Por enquanto, estrutura básica
            
            $dataInicio = date("{$ano}-{$mes}-01");
            $dataFim = date("{$ano}-{$mes}-t");

            // Buscar dados de PIS/COFINS do período
            $totais = $this->calcularTotaisContribuicoes($dataInicio, $dataFim);

            // Gerar linhas do SPED Contribuições
            $lines = $this->gerarLinhas($ano, $mes, $totais, $opcoes);
            $txt = $this->linhasParaTxt($lines);

            // Salvar arquivo
            $arquivoId = $this->salvarArquivo('contribuicoes', $ano, $mes, $txt, $opcoes);

            // Salvar dados específicos
            $this->salvarDadosContribuicoes($arquivoId, $dataInicio, $dataFim, $totais);

            // Registrar log
            $this->registrarLog($arquivoId, 'geracao', 'sucesso', 'SPED Contribuições gerado com sucesso', [
                'ano' => $ano,
                'mes' => $mes,
                'total_linhas' => count($lines)
            ]);

            return [
                'arquivo_id' => $arquivoId,
                'total_linhas' => count($lines),
                'tamanho_bytes' => strlen($txt),
                'conteudo' => $txt
            ];
        } catch (Exception $e) {
            $this->registrarLog(null, 'geracao', 'erro', $e->getMessage());
            throw $e;
        }
    }

    /**
     * Calcula totais de contribuições
     */
    private function calcularTotaisContribuicoes(string $dataInicio, string $dataFim): array {
        // Buscar notas fiscais do período
        $stmt = $this->pdo->prepare('
            SELECT 
                SUM(valor_pis) as total_pis,
                SUM(valor_cofins) as total_cofins,
                SUM(valor_total) as total_vendas
            FROM nfe_saida
            WHERE DATE(data_emissao) BETWEEN ? AND ?
            AND status = "autorizada"
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        $totalVendas = (float)($result['total_vendas'] ?? 0);
        $totalPis = (float)($result['total_pis'] ?? 0);
        $totalCofins = (float)($result['total_cofins'] ?? 0);

        // Se não tiver PIS/COFINS calculados, calcular baseado em alíquotas padrão
        if ($totalPis == 0 && $totalCofins == 0 && $totalVendas > 0) {
            // Alíquotas padrão (podem ser configuráveis)
            $aliquotaPis = 0.0165; // 1,65%
            $aliquotaCofins = 0.076; // 7,6%
            $totalPis = $totalVendas * $aliquotaPis;
            $totalCofins = $totalVendas * $aliquotaCofins;
        }

        // Calcular CSLL (Contribuição Social sobre o Lucro Líquido)
        // CSLL = 9% sobre o lucro líquido (simplificado: 9% sobre receita líquida)
        $totalCsll = $this->calcularCSLL($dataInicio, $dataFim, $totalVendas);

        // Calcular IRPJ (Imposto de Renda Pessoa Jurídica)
        // IRPJ = 15% sobre o lucro líquido (simplificado: 15% sobre receita líquida)
        $totalIrpj = $this->calcularIRPJ($dataInicio, $dataFim, $totalVendas);

        // Calcular INSS (sobre folha de pagamento)
        $totalInss = $this->calcularINSS($dataInicio, $dataFim);

        return [
            'total_pis' => $totalPis,
            'total_cofins' => $totalCofins,
            'total_csll' => $totalCsll,
            'total_irpj' => $totalIrpj,
            'total_inss' => $totalInss,
            'total_vendas' => $totalVendas
        ];
    }

    /**
     * Calcula INSS (Instituto Nacional do Seguro Social)
     * INSS = alíquota sobre a folha de pagamento
     */
    private function calcularINSS(string $dataInicio, string $dataFim): float {
        // Buscar despesas de salários/folha de pagamento
        // Por enquanto, buscar todas as despesas relacionadas a salários
        $inss = 0;
        
        try {
            // Buscar despesas com tipo "folha" ou "salario" ou que contenham "INSS" na descrição
            $stmt = $this->pdo->prepare('
                SELECT COALESCE(SUM(valor), 0) as total
                FROM contas_pagar
                WHERE DATE(data_pagamento) BETWEEN ? AND ?
                AND status = "pago"
                AND (
                    tipo IN ("folha", "salario", "encargos")
                    OR descricao LIKE "%INSS%"
                    OR descricao LIKE "%Folha%"
                    OR descricao LIKE "%Salário%"
                )
            ');
            $stmt->execute([$dataInicio, $dataFim]);
            $folhaPagamento = (float)$stmt->fetchColumn();
            
            if ($folhaPagamento > 0) {
                // Alíquota padrão do INSS sobre folha: 20% (empresa) + 11% (empregado) = 31% total
                // Mas a empresa paga apenas 20% (a parte do empregado é retida)
                // Para simplificar, considerar 20% sobre a folha total
                $aliquotaINSS = 0.20; // 20%
                
                // Verificar se há configuração
                try {
                    $stmt = $this->pdo->prepare('SELECT valor FROM config WHERE chave = "inss_aliquota" LIMIT 1');
                    $stmt->execute();
                    $config = $stmt->fetch();
                    if ($config) {
                        $aliquotaINSS = (float)$config['valor'] / 100;
                    }
                } catch (\Exception $e) {
                    // Usar padrão
                }
                
                $inss = $folhaPagamento * $aliquotaINSS;
            }
        } catch (\Exception $e) {
            // Campo tipo pode não existir, tentar buscar por descrição
            try {
                $stmt = $this->pdo->prepare('
                    SELECT COALESCE(SUM(valor), 0) as total
                    FROM contas_pagar
                    WHERE DATE(data_pagamento) BETWEEN ? AND ?
                    AND status = "pago"
                    AND (
                        descricao LIKE "%INSS%"
                        OR descricao LIKE "%Folha%"
                        OR descricao LIKE "%Salário%"
                    )
                ');
                $stmt->execute([$dataInicio, $dataFim]);
                $folhaPagamento = (float)$stmt->fetchColumn();
                
                if ($folhaPagamento > 0) {
                    $inss = $folhaPagamento * 0.20; // 20% padrão
                }
            } catch (\Exception $e2) {
                // Não foi possível calcular
            }
        }
        
        return $inss;
    }

    /**
     * Calcula CSLL (Contribuição Social sobre o Lucro Líquido)
     * CSLL = 9% sobre o lucro líquido (ou 15% para algumas atividades)
     */
    private function calcularCSLL(string $dataInicio, string $dataFim, float $receitaBruta): float {
        // Buscar receitas (vendas)
        $stmt = $this->pdo->prepare('
            SELECT COALESCE(SUM(valor_total), 0) as total
            FROM sales_orders
            WHERE DATE(created_at) BETWEEN ? AND ?
            AND status != "cancelado"
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $receitaVendas = (float)$stmt->fetchColumn();
        
        // Adicionar vendas do PDV
        try {
            $stmt = $this->pdo->prepare('
                SELECT COALESCE(SUM(valor_final), 0) as total
                FROM pos_sales
                WHERE DATE(created_at) BETWEEN ? AND ?
            ');
            $stmt->execute([$dataInicio, $dataFim]);
            $receitaPDV = (float)$stmt->fetchColumn();
            $receitaVendas += $receitaPDV;
        } catch (\Exception $e) {
            // Tabela pode não existir
        }

        // Buscar CMV (custo das mercadorias vendidas)
        $cmv = 0;
        try {
            $stmt = $this->pdo->prepare('
                SELECT COALESCE(SUM(soi.quantidade * COALESCE(p.preco_custo, p.custo_medio, p.preco * 0.6, 0)), 0) as total
                FROM sales_order_items soi
                INNER JOIN sales_orders so ON so.id = soi.order_id
                LEFT JOIN products p ON p.id = soi.product_id
                WHERE DATE(so.created_at) BETWEEN ? AND ? AND so.status != "cancelado"
            ');
            $stmt->execute([$dataInicio, $dataFim]);
            $cmv = (float)$stmt->fetchColumn();
            
            // Adicionar CMV do PDV
            try {
                $stmt = $this->pdo->prepare('
                    SELECT COALESCE(SUM(psi.quantidade * COALESCE(p.preco_custo, p.custo_medio, p.preco * 0.6, 0)), 0) as total
                    FROM pos_sale_items psi
                    INNER JOIN pos_sales ps ON ps.id = psi.sale_id
                    LEFT JOIN products p ON p.id = psi.product_id
                    WHERE DATE(ps.created_at) BETWEEN ? AND ?
                ');
                $stmt->execute([$dataInicio, $dataFim]);
                $cmvPDV = (float)$stmt->fetchColumn();
                $cmv += $cmvPDV;
            } catch (\Exception $e) {
                // Ignorar
            }
        } catch (\Exception $e) {
            // Fallback: estimar CMV como 60% da receita
            $cmv = $receitaVendas * 0.6;
        }

        // Buscar despesas operacionais
        $stmt = $this->pdo->prepare('
            SELECT COALESCE(SUM(valor), 0) as total
            FROM contas_pagar
            WHERE DATE(data_pagamento) BETWEEN ? AND ?
            AND status = "pago"
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $despesas = (float)$stmt->fetchColumn();

        // Lucro líquido = Receita - CMV - Despesas
        $lucroLiquido = max(0, $receitaVendas - $cmv - $despesas);

        // CSLL = 9% sobre o lucro líquido (pode ser configurável)
        // Para algumas atividades, pode ser 15%
        $aliquotaCSLL = 0.09; // 9% padrão
        
        // Verificar se há configuração específica
        try {
            $stmt = $this->pdo->prepare('SELECT valor FROM config WHERE chave = "csll_aliquota" LIMIT 1');
            $stmt->execute();
            $config = $stmt->fetch();
            if ($config) {
                $aliquotaCSLL = (float)$config['valor'] / 100;
            }
        } catch (\Exception $e) {
            // Usar padrão
        }

        return $lucroLiquido * $aliquotaCSLL;
    }

    /**
     * Calcula IRPJ (Imposto de Renda Pessoa Jurídica)
     * IRPJ = 15% sobre o lucro líquido (até R$ 20.000/mês)
     * Acima disso, 15% + 10% sobre o excedente (alíquota adicional)
     */
    private function calcularIRPJ(string $dataInicio, string $dataFim, float $receitaBruta): float {
        // Buscar receitas (vendas)
        $stmt = $this->pdo->prepare('
            SELECT COALESCE(SUM(valor_total), 0) as total
            FROM sales_orders
            WHERE DATE(created_at) BETWEEN ? AND ?
            AND status != "cancelado"
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $receitaVendas = (float)$stmt->fetchColumn();
        
        // Adicionar vendas do PDV
        try {
            $stmt = $this->pdo->prepare('
                SELECT COALESCE(SUM(valor_final), 0) as total
                FROM pos_sales
                WHERE DATE(created_at) BETWEEN ? AND ?
            ');
            $stmt->execute([$dataInicio, $dataFim]);
            $receitaPDV = (float)$stmt->fetchColumn();
            $receitaVendas += $receitaPDV;
        } catch (\Exception $e) {
            // Tabela pode não existir
        }

        // Buscar CMV
        $cmv = 0;
        try {
            $stmt = $this->pdo->prepare('
                SELECT COALESCE(SUM(soi.quantidade * COALESCE(p.preco_custo, p.custo_medio, p.preco * 0.6, 0)), 0) as total
                FROM sales_order_items soi
                INNER JOIN sales_orders so ON so.id = soi.order_id
                LEFT JOIN products p ON p.id = soi.product_id
                WHERE DATE(so.created_at) BETWEEN ? AND ? AND so.status != "cancelado"
            ');
            $stmt->execute([$dataInicio, $dataFim]);
            $cmv = (float)$stmt->fetchColumn();
            
            // Adicionar CMV do PDV
            try {
                $stmt = $this->pdo->prepare('
                    SELECT COALESCE(SUM(psi.quantidade * COALESCE(p.preco_custo, p.custo_medio, p.preco * 0.6, 0)), 0) as total
                    FROM pos_sale_items psi
                    INNER JOIN pos_sales ps ON ps.id = psi.sale_id
                    LEFT JOIN products p ON p.id = psi.product_id
                    WHERE DATE(ps.created_at) BETWEEN ? AND ?
                ');
                $stmt->execute([$dataInicio, $dataFim]);
                $cmvPDV = (float)$stmt->fetchColumn();
                $cmv += $cmvPDV;
            } catch (\Exception $e) {
                // Ignorar
            }
        } catch (\Exception $e) {
            // Fallback: estimar CMV como 60% da receita
            $cmv = $receitaVendas * 0.6;
        }

        // Buscar despesas operacionais
        $stmt = $this->pdo->prepare('
            SELECT COALESCE(SUM(valor), 0) as total
            FROM contas_pagar
            WHERE DATE(data_pagamento) BETWEEN ? AND ?
            AND status = "pago"
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $despesas = (float)$stmt->fetchColumn();

        // Lucro líquido = Receita - CMV - Despesas
        $lucroLiquido = max(0, $receitaVendas - $cmv - $despesas);

        // IRPJ = 15% sobre o lucro líquido (até R$ 20.000/mês de lucro)
        // Acima disso, 15% + 10% sobre o excedente (alíquota adicional de 10%)
        $baseIsenta = 20000; // Base isenta mensal (pode variar)
        
        // Verificar se há configuração
        try {
            $stmt = $this->pdo->prepare('SELECT valor FROM config WHERE chave = "irpj_base_isenta" LIMIT 1');
            $stmt->execute();
            $config = $stmt->fetch();
            if ($config) {
                $baseIsenta = (float)$config['valor'];
            }
        } catch (\Exception $e) {
            // Usar padrão
        }
        
        if ($lucroLiquido <= $baseIsenta) {
            return $lucroLiquido * 0.15; // 15% sobre o lucro
        } else {
            $base = $baseIsenta * 0.15; // 15% sobre a base isenta
            $excedente = ($lucroLiquido - $baseIsenta) * 0.25; // 15% + 10% adicional sobre o excedente
            return $base + $excedente;
        }
    }

    /**
     * Gera linhas do SPED Contribuições
     */
    private function gerarLinhas(int $ano, int $mes, array $totais, array $opcoes): array {
        $lines = [];
        $dataInicio = date("{$ano}-{$mes}-01");
        $dataFim = date("{$ano}-{$mes}-t");

        // Bloco 0 - Abertura
        $empresa = $this->getDadosEmpresa();
        $codVer = $opcoes['cod_ver'] ?? '017';
        $codFin = (int)($opcoes['cod_fin'] ?? 0); // 0=Original, 1=Substituto
        $dtIni = date("dmY", strtotime($dataInicio));
        $dtFin = date("dmY", strtotime($dataFim));
        $nome = $empresa['razao_social'] ?? $empresa['nome'] ?? 'EMPRESA NÃO CADASTRADA';
        $cnpj = preg_replace('/[^0-9]/', '', $empresa['cnpj'] ?? '');
        $cpf = '';
        $uf = strtoupper($empresa['estado'] ?? '');
        $ie = preg_replace('/[^0-9]/', '', $empresa['ie'] ?? '');
        $im = preg_replace('/[^0-9]/', '', $empresa['im'] ?? '');
        $suframa = '';
        $indNatPj = empty($cnpj) ? 1 : 0; // 0=PJ, 1=PF
        if (empty($cnpj)) {
            $cpf = preg_replace('/[^0-9]/', '', $empresa['cpf'] ?? '');
        }
        $indAtiv = (int)($opcoes['ind_ativ'] ?? 1); // 0=Inativo, 1=Ativo
        
        // 0000 - Abertura do arquivo SPED Contribuições
        $lines[] = $this->gerarLinha('0000', [
            'COD_VER' => $codVer,
            'COD_FIN' => $codFin,
            'DT_INI' => $dtIni,
            'DT_FIN' => $dtFin,
            'NOME' => substr($nome, 0, 100),
            'CNPJ' => str_pad($cnpj, 14, '0', STR_PAD_LEFT),
            'CPF' => str_pad($cpf, 11, '0', STR_PAD_LEFT),
            'UF' => str_pad($uf, 2),
            'IE' => $ie,
            'COD_MUN' => '', // Código do município (IBGE)
            'IM' => $im,
            'SUFRAMA' => $suframa,
            'IND_NAT_PJ' => $indNatPj,
            'IND_ATIV' => $indAtiv,
        ]);

        // 0001 - Abertura do bloco 0
        $lines[] = $this->gerarLinha('0001', [
            'IND_MOV' => '0', // 0=Com movimento, 1=Sem movimento (será atualizado se houver dados)
        ]);

        // 0005 - Dados complementares da entidade (se disponível)
        if (!empty($empresa)) {
            $lines[] = $this->gerarLinha('0005', [
                'FANTASIA' => substr($empresa['nome'] ?? '', 0, 60),
                'CEP' => preg_replace('/[^0-9]/', '', $empresa['cep'] ?? ''),
                'END' => substr($empresa['logradouro'] ?? '', 0, 60),
                'NUM' => substr($empresa['numero'] ?? '', 0, 10),
                'COMPL' => substr($empresa['complemento'] ?? '', 0, 60),
                'BAIRRO' => substr($empresa['bairro'] ?? '', 0, 60),
                'FONE' => preg_replace('/[^0-9]/', '', $empresa['telefone'] ?? ''),
                'FAX' => '',
                'EMAIL' => substr($empresa['email'] ?? '', 0, 115),
            ]);
        }

        // Bloco A - Abertura
        $lines[] = $this->gerarLinha('A001', [
            'IND_MOV' => '0', // Sem movimento (será atualizado se houver dados)
        ]);

        // Bloco C - Documentos Fiscais
        $lines = array_merge($lines, $this->gerarBlocoC($dataInicio, $dataFim, $opcoes));

        // Bloco F - Demais Documentos
        $lines = array_merge($lines, $this->gerarBlocoF($dataInicio, $dataFim, $opcoes));

        // Bloco M - Apuração
        $lines = array_merge($lines, $this->gerarBlocoM($totais, $opcoes));

        // Bloco 9 - Encerramento
        $lines[] = $this->gerarLinha('9999', [
            'QTD_LIN' => count($lines) + 1,
        ]);

        return $lines;
    }

    /**
     * Converte linhas para texto
     */
    private function linhasParaTxt(array $lines): string {
        return implode("\n", $lines);
    }

    /**
     * Gera linha formatada
     */
    private function gerarLinha(string $registro, array $campos): string {
        $parts = [$registro];
        foreach ($campos as $valor) {
            $parts[] = $valor ?? '';
        }
        return implode('|', $parts) . '|';
    }

    /**
     * Salva arquivo
     */
    private function salvarArquivo(string $tipo, int $ano, int $mes, string $conteudo, array $opcoes = []): int {
        $base = getenv('SPED_EXPORT_DIR') ?: (__DIR__ . '/../../../storage/sped');
        $dir = rtrim($base, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $this->tenantId . DIRECTORY_SEPARATOR . sprintf('%04d-%02d', $ano, $mes);
        
        if (!is_dir($dir)) {
            mkdir($dir, 0775, true);
        }

        $nomeArquivo = "sped_{$tipo}_{$ano}{$mes}_" . date('Ymd_His') . '.txt';
        $caminho = $dir . DIRECTORY_SEPARATOR . $nomeArquivo;
        
        file_put_contents($caminho, $conteudo);

        $userContext = \Gestoreasy\Core\Auth\UserContext::getCurrent();

        $stmt = $this->pdo->prepare('
            INSERT INTO sped_arquivos (
                tenant_id, tipo, ano, mes, nome_arquivo, caminho_arquivo,
                tamanho_bytes, versao_layout, perfil, created_by
            ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        ');
        $stmt->execute([
            $this->tenantId,
            $tipo,
            $ano,
            $mes,
            $nomeArquivo,
            $caminho,
            strlen($conteudo),
            $opcoes['cod_ver'] ?? '017',
            $opcoes['perfil'] ?? 'A',
            $userContext?->userId
        ]);

        return (int)$this->pdo->lastInsertId();
    }

    /**
     * Salva dados específicos de contribuições
     */
    private function salvarDadosContribuicoes(int $arquivoId, string $dataInicio, string $dataFim, array $totais): void {
        try {
            $stmt = $this->pdo->prepare('
                INSERT INTO sped_contribuicoes_dados (
                    tenant_id, arquivo_id, data_inicio, data_fim,
                    total_pis, total_cofins, total_csll, total_irpj
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
            ');
            $stmt->execute([
                $this->tenantId,
                $arquivoId,
                $dataInicio,
                $dataFim,
                $totais['total_pis'],
                $totais['total_cofins'],
                $totais['total_csll'] ?? 0,
                $totais['total_irpj'] ?? 0
            ]);
        } catch (\Exception $e) {
            // Se a tabela não tiver campo INSS, inserir sem ele
            // Ou se houver erro, tentar inserir apenas campos obrigatórios
            try {
                $stmt = $this->pdo->prepare('
                    INSERT INTO sped_contribuicoes_dados (
                        tenant_id, arquivo_id, data_inicio, data_fim,
                        total_pis, total_cofins
                    ) VALUES (?, ?, ?, ?, ?, ?)
                ');
                $stmt->execute([
                    $this->tenantId,
                    $arquivoId,
                    $dataInicio,
                    $dataFim,
                    $totais['total_pis'],
                    $totais['total_cofins']
                ]);
            } catch (\Exception $e2) {
                // Ignorar erro - tabela pode não existir
            }
        }
    }

    /**
     * Registra log
     */
    private function registrarLog(?int $arquivoId, string $operacao, string $status, string $mensagem, array $detalhes = []): void {
        $stmt = $this->pdo->prepare('
            INSERT INTO sped_logs (
                tenant_id, arquivo_id, operacao, status, mensagem, detalhes_json
            ) VALUES (?, ?, ?, ?, ?, ?)
        ');
        $stmt->execute([
            $this->tenantId,
            $arquivoId,
            $operacao,
            $status,
            $mensagem,
            !empty($detalhes) ? json_encode($detalhes) : null
        ]);
    }

    /**
     * Gera Bloco C - Documentos Fiscais
     */
    private function gerarBlocoC(string $dataInicio, string $dataFim, array $opcoes): array {
        $lines = [];
        
        // C001 - Abertura do bloco C
        $lines[] = $this->gerarLinha('C001', [
            'IND_MOV' => '0', // 0 = Sem movimento, 1 = Com movimento
        ]);

        // Buscar documentos fiscais do período
        $stmt = $this->pdo->prepare('
            SELECT 
                id, numero, serie, data_emissao, valor_total,
                cliente_id, cfop, cod_situacao
            FROM nfe_saida
            WHERE DATE(data_emissao) BETWEEN ? AND ?
            AND status = "autorizada"
            ORDER BY data_emissao, numero
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $documentos = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (count($documentos) > 0) {
            // Atualizar C001 para indicar movimento
            $lines[count($lines) - 1] = $this->gerarLinha('C001', [
                'IND_MOV' => '1', // Com movimento
            ]);

            foreach ($documentos as $doc) {
                // Buscar valores de impostos do documento
                $valorICMS = 0;
                $valorIPI = 0;
                $valorDesconto = 0;
                $valorFrete = 0;
                
                try {
                    $impStmt = $this->pdo->prepare('
                        SELECT 
                            COALESCE(valor_icms, 0) as icms,
                            COALESCE(valor_ipi, 0) as ipi,
                            COALESCE(valor_desconto, 0) as desconto,
                            COALESCE(valor_frete, 0) as frete,
                            COALESCE(base_icms, 0) as base_icms
                        FROM nfe_saida
                        WHERE id = ?
                    ');
                    $impStmt->execute([$doc['id']]);
                    $impostos = $impStmt->fetch(PDO::FETCH_ASSOC);
                    if ($impostos) {
                        $valorICMS = (float)($impostos['icms'] ?? 0);
                        $valorIPI = (float)($impostos['ipi'] ?? 0);
                        $valorDesconto = (float)($impostos['desconto'] ?? 0);
                        $valorFrete = (float)($impostos['frete'] ?? 0);
                    }
                } catch (\Exception $e) {
                    // Campos podem não existir
                }
                
                // Calcular valor das mercadorias (valor total - impostos - frete + desconto)
                $valorMercadorias = (float)$doc['valor_total'] - $valorICMS - $valorIPI - $valorFrete + $valorDesconto;
                $valorMercadorias = max(0, $valorMercadorias);
                
                // Verificar forma de pagamento (à vista ou a prazo)
                $indPgto = '0'; // À vista por padrão
                try {
                    // Verificar se há parcelas ou condições de pagamento
                    $pgtoStmt = $this->pdo->prepare('
                        SELECT COUNT(*) as total
                        FROM contas_receber
                        WHERE order_id = ?
                    ');
                    $pgtoStmt->execute([$doc['id']]);
                    $parcelas = $pgtoStmt->fetch(PDO::FETCH_ASSOC);
                    if ($parcelas && (int)$parcelas['total'] > 1) {
                        $indPgto = '1'; // A prazo
                    }
                } catch (\Exception $e) {
                    // Ignorar
                }
                
                // C100 - Documento Nota Fiscal (Saída - Venda)
                // IND_OPER: 0=Entrada, 1=Saída
                // IND_EMIT: 0=Emissão de terceiros, 1=Emissão própria
                // Para notas de saída (vendas), IND_OPER=1 e IND_EMIT=1 (emissão própria)
                $lines[] = $this->gerarLinha('C100', [
                    'IND_OPER' => '1', // 1 = Saída (venda)
                    'IND_EMIT' => '1', // 1 = Emissão própria (nota de saída)
                    'COD_PART' => $this->getCodigoParticipante($doc['cliente_id']),
                    'COD_MOD' => '55', // 55 = NF-e
                    'COD_SIT' => $doc['cod_situacao'] ?? '00', // 00 = Documento regular
                    'SER' => str_pad($doc['serie'] ?? '1', 3, '0', STR_PAD_LEFT),
                    'NUM_DOC' => str_pad($doc['numero'], 9, '0', STR_PAD_LEFT),
                    'CHV_NFE' => $this->getChaveAcessoNFE($doc['id']),
                    'DT_DOC' => date('dmY', strtotime($doc['data_emissao'])),
                    'DT_E_S' => date('dmY', strtotime($doc['data_emissao'])),
                    'VL_DOC' => number_format($doc['valor_total'], 2, ',', ''),
                    'IND_PGTO' => $indPgto, // 0 = À vista, 1 = A prazo
                    'VL_DESC' => number_format($valorDesconto, 2, ',', ''),
                    'VL_ABAT_NT' => '0,00',
                    'VL_MERC' => number_format($valorMercadorias, 2, ',', ''),
                    'IND_FRT' => $valorFrete > 0 ? '0' : '9', // 0 = Por conta do emitente, 9 = Sem frete
                    'VL_FRT' => number_format($valorFrete, 2, ',', ''),
                    'VL_SEG' => '0,00',
                    'VL_OUT_DA' => '0,00',
                    'VL_BC_ICMS' => number_format($valorICMS > 0 ? ($valorICMS / 0.18) : 0, 2, ',', ''),
                    'VL_ICMS' => number_format($valorICMS, 2, ',', ''),
                    'VL_BC_ICMS_ST' => '0,00',
                    'VL_ICMS_ST' => '0,00',
                    'VL_IPI' => number_format($valorIPI, 2, ',', ''),
                    'VL_PIS' => number_format($this->calcularPisDocumento($doc['id']), 2, ',', ''),
                    'VL_COFINS' => number_format($this->calcularCofinsDocumento($doc['id']), 2, ',', ''),
                    'VL_PIS_ST' => '0,00',
                    'VL_COFINS_ST' => '0,00',
                ]);

                // C170 - Itens do documento
                $itens = $this->buscarItensDocumento($doc['id']);
                foreach ($itens as $item) {
                    // Buscar valores de impostos do item
                    $itemICMS = (float)($item['valor_icms'] ?? 0);
                    $itemIPI = (float)($item['valor_ipi'] ?? 0);
                    $itemDesconto = (float)($item['desconto'] ?? 0);
                    $itemBaseICMS = (float)($item['base_icms'] ?? $item['valor_total']);
                    $aliqICMS = 0;
                    if ($itemBaseICMS > 0 && $itemICMS > 0) {
                        $aliqICMS = ($itemICMS / $itemBaseICMS) * 100;
                    }
                    
                    // Calcular base de cálculo de PIS e COFINS (valor do item - desconto)
                    $basePisCofins = max(0, $item['valor_total'] - $itemDesconto);
                    $valorPisItem = $basePisCofins * 0.0165; // 1,65%
                    $valorCofinsItem = $basePisCofins * 0.076; // 7,6%
                    
                    // Buscar CST PIS/COFINS do produto ou usar padrão
                    $cstPis = $item['cst_pis'] ?? '01'; // 01 = Operação tributável (alíquota normal)
                    $cstCofins = $item['cst_cofins'] ?? '01'; // 01 = Operação tributável (alíquota normal)
                    $cstIcms = $item['cst_icms'] ?? '000';
                    $cfop = $item['cfop'] ?? '5102';
                    
                    $lines[] = $this->gerarLinha('C170', [
                        'NUM_ITEM' => str_pad($item['sequencia'], 3, '0', STR_PAD_LEFT),
                        'COD_ITEM' => $item['codigo_produto'],
                        'DESCR_COMPL' => substr($item['descricao'], 0, 255),
                        'QTD' => number_format($item['quantidade'], 3, ',', ''),
                        'UN' => substr($item['unidade'] ?? 'UN', 0, 6),
                        'VL_ITEM' => number_format($item['valor_total'], 2, ',', ''),
                        'VL_DESC' => number_format($itemDesconto, 2, ',', ''),
                        'IND_MOV' => '0', // 0 = Não movimenta estoque
                        'CST_ICMS' => str_pad($cstIcms, 3, '0', STR_PAD_LEFT),
                        'CFOP' => $cfop,
                        'COD_NAT' => '', // Código da natureza da operação
                        'VL_BC_ICMS' => number_format($itemBaseICMS, 2, ',', ''),
                        'ALIQ_ICMS' => number_format($aliqICMS, 2, ',', ''),
                        'VL_ICMS' => number_format($itemICMS, 2, ',', ''),
                        'VL_BC_ICMS_ST' => '0,00',
                        'ALIQ_ST' => '0,00',
                        'VL_ICMS_ST' => '0,00',
                        'IND_APUR' => '0', // 0 = Apuração no momento da operação
                        'CST_IPI' => $item['cst_ipi'] ?? '99', // 99 = Outras entradas
                        'COD_ENQ' => '', // Código de enquadramento do IPI
                        'VL_BC_IPI' => number_format($item['valor_total'], 2, ',', ''),
                        'ALIQ_IPI' => number_format($itemIPI > 0 ? ($itemIPI / $item['valor_total']) * 100 : 0, 2, ',', ''),
                        'VL_IPI' => number_format($itemIPI, 2, ',', ''),
                        'CST_PIS' => str_pad($cstPis, 2, '0', STR_PAD_LEFT),
                        'VL_BC_PIS' => number_format($basePisCofins, 2, ',', ''),
                        'ALIQ_PIS' => number_format(1.65, 2, ',', ''),
                        'QUANT_BC_PIS' => number_format($item['quantidade'], 3, ',', ''),
                        'ALIQ_PIS_QUANT' => '0,0000',
                        'VL_PIS' => number_format($valorPisItem, 2, ',', ''),
                        'CST_COFINS' => str_pad($cstCofins, 2, '0', STR_PAD_LEFT),
                        'VL_BC_COFINS' => number_format($basePisCofins, 2, ',', ''),
                        'ALIQ_COFINS' => number_format(7.60, 2, ',', ''),
                        'QUANT_BC_COFINS' => number_format($item['quantidade'], 3, ',', ''),
                        'ALIQ_COFINS_QUANT' => '0,0000',
                        'VL_COFINS' => number_format($valorCofinsItem, 2, ',', ''),
                        'COD_CTA' => '', // Código da conta contábil
                    ]);
                }
            }
        }

        return $lines;
    }

    /**
     * Gera Bloco F - Demais Documentos (PIS e COFINS)
     */
    private function gerarBlocoF(string $dataInicio, string $dataFim, array $opcoes): array {
        $lines = [];
        
        // F001 - Abertura do bloco F
        $lines[] = $this->gerarLinha('F001', [
            'IND_MOV' => '0', // Sem movimento por padrão
        ]);

        // Buscar documentos fiscais para PIS e COFINS
        $stmt = $this->pdo->prepare('
            SELECT 
                id, numero, serie, data_emissao, valor_total,
                valor_pis, valor_cofins, cfop
            FROM nfe_saida
            WHERE DATE(data_emissao) BETWEEN ? AND ?
            AND status = "autorizada"
            ORDER BY data_emissao, numero
        ');
        $stmt->execute([$dataInicio, $dataFim]);
        $documentos = $stmt->fetchAll(PDO::FETCH_ASSOC);

        if (count($documentos) > 0) {
            // Atualizar F001 para indicar movimento
            $lines[count($lines) - 1] = $this->gerarLinha('F001', [
                'IND_MOV' => '1', // Com movimento
            ]);

            // Agrupar por CFOP para F100 (PIS)
            $pisPorCFOP = [];
            $cofinsPorCFOP = [];
            
            foreach ($documentos as $doc) {
                $cfop = $doc['cfop'] ?? '5102';
                $valorPis = (float)($doc['valor_pis'] ?? 0);
                $valorCofins = (float)($doc['valor_cofins'] ?? 0);
                
                // Se não tiver PIS/COFINS calculados, calcular
                if ($valorPis == 0 || $valorCofins == 0) {
                    $valorTotal = (float)$doc['valor_total'];
                    $valorPis = $valorTotal * 0.0165; // 1,65%
                    $valorCofins = $valorTotal * 0.076; // 7,6%
                }
                
                if (!isset($pisPorCFOP[$cfop])) {
                    $pisPorCFOP[$cfop] = 0;
                    $cofinsPorCFOP[$cfop] = 0;
                }
                
                $pisPorCFOP[$cfop] += $valorPis;
                $cofinsPorCFOP[$cfop] += $valorCofins;
            }

            // F100 - Apuração do PIS
            foreach ($pisPorCFOP as $cfop => $valorPis) {
                $lines[] = $this->gerarLinha('F100', [
                    'IND_OPER' => '0', // 0 = Operação de entrada, 1 = Operação de saída
                    'COD_PART' => '', // Código do participante (cliente/fornecedor)
                    'COD_ITEM' => '', // Código do item
                    'DT_OPER' => date('dmY', strtotime($dataInicio)), // Data da operação
                    'VL_OPER' => number_format($valorPis / 0.0165, 2, ',', ''), // Valor da operação (base de cálculo)
                    'CST_PIS' => '01', // Código de Situação Tributária do PIS
                    'VL_BC_PIS' => number_format($valorPis / 0.0165, 2, ',', ''), // Base de cálculo do PIS
                    'ALIQ_PIS' => '1,65', // Alíquota do PIS (%)
                    'VL_PIS' => number_format($valorPis, 2, ',', ''), // Valor do PIS
                    'COD_CTA' => '', // Código da conta contábil
                    'COD_CCUS' => '', // Código do centro de custo
                    'DESC_DOC_OPER' => '', // Descrição do documento/operação
                ]);
            }

            // F200 - Apuração do COFINS
            foreach ($cofinsPorCFOP as $cfop => $valorCofins) {
                $lines[] = $this->gerarLinha('F200', [
                    'IND_OPER' => '0', // 0 = Operação de entrada, 1 = Operação de saída
                    'COD_PART' => '', // Código do participante
                    'COD_ITEM' => '', // Código do item
                    'DT_OPER' => date('dmY', strtotime($dataInicio)), // Data da operação
                    'VL_OPER' => number_format($valorCofins / 0.076, 2, ',', ''), // Valor da operação (base de cálculo)
                    'CST_COFINS' => '01', // Código de Situação Tributária do COFINS
                    'VL_BC_COFINS' => number_format($valorCofins / 0.076, 2, ',', ''), // Base de cálculo do COFINS
                    'ALIQ_COFINS' => '7,60', // Alíquota do COFINS (%)
                    'VL_COFINS' => number_format($valorCofins, 2, ',', ''), // Valor do COFINS
                    'COD_CTA' => '', // Código da conta contábil
                    'COD_CCUS' => '', // Código do centro de custo
                    'DESC_DOC_OPER' => '', // Descrição do documento/operação
                ]);
            }
        }

        return $lines;
    }

    /**
     * Gera Bloco M - Apuração
     */
    private function gerarBlocoM(array $totais, array $opcoes): array {
        $lines = [];
        
        // M001 - Abertura do bloco M
        $lines[] = $this->gerarLinha('M001', [
            'IND_MOV' => '1', // Com movimento
        ]);

        // M100 - Apuração do PIS
        $lines[] = $this->gerarLinha('M100', [
            'COD_CRED' => '101', // Crédito de PIS sobre receitas
            'IND_CRED_ORI' => '0', // Crédito originado de operações próprias
            'VL_TOT_CRED_APU' => number_format($totais['total_pis'], 2, ',', ''),
            'VL_TOT_CRED_UTIL' => number_format($totais['total_pis'], 2, ',', ''),
            'VL_SLD_CRED_FIM' => '0,00',
        ]);

        // M200 - Apuração do COFINS
        $lines[] = $this->gerarLinha('M200', [
            'COD_CRED' => '201', // Crédito de COFINS sobre receitas
            'IND_CRED_ORI' => '0', // Crédito originado de operações próprias
            'VL_TOT_CRED_APU' => number_format($totais['total_cofins'], 2, ',', ''),
            'VL_TOT_CRED_UTIL' => number_format($totais['total_cofins'], 2, ',', ''),
            'VL_SLD_CRED_FIM' => '0,00',
        ]);

        // M300 - Apuração do CSLL
        if (isset($totais['total_csll']) && $totais['total_csll'] > 0) {
            $lines[] = $this->gerarLinha('M300', [
                'COD_CONT' => '01', // CSLL
                'VL_CONT_APUR_DIFER' => number_format($totais['total_csll'], 2, ',', ''),
                'VL_CONT_APUR' => number_format($totais['total_csll'], 2, ',', ''),
            ]);
        }

        // M400 - Apuração do IRPJ
        if (isset($totais['total_irpj']) && $totais['total_irpj'] > 0) {
            $lines[] = $this->gerarLinha('M400', [
                'COD_CONT' => '02', // IRPJ
                'VL_CONT_APUR_DIFER' => number_format($totais['total_irpj'], 2, ',', ''),
                'VL_CONT_APUR' => number_format($totais['total_irpj'], 2, ',', ''),
            ]);
        }

        // Nota: INSS sobre folha de pagamento não é registrado no SPED Contribuições
        // O SPED Contribuições foca em PIS e COFINS sobre receitas
        // INSS é calculado e pago separadamente (GPS - Guia da Previdência Social)

        return $lines;
    }

    /**
     * Busca itens de um documento fiscal
     */
    private function buscarItensDocumento(int $documentoId): array {
        $stmt = $this->pdo->prepare('
            SELECT 
                id, sequencia, product_id, quantidade, valor_unitario, valor_total,
                desconto, cfop, cst_icms, cst_ipi, cst_pis, cst_cofins,
                valor_icms, valor_ipi, base_icms, aliquota_icms
            FROM nfe_saida_itens
            WHERE nfe_saida_id = ?
            ORDER BY sequencia
        ');
        $stmt->execute([$documentoId]);
        $itens = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $result = [];
        foreach ($itens as $item) {
            // Buscar dados do produto
            $prodStmt = $this->pdo->prepare('
                SELECT codigo, nome, unidade, ncm, cest, ex_tipi
                FROM products 
                WHERE id = ?
            ');
            $prodStmt->execute([$item['product_id']]);
            $produto = $prodStmt->fetch(PDO::FETCH_ASSOC);

            // Buscar CST PIS/COFINS do produto (pode estar em grupo tributário)
            $cstPis = $item['cst_pis'] ?? null;
            $cstCofins = $item['cst_cofins'] ?? null;
            
            if (!$cstPis || !$cstCofins) {
                // Tentar buscar do grupo tributário do produto
                try {
                    $taxStmt = $this->pdo->prepare('
                        SELECT 
                            tg.cst_pis, tg.cst_cofins
                        FROM products p
                        LEFT JOIN tax_groups tg ON tg.id = p.tax_group_id
                        WHERE p.id = ?
                    ');
                    $taxStmt->execute([$item['product_id']]);
                    $tax = $taxStmt->fetch(PDO::FETCH_ASSOC);
                    if ($tax) {
                        $cstPis = $cstPis ?? $tax['cst_pis'] ?? '01';
                        $cstCofins = $cstCofins ?? $tax['cst_cofins'] ?? '01';
                    }
                } catch (\Exception $e) {
                    // Ignorar
                }
            }
            
            $result[] = [
                'sequencia' => (int)$item['sequencia'],
                'codigo_produto' => $produto['codigo'] ?? '',
                'descricao' => $produto['nome'] ?? '',
                'quantidade' => (float)$item['quantidade'],
                'valor_total' => (float)$item['valor_total'],
                'valor_unitario' => (float)$item['valor_unitario'],
                'unidade' => $produto['unidade'] ?? 'UN',
                'cfop' => $item['cfop'] ?? '5102',
                'cst_icms' => $item['cst_icms'] ?? '000',
                'cst_ipi' => $item['cst_ipi'] ?? '99',
                'cst_pis' => $cstPis ?? '01',
                'cst_cofins' => $cstCofins ?? '01',
                'valor_icms' => (float)($item['valor_icms'] ?? 0),
                'valor_ipi' => (float)($item['valor_ipi'] ?? 0),
                'base_icms' => (float)($item['base_icms'] ?? $item['valor_total']),
                'aliquota_icms' => (float)($item['aliquota_icms'] ?? 0),
                'desconto' => (float)($item['desconto'] ?? 0),
                'ncm' => $produto['ncm'] ?? '',
                'cest' => $produto['cest'] ?? '',
                'ex_tipi' => $produto['ex_tipi'] ?? '',
            ];
        }

        return $result;
    }

    /**
     * Calcula PIS de um documento
     */
    private function calcularPisDocumento(int $documentoId): float {
        $stmt = $this->pdo->prepare('
            SELECT COALESCE(SUM(valor_pis), 0) as total
            FROM nfe_saida_itens
            WHERE nfe_saida_id = ?
        ');
        $stmt->execute([$documentoId]);
        $total = (float)$stmt->fetchColumn();

        if ($total == 0) {
            // Calcular baseado no total do documento
            $docStmt = $this->pdo->prepare('SELECT valor_total FROM nfe_saida WHERE id = ?');
            $docStmt->execute([$documentoId]);
            $valorTotal = (float)$docStmt->fetchColumn();
            return $valorTotal * 0.0165; // 1,65%
        }

        return $total;
    }

    /**
     * Calcula COFINS de um documento
     */
    private function calcularCofinsDocumento(int $documentoId): float {
        $stmt = $this->pdo->prepare('
            SELECT COALESCE(SUM(valor_cofins), 0) as total
            FROM nfe_saida_itens
            WHERE nfe_saida_id = ?
        ');
        $stmt->execute([$documentoId]);
        $total = (float)$stmt->fetchColumn();

        if ($total == 0) {
            // Calcular baseado no total do documento
            $docStmt = $this->pdo->prepare('SELECT valor_total FROM nfe_saida WHERE id = ?');
            $docStmt->execute([$documentoId]);
            $valorTotal = (float)$docStmt->fetchColumn();
            return $valorTotal * 0.076; // 7,6%
        }

        return $total;
    }

    /**
     * Obtém código do participante (cliente/fornecedor)
     */
    private function getCodigoParticipante(?int $clienteId): string {
        if (!$clienteId) {
            return '';
        }

        // Buscar código do cliente (pode ser CPF/CNPJ)
        try {
            $stmt = $this->pdo->prepare('SELECT cpf, cnpj, codigo FROM clients WHERE id = ?');
            $stmt->execute([$clienteId]);
            $cliente = $stmt->fetch(PDO::FETCH_ASSOC);

            if ($cliente) {
                // Priorizar CNPJ, depois CPF, depois código
                if (!empty($cliente['cnpj'])) {
                    return preg_replace('/[^0-9]/', '', $cliente['cnpj']);
                } elseif (!empty($cliente['cpf'])) {
                    return preg_replace('/[^0-9]/', '', $cliente['cpf']);
                } elseif (!empty($cliente['codigo'])) {
                    return $cliente['codigo'];
                }
            }
        } catch (\Exception $e) {
            // Tabela pode não existir ou campos podem não existir
        }

        return '';
    }

    /**
     * Obtém chave de acesso da NF-e
     */
    private function getChaveAcessoNFE(int $nfeId): string {
        try {
            $stmt = $this->pdo->prepare('SELECT chave_acesso FROM nfe_saida WHERE id = ?');
            $stmt->execute([$nfeId]);
            $nfe = $stmt->fetch(PDO::FETCH_ASSOC);
            return $nfe['chave_acesso'] ?? '';
        } catch (\Exception $e) {
            return '';
        }
    }

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

    /**
     * Obtém nome da empresa
     */
    private function getNomeEmpresa(): string {
        $empresa = $this->getDadosEmpresa();
        return $empresa['razao_social'] ?? $empresa['nome'] ?? 'EMPRESA NÃO CADASTRADA';
    }

    /**
     * Obtém CNPJ
     */
    private function getCNPJ(): string {
        $empresa = $this->getDadosEmpresa();
        $cnpj = preg_replace('/[^0-9]/', '', $empresa['cnpj'] ?? '');
        return str_pad($cnpj, 14, '0', STR_PAD_LEFT);
    }
}

