<?php

namespace App\Controllers;

use Exception;

class ImportacaoController extends BaseController
{
    /**
     * Exibe página de importação
     */
    public function index(): void
    {
        // Verificar se o usuário é admin ou tem permissão de suporte
        $user = $this->session->get('user');
        if (!$user || ($user['role'] !== 'admin' && $user['role'] !== 'suporte')) {
            $this->response->forbidden('Acesso negado. Área restrita ao suporte.');
            return;
        }

        $this->view('importacao/index', [
            'pageTitle' => 'Importação de Dados',
            'activeMenu' => 'importacao'
        ]);
    }

    /**
     * Gera template CSV para uma tabela específica
     */
    public function gerarTemplate(): void
    {
        // Verificar se o usuário é admin ou tem permissão de suporte
        $user = $this->session->get('user');
        if (!$user || ($user['role'] !== 'admin' && $user['role'] !== 'suporte')) {
            $this->response->forbidden('Acesso negado.');
            return;
        }

        $tabela = $this->request->get('tabela');
        $templates = $this->getTemplates();

        if (!isset($templates[$tabela])) {
            $this->response->notFound('Template não encontrado.');
            return;
        }

        $campos = $templates[$tabela];
        $nomeArquivo = "template_{$tabela}_" . date('Y-m-d') . ".csv";

        // Headers para download
        header('Content-Type: text/csv; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $nomeArquivo . '"');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Pragma: public');

        // Adicionar BOM para UTF-8 (Excel)
        echo "\xEF\xBB\xBF";

        // Criar arquivo CSV
        $output = fopen('php://output', 'w');

        // Escrever cabeçalhos
        fputcsv($output, $campos, ';');

        // Escrever linha de exemplo (opcional)
        $exemplo = array_fill(0, count($campos), '');
        fputcsv($output, $exemplo, ';');

        fclose($output);
        exit;
    }

    /**
     * Processa upload e importação de arquivo
     */
    public function processarImportacao(): void
    {
        // Log inicial para confirmar que o método está sendo executado
        error_log("ImportacaoController::processarImportacao() - INÍCIO");

        // Aumentar limite de memória para importações grandes (especialmente contas_receber)
        ini_set('memory_limit', '512M');
        set_time_limit(300); // 5 minutos

        // Verificar se o usuário é admin ou tem permissão de suporte
        $user = $this->session->get('user');
        if (!$user || ($user['role'] !== 'admin' && $user['role'] !== 'suporte')) {
            error_log("ImportacaoController::processarImportacao() - Acesso negado. User: " . json_encode($user));
            $this->error('Acesso negado. Área restrita ao suporte.');
            return;
        }

        error_log("ImportacaoController::processarImportacao() - Usuário autenticado: " . ($user['name'] ?? 'N/A'));

        try {
            $companyId = $this->getCompanyId();

            // IMPORTANTE: Com multipart/form-data, verificar $_POST diretamente no momento da execução
            // O Request pode ter cacheado $_POST quando ainda estava vazio
            error_log("ImportacaoController: Verificando tabela...");
            error_log("ImportacaoController: _POST keys: " . json_encode(array_keys($_POST)));
            error_log("ImportacaoController: _POST completo: " . json_encode($_POST));
            error_log("ImportacaoController: _FILES keys: " . json_encode(array_keys($_FILES)));

            $tabela = null;

            // Primeiro verifica $_POST diretamente (mais confiável para multipart/form-data)
            if (isset($_POST['tabela'])) {
                error_log("ImportacaoController: _POST['tabela'] encontrado: " . var_export($_POST['tabela'], true));
                $tabelaValue = trim((string)$_POST['tabela']);
                if (!empty($tabelaValue)) {
                    $tabela = $tabelaValue;
                }
            } else {
                error_log("ImportacaoController: _POST['tabela'] NÃO encontrado");
            }

            // Se não encontrou, tenta através do Request (que agora verifica $_POST dinamicamente)
            if (empty($tabela)) {
                $requestTabela = $this->request->post('tabela');
                error_log("ImportacaoController: request->post('tabela'): " . var_export($requestTabela, true));
                if ($requestTabela) {
                    $tabelaValue = trim((string)$requestTabela);
                    if (!empty($tabelaValue)) {
                        $tabela = $tabelaValue;
                    }
                }
            }

            // Última tentativa: input (verifica GET e POST)
            if (empty($tabela)) {
                $inputTabela = $this->request->input('tabela');
                error_log("ImportacaoController: request->input('tabela'): " . var_export($inputTabela, true));
                if ($inputTabela) {
                    $tabelaValue = trim((string)$inputTabela);
                    if (!empty($tabelaValue)) {
                        $tabela = $tabelaValue;
                    }
                }
            }

            if (empty($tabela)) {
                // Log detalhado para debug
                error_log("ImportacaoController: ========== DEBUG TABELA NÃO ENCONTRADA ==========");
                error_log("ImportacaoController: _POST completo: " . json_encode($_POST));
                error_log("ImportacaoController: _POST['tabela']: " . var_export($_POST['tabela'] ?? 'NÃO DEFINIDO', true));
                error_log("ImportacaoController: request->post('tabela'): " . var_export($this->request->post('tabela'), true));
                error_log("ImportacaoController: request->all(): " . json_encode($this->request->all()));
                error_log("ImportacaoController: Content-Type: " . ($_SERVER['CONTENT_TYPE'] ?? 'não definido'));
                error_log("ImportacaoController: REQUEST_METHOD: " . ($_SERVER['REQUEST_METHOD'] ?? 'não definido'));
                error_log("ImportacaoController: _FILES: " . json_encode($_FILES));
                error_log("ImportacaoController: =================================================");

                $this->error('Tabela não especificada. Verifique se selecionou uma tabela no formulário e tente novamente.');
                return;
            }

            error_log("ImportacaoController: ✅ Tabela recebida com sucesso: " . $tabela);

            if (!isset($_FILES['arquivo']) || $_FILES['arquivo']['error'] !== UPLOAD_ERR_OK) {
                $errorMsg = 'Erro ao fazer upload do arquivo.';
                if ($_FILES['arquivo']['error'] === UPLOAD_ERR_INI_SIZE || $_FILES['arquivo']['error'] === UPLOAD_ERR_FORM_SIZE) {
                    $errorMsg = 'Arquivo muito grande. Tamanho máximo: ' . ($tabela === 'contas_receber' ? '25MB' : '10MB') . '.';
                }
                $this->error($errorMsg);
                return;
            }

            $arquivo = $_FILES['arquivo'];
            $extensao = strtolower(pathinfo($arquivo['name'], PATHINFO_EXTENSION));

            if (!in_array($extensao, ['csv', 'xls', 'xlsx'])) {
                $this->error('Formato de arquivo não suportado. Use CSV, XLS ou XLSX.');
                return;
            }

            // Validar tamanho do arquivo (25MB para contas_receber, 10MB para outros)
            $maxSize = $tabela === 'contas_receber' ? 25 * 1024 * 1024 : 10 * 1024 * 1024;
            $maxSizeMB = $tabela === 'contas_receber' ? '25MB' : '10MB';

            if ($arquivo['size'] > $maxSize) {
                $this->error("Arquivo muito grande. Tamanho máximo: {$maxSizeMB}.");
                return;
            }

            // Ler dados do arquivo
            $dados = $this->lerArquivo($arquivo['tmp_name'], $extensao);

            if (empty($dados)) {
                $this->error('Arquivo vazio ou inválido.');
                return;
            }

            // Validar estrutura
            $templates = $this->getTemplates();
            if (!isset($templates[$tabela])) {
                $this->error('Tabela não suportada para importação.');
                return;
            }

            $camposEsperados = $templates[$tabela];
            $primeiraLinha = reset($dados);
            $camposRecebidos = array_keys($primeiraLinha);

            // Validar se campos obrigatórios estão presentes
            // Para pessoas, campos obrigatórios são: type, person_type, name
            $camposObrigatorios = [];
            if ($tabela === 'pessoas') {
                $camposObrigatorios = ['type', 'person_type', 'name'];
            } elseif ($tabela === 'plano_contas') {
                $camposObrigatorios = ['code', 'name'];
            } elseif ($tabela === 'centro_custos') {
                $camposObrigatorios = ['code', 'name'];
            } elseif ($tabela === 'impostos') {
                $camposObrigatorios = ['nome'];
            } elseif ($tabela === 'estoque') {
                $camposObrigatorios = ['name'];
            } elseif ($tabela === 'contas_receber') {
                $camposObrigatorios = ['description', 'amount', 'due_date'];
            }

            $camposFaltando = array_diff($camposObrigatorios, $camposRecebidos);
            if (!empty($camposFaltando)) {
                $this->error('Campos obrigatórios faltando no arquivo: ' . implode(', ', $camposFaltando));
                return;
            }

            // Importar dados
            $resultado = $this->importarDados($tabela, $dados, $companyId);

            $this->success('Importação concluída com sucesso', [
                'total' => $resultado['total'],
                'inseridos' => $resultado['inseridos'],
                'atualizados' => $resultado['atualizados'],
                'erros' => $resultado['erros']
            ]);

        } catch (Exception $e) {
            error_log("Erro ao processar importação: " . $e->getMessage());
            $this->error('Erro ao processar importação: ' . $e->getMessage());
        }
    }

    /**
     * Retorna templates de campos para cada tabela
     */
    private function getTemplates(): array
    {
        return [
            'pessoas' => [
                'type',
                'person_type',
                'name',
                'trade_name',
                'document',
                'rg_ie',
                'inscricao_municipal',
                'inscricao_suframa',
                'passaporte',
                'cnh',
                'email',
                'phone',
                'mobile',
                'website',
                'skype',
                'address',
                'numero',
                'complemento',
                'bairro',
                'city',
                'state',
                'zip_code',
                'notes',
                'credit_limit',
                'payment_terms',
                'tabela_preco_id',
                'grupo_nome',
                'subgrupo_nome',
                'send_email',
                'send_sms',
                'is_vip',
                'is_active',
                'tipo_cliente',
                'tipo_fornecedor',
                'tipo_transportadora'
            ],
            'plano_contas' => [
                'code',
                'name',
                'type',
                'parent_code',
                'is_active'
            ],
            'centro_custos' => [
                'code',
                'name',
                'parent_code',
                'notes',
                'is_active'
            ],
            'impostos' => [
                'nome',
                'ncm',
                'cest',
                'uf_origem',
                'cst_csosn',
                'icms',
                'cfop',
                'uf_destino',
                'cst_csosn_st',
                'icms_st',
                'mva',
                'cfop_st',
                'cst_ipi',
                'ipi',
                'cst_pis',
                'pis',
                'cst_cofins',
                'cofins',
                'ativo'
            ],
            'estoque' => [
                'code',
                'barcode',
                'name',
                'description',
                'type',
                'unit',
                'cost_price',
                'sale_price',
                'stock_quantity',
                'min_stock',
                'max_stock',
                'grupo_id',
                'is_active'
            ],
            'contas_receber' => [
                'customer_document',
                'customer_name',
                'description',
                'amount',
                'amount_received',
                'due_date',
                'payment_date',
                'bank_account',
                'status',
                'payment_method',
                'conta_bancaria_nome',
                'plano_conta_code',
                'centro_custo_code',
                'notes',
                'nosso_numero_boleto',
                'codigo_solicitacao_boleto',
                'linha_digitavel',
                'codigo_barras',
                'boleto_pdf_url',
                'pix_qrcode',
                'pix_txid',
                'boleto_status',
                'boleto_emitido_em',
                'shipay_charge_id',
                'shipay_status',
                'shipay_linha_digitavel',
                'shipay_qr_code',
                'shipay_pdf_url',
                'shipay_codigo_barras',
                'shipay_tipo',
                'shipay_due_date'
            ]
        ];
    }

    /**
     * Lê arquivo CSV ou Excel
     */
    private function lerArquivo(string $caminho, string $extensao): array
    {
        $dados = [];

        if ($extensao === 'csv') {
            // Ler CSV
            $handle = fopen($caminho, 'r');
            if ($handle === false) {
                throw new Exception('Erro ao abrir arquivo CSV.');
            }

            // Detectar delimitador
            $primeiraLinha = fgets($handle);
            rewind($handle);
            $delimitador = (strpos($primeiraLinha, ';') !== false) ? ';' : ',';

            // Ler cabeçalho
            $cabecalho = fgetcsv($handle, 0, $delimitador);
            if ($cabecalho === false) {
                fclose($handle);
                throw new Exception('Erro ao ler cabeçalho do arquivo.');
            }

            // Limpar BOM se existir
            if (!empty($cabecalho[0]) && substr($cabecalho[0], 0, 3) === "\xEF\xBB\xBF") {
                $cabecalho[0] = substr($cabecalho[0], 3);
            }

            // Limpar espaços dos cabeçalhos
            $cabecalho = array_map('trim', $cabecalho);

            // Ler linhas
            while (($linha = fgetcsv($handle, 0, $delimitador)) !== false) {
                if (count($linha) !== count($cabecalho)) {
                    continue; // Pular linhas incompletas
                }

                $registro = [];
                foreach ($cabecalho as $index => $campo) {
                    $registro[$campo] = isset($linha[$index]) ? trim($linha[$index]) : '';
                }

                // Ignorar linhas vazias
                if (array_filter($registro)) {
                    $dados[] = $registro;
                }
            }

            fclose($handle);
        } else {
            // Ler Excel (XLS/XLSX) - requer biblioteca PhpSpreadsheet
            // Por enquanto, vamos usar uma abordagem simples
            // Em produção, seria necessário instalar: composer require phpoffice/phpspreadsheet
            throw new Exception('Importação de Excel ainda não implementada. Use arquivo CSV.');
        }

        return $dados;
    }

    /**
     * Importa dados para o banco
     */
    private function importarDados(string $tabela, array $dados, int $companyId): array
    {
        $this->db->beginTransaction();

        $resultado = [
            'total' => count($dados),
            'inseridos' => 0,
            'atualizados' => 0,
            'erros' => []
        ];

        try {
            foreach ($dados as $index => $linha) {
                try {
                    $linhaNumero = $index + 2; // +2 porque linha 1 é cabeçalho

                    switch ($tabela) {
                        case 'pessoas':
                            $this->importarPessoa($linha, $companyId, $resultado);
                            break;
                        case 'plano_contas':
                            $this->importarPlanoContas($linha, $companyId, $resultado);
                            break;
                        case 'centro_custos':
                            $this->importarCentroCustos($linha, $companyId, $resultado);
                            break;
                        case 'impostos':
                            $this->importarImposto($linha, $companyId, $resultado);
                            break;
                        case 'estoque':
                            $this->importarEstoque($linha, $companyId, $resultado);
                            break;
                        case 'contas_receber':
                            $this->importarContasReceber($linha, $companyId, $resultado);
                            break;
                        default:
                            throw new Exception("Tabela {$tabela} não suportada.");
                    }
                } catch (Exception $e) {
                    $resultado['erros'][] = [
                        'linha' => $linhaNumero,
                        'erro' => $e->getMessage()
                    ];
                }
            }

            $this->db->commit();
        } catch (Exception $e) {
            $this->db->rollBack();
            throw $e;
        }

        return $resultado;
    }

    /**
     * Importa pessoa
     */
    private function importarPessoa(array $dados, int $companyId, array &$resultado): void
    {
        // Verificar se já existe pelo documento
        $documento = $dados['document'] ?? '';
        $existe = false;
        $pessoaId = null;

        if (!empty($documento)) {
            $stmt = $this->db->prepare("SELECT id FROM pessoas WHERE document = :document AND company_id = :company_id LIMIT 1");
            $stmt->execute(['document' => $documento, 'company_id' => $companyId]);
            $existe = $stmt->fetch();
            if ($existe) {
                $pessoaId = $existe['id'];
            }
        }

        // Buscar grupo_id se grupo_nome foi informado
        $grupoId = null;
        if (!empty($dados['grupo_nome'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM grupos_pessoas
                WHERE nome = :nome AND company_id = :company_id AND ativo = 1
                LIMIT 1
            ");
            $stmt->execute(['nome' => trim($dados['grupo_nome']), 'company_id' => $companyId]);
            $grupo = $stmt->fetch();
            if ($grupo) {
                $grupoId = $grupo['id'];
            }
        }

        // Buscar subgrupo_id se subgrupo_nome foi informado
        $subgrupoId = null;
        if (!empty($dados['subgrupo_nome']) && $grupoId) {
            $stmt = $this->db->prepare("
                SELECT id FROM subgrupos_pessoas
                WHERE nome = :nome AND grupo_id = :grupo_id AND company_id = :company_id AND ativo = 1
                LIMIT 1
            ");
            $stmt->execute([
                'nome' => trim($dados['subgrupo_nome']),
                'grupo_id' => $grupoId,
                'company_id' => $companyId
            ]);
            $subgrupo = $stmt->fetch();
            if ($subgrupo) {
                $subgrupoId = $subgrupo['id'];
            }
        }

        $campos = [
            'company_id' => $companyId,
            'grupo_id' => $grupoId,
            'subgrupo_id' => $subgrupoId,
            'type' => $dados['type'] ?? 'cliente',
            'person_type' => $dados['person_type'] ?? 'fisica',
            'name' => $dados['name'] ?? '',
            'trade_name' => $dados['trade_name'] ?? null,
            'document' => $documento ?: null,
            'rg_ie' => $dados['rg_ie'] ?? null,
            'inscricao_municipal' => !empty($dados['inscricao_municipal']) ? $dados['inscricao_municipal'] : null,
            'inscricao_suframa' => !empty($dados['inscricao_suframa']) ? $dados['inscricao_suframa'] : null,
            'passaporte' => !empty($dados['passaporte']) ? $dados['passaporte'] : null,
            'cnh' => !empty($dados['cnh']) ? $dados['cnh'] : null,
            'email' => $dados['email'] ?? null,
            'phone' => $dados['phone'] ?? null,
            'mobile' => $dados['mobile'] ?? null,
            'website' => !empty($dados['website']) ? $dados['website'] : null,
            'skype' => !empty($dados['skype']) ? $dados['skype'] : null,
            'address' => $dados['address'] ?? null,
            'numero' => $dados['numero'] ?? null,
            'complemento' => $dados['complemento'] ?? null,
            'bairro' => $dados['bairro'] ?? null,
            'city' => $dados['city'] ?? null,
            'state' => $dados['state'] ?? null,
            'zip_code' => $dados['zip_code'] ?? null,
            'notes' => $dados['notes'] ?? null,
            'credit_limit' => $this->parseDecimal($dados['credit_limit'] ?? 0),
            'payment_terms' => (int)($dados['payment_terms'] ?? 30),
            'tabela_preco_id' => !empty($dados['tabela_preco_id']) ? (int)$dados['tabela_preco_id'] : null,
            'send_email' => $this->parseBoolean($dados['send_email'] ?? '0'),
            'send_sms' => $this->parseBoolean($dados['send_sms'] ?? '0'),
            'is_vip' => $this->parseBoolean($dados['is_vip'] ?? '0'),
            'is_active' => $this->parseBoolean($dados['is_active'] ?? '1'),
            'tipo_cliente' => !empty($dados['tipo_cliente']) ? $dados['tipo_cliente'] : null,
            'tipo_fornecedor' => !empty($dados['tipo_fornecedor']) ? $dados['tipo_fornecedor'] : null,
            'tipo_transportadora' => !empty($dados['tipo_transportadora']) ? $dados['tipo_transportadora'] : null
        ];

        if ($existe) {
            // Atualizar
            $sets = [];
            foreach ($campos as $campo => $valor) {
                if ($campo !== 'company_id') {
                    $sets[] = "`{$campo}` = :{$campo}";
                }
            }
            $sql = "UPDATE pessoas SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);
            $campos['id'] = $pessoaId;
            $stmt->execute($campos);
            $resultado['atualizados']++;
        } else {
            // Inserir
            $camposSql = array_keys($campos);
            $valoresSql = ':' . implode(', :', $camposSql);
            $sql = "INSERT INTO pessoas (" . implode(', ', $camposSql) . ") VALUES ({$valoresSql})";
            $stmt = $this->db->prepare($sql);
            $stmt->execute($campos);
            $resultado['inseridos']++;
        }
    }

    /**
     * Importa plano de contas
     */
    private function importarPlanoContas(array $dados, int $companyId, array &$resultado): void
    {
        $code = $dados['code'] ?? '';
        if (empty($code)) {
            throw new Exception('Código é obrigatório.');
        }

        // Verificar se já existe
        $stmt = $this->db->prepare("SELECT id FROM plano_contas WHERE code = :code AND company_id = :company_id LIMIT 1");
        $stmt->execute(['code' => $code, 'company_id' => $companyId]);
        $existe = $stmt->fetch();
        $contaId = $existe ? $existe['id'] : null;

        // Buscar parent_id se parent_code foi informado
        $parentId = null;
        if (!empty($dados['parent_code'])) {
            $stmt = $this->db->prepare("SELECT id FROM plano_contas WHERE code = :code AND company_id = :company_id LIMIT 1");
            $stmt->execute(['code' => $dados['parent_code'], 'company_id' => $companyId]);
            $parent = $stmt->fetch();
            if ($parent) {
                $parentId = $parent['id'];
            }
        }

        $campos = [
            'company_id' => $companyId,
            'code' => $code,
            'name' => $dados['name'] ?? '',
            'type' => $dados['type'] ?? 'despesa',
            'parent_id' => $parentId,
            'is_active' => $this->parseBoolean($dados['is_active'] ?? '1')
        ];

        if ($existe) {
            $sets = [];
            foreach ($campos as $campo => $valor) {
                if ($campo !== 'company_id') {
                    $sets[] = "`{$campo}` = :{$campo}";
                }
            }
            $sql = "UPDATE plano_contas SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);
            $campos['id'] = $contaId;
            $stmt->execute($campos);
            $resultado['atualizados']++;
        } else {
            $camposSql = array_keys($campos);
            $valoresSql = ':' . implode(', :', $camposSql);
            $sql = "INSERT INTO plano_contas (" . implode(', ', $camposSql) . ") VALUES ({$valoresSql})";
            $stmt = $this->db->prepare($sql);
            $stmt->execute($campos);
            $resultado['inseridos']++;
        }
    }

    /**
     * Importa centro de custos
     */
    private function importarCentroCustos(array $dados, int $companyId, array &$resultado): void
    {
        $code = $dados['code'] ?? '';
        if (empty($code)) {
            throw new Exception('Código é obrigatório.');
        }

        // Verificar se já existe
        $stmt = $this->db->prepare("SELECT id FROM centro_custos WHERE code = :code AND company_id = :company_id LIMIT 1");
        $stmt->execute(['code' => $code, 'company_id' => $companyId]);
        $existe = $stmt->fetch();
        $centroId = $existe ? $existe['id'] : null;

        // Buscar parent_id se parent_code foi informado
        $parentId = null;
        if (!empty($dados['parent_code'])) {
            $stmt = $this->db->prepare("SELECT id FROM centro_custos WHERE code = :code AND company_id = :company_id LIMIT 1");
            $stmt->execute(['code' => $dados['parent_code'], 'company_id' => $companyId]);
            $parent = $stmt->fetch();
            if ($parent) {
                $parentId = $parent['id'];
            }
        }

        $campos = [
            'company_id' => $companyId,
            'code' => $code,
            'name' => $dados['name'] ?? '',
            'parent_id' => $parentId,
            'notes' => $dados['notes'] ?? null,
            'is_active' => $this->parseBoolean($dados['is_active'] ?? '1')
        ];

        if ($existe) {
            $sets = [];
            foreach ($campos as $campo => $valor) {
                if ($campo !== 'company_id') {
                    $sets[] = "`{$campo}` = :{$campo}";
                }
            }
            $sql = "UPDATE centro_custos SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);
            $campos['id'] = $centroId;
            $stmt->execute($campos);
            $resultado['atualizados']++;
        } else {
            $camposSql = array_keys($campos);
            $valoresSql = ':' . implode(', :', $camposSql);
            $sql = "INSERT INTO centro_custos (" . implode(', ', $camposSql) . ") VALUES ({$valoresSql})";
            $stmt = $this->db->prepare($sql);
            $stmt->execute($campos);
            $resultado['inseridos']++;
        }
    }

    /**
     * Importa imposto
     */
    private function importarImposto(array $dados, int $companyId, array &$resultado): void
    {
        $nome = $dados['nome'] ?? '';
        if (empty($nome)) {
            throw new Exception('Nome é obrigatório.');
        }

        // Gerar hash único
        $hash = md5($companyId . '_' . $nome . '_' . ($dados['ncm'] ?? ''));

        // Verificar se já existe
        $stmt = $this->db->prepare("SELECT id FROM impostos WHERE hash_imposto = :hash LIMIT 1");
        $stmt->execute(['hash' => $hash]);
        $existe = $stmt->fetch();
        $impostoId = $existe ? $existe['id'] : null;

        $campos = [
            'company_id' => $companyId,
            'hash_imposto' => $hash,
            'nome' => $nome,
            'ncm' => $dados['ncm'] ?? null,
            'cest' => $dados['cest'] ?? null,
            'uf_origem' => $dados['uf_origem'] ?? null,
            'cst_csosn' => $dados['cst_csosn'] ?? null,
            'icms' => $this->parseDecimal($dados['icms'] ?? 0),
            'cfop' => $dados['cfop'] ?? null,
            'uf_destino' => $dados['uf_destino'] ?? null,
            'cst_csosn_st' => $dados['cst_csosn_st'] ?? null,
            'icms_st' => $this->parseDecimal($dados['icms_st'] ?? 0),
            'mva' => $this->parseDecimal($dados['mva'] ?? 0),
            'cfop_st' => $dados['cfop_st'] ?? null,
            'cst_ipi' => $dados['cst_ipi'] ?? null,
            'ipi' => $this->parseDecimal($dados['ipi'] ?? 0),
            'cst_pis' => $dados['cst_pis'] ?? null,
            'pis' => $this->parseDecimal($dados['pis'] ?? 0),
            'cst_cofins' => $dados['cst_cofins'] ?? null,
            'cofins' => $this->parseDecimal($dados['cofins'] ?? 0),
            'ativo' => $this->parseBooleanImposto($dados['ativo'] ?? 'Sim')
        ];

        if ($existe) {
            $sets = [];
            foreach ($campos as $campo => $valor) {
                if ($campo !== 'company_id' && $campo !== 'hash_imposto') {
                    $sets[] = "`{$campo}` = :{$campo}";
                }
            }
            $sql = "UPDATE impostos SET " . implode(', ', $sets) . " WHERE id = :id";
            $stmt = $this->db->prepare($sql);
            $campos['id'] = $impostoId;
            $stmt->execute($campos);
            $resultado['atualizados']++;
        } else {
            $camposSql = array_keys($campos);
            $valoresSql = ':' . implode(', :', $camposSql);
            $sql = "INSERT INTO impostos (" . implode(', ', $camposSql) . ") VALUES ({$valoresSql})";
            $stmt = $this->db->prepare($sql);
            $stmt->execute($campos);
            $resultado['inseridos']++;
        }
    }

    /**
     * Importa estoque (itens)
     */
    private function importarEstoque(array $dados, int $companyId, array &$resultado): void
    {
        $code = $dados['code'] ?? '';
        $name = $dados['name'] ?? '';

        if (empty($code) && empty($name)) {
            throw new Exception('Código ou nome é obrigatório.');
        }

        // Verificar se já existe
        $stmt = null;
        if (!empty($code)) {
            $stmt = $this->db->prepare("SELECT id FROM itens WHERE code = :code AND company_id = :company_id LIMIT 1");
            $stmt->execute(['code' => $code, 'company_id' => $companyId]);
        } else {
            $stmt = $this->db->prepare("SELECT id FROM itens WHERE name = :name AND company_id = :company_id LIMIT 1");
            $stmt->execute(['name' => $name, 'company_id' => $companyId]);
        }
        $existe = $stmt->fetch();
        $itemId = $existe ? $existe['id'] : null;

        $campos = [
            'company_id' => $companyId,
            'code' => $code ?: null,
            'barcode' => $dados['barcode'] ?? null,
            'name' => $name,
            'description' => $dados['description'] ?? null,
            'type' => $dados['type'] ?? 'produto',
            'unit' => $dados['unit'] ?? 'UN',
            'cost_price' => $this->parseDecimal($dados['cost_price'] ?? 0),
            'sale_price' => $this->parseDecimal($dados['sale_price'] ?? 0),
            'stock_quantity' => $this->parseDecimal($dados['stock_quantity'] ?? 0),
            'min_stock' => $this->parseDecimal($dados['min_stock'] ?? 0),
            'max_stock' => $this->parseDecimal($dados['max_stock'] ?? 0),
            'grupo_id' => !empty($dados['grupo_id']) ? (int)$dados['grupo_id'] : null,
            'is_active' => $this->parseBoolean($dados['is_active'] ?? '1')
        ];

        if ($existe) {
            $sets = [];
            foreach ($campos as $campo => $valor) {
                if ($campo !== 'company_id') {
                    $sets[] = "`{$campo}` = :{$campo}";
                }
            }
            $sql = "UPDATE itens SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);
            $campos['id'] = $itemId;
            $stmt->execute($campos);
            $resultado['atualizados']++;
        } else {
            $camposSql = array_keys($campos);
            $valoresSql = ':' . implode(', :', $camposSql);
            $sql = "INSERT INTO itens (" . implode(', ', $camposSql) . ") VALUES ({$valoresSql})";
            $stmt = $this->db->prepare($sql);
            $stmt->execute($campos);
            $resultado['inseridos']++;
        }
    }

    /**
     * Converte string para decimal
     */
    private function parseDecimal($valor): float
    {
        if (empty($valor)) {
            return 0.0;
        }
        // Remove formatação brasileira
        $valor = str_replace(['.', ','], ['', '.'], (string)$valor);
        return (float)$valor;
    }

    /**
     * Converte string para boolean
     */
    private function parseBoolean($valor, $trueValue = '1', $falseValue = '0'): bool
    {
        if (is_bool($valor)) {
            return $valor;
        }
        $valor = strtolower(trim((string)$valor));
        return in_array($valor, ['1', 'sim', 'yes', 'true', 's', 'y', strtolower($trueValue)]);
    }

    /**
     * Converte string para enum de impostos (Sim/Não)
     */
    private function parseBooleanImposto($valor): string
    {
        if (is_bool($valor)) {
            return $valor ? 'Sim' : 'Não';
        }
        $valor = strtolower(trim((string)$valor));
        return in_array($valor, ['1', 'sim', 'yes', 'true', 's', 'y']) ? 'Sim' : 'Não';
    }

    /**
     * Converte string para data (formato YYYY-MM-DD)
     */
    private function parseDate($valor): ?string
    {
        if (empty($valor)) {
            return null;
        }

        $valor = trim((string)$valor);

        // Se já estiver no formato correto
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $valor)) {
            return $valor;
        }

        // Tentar formatos brasileiros
        if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $valor)) {
            $parts = explode('/', $valor);
            return $parts[2] . '-' . $parts[1] . '-' . $parts[0];
        }

        // Tentar formato DD-MM-YYYY
        if (preg_match('/^\d{2}-\d{2}-\d{4}$/', $valor)) {
            $parts = explode('-', $valor);
            return $parts[2] . '-' . $parts[1] . '-' . $parts[0];
        }

        // Tentar parsear timestamp
        $timestamp = strtotime($valor);
        if ($timestamp !== false) {
            return date('Y-m-d', $timestamp);
        }

        return null;
    }

    /**
     * Importa conta a receber
     */
    private function importarContasReceber(array $dados, int $companyId, array &$resultado): void
    {
        // Validar campos obrigatórios
        if (empty($dados['description'])) {
            throw new Exception('Descrição é obrigatória.');
        }
        if (empty($dados['amount'])) {
            throw new Exception('Valor é obrigatório.');
        }
        if (empty($dados['due_date'])) {
            throw new Exception('Data de vencimento é obrigatória.');
        }

        // Detectar estrutura da tabela
        $stmtCheck = $this->db->query("SHOW COLUMNS FROM contas_receber");
        $columns = $stmtCheck->fetchAll();
        $columnNames = array_column($columns, 'Field');
        $temPessoaId = in_array('pessoa_id', $columnNames);
        $temCustomerId = in_array('customer_id', $columnNames);
        $temAmountPaid = in_array('amount_paid', $columnNames);
        $temAmountReceived = in_array('amount_received', $columnNames);

        // Buscar pessoa_id/customer_id pelo documento ou nome
        $pessoaId = null;
        if (!empty($dados['customer_document'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM pessoas
                WHERE document = :document AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute(['document' => trim($dados['customer_document']), 'company_id' => $companyId]);
            $pessoa = $stmt->fetch();
            if ($pessoa) {
                $pessoaId = $pessoa['id'];
            }
        } elseif (!empty($dados['customer_name'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM pessoas
                WHERE (name = :name OR nome = :name)
                AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute(['name' => trim($dados['customer_name']), 'company_id' => $companyId]);
            $pessoa = $stmt->fetch();
            if ($pessoa) {
                $pessoaId = $pessoa['id'];
            }
        }

        if (!$pessoaId) {
            throw new Exception('Cliente não encontrado. Informe customer_document ou customer_name válido.');
        }

        // Buscar conta_bancaria_id se informado
        $contaBancariaId = null;
        if (!empty($dados['conta_bancaria_nome'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM contas_bancarias
                WHERE (bank_name = :nome OR name = :nome)
                AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute(['nome' => trim($dados['conta_bancaria_nome']), 'company_id' => $companyId]);
            $conta = $stmt->fetch();
            if ($conta) {
                $contaBancariaId = $conta['id'];
            }
        }

        // Buscar plano_conta_id se informado
        $planoContaId = null;
        if (!empty($dados['plano_conta_code'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM plano_contas
                WHERE code = :code AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute(['code' => trim($dados['plano_conta_code']), 'company_id' => $companyId]);
            $plano = $stmt->fetch();
            if ($plano) {
                $planoContaId = $plano['id'];
            }
        }

        // Buscar centro_custo_id se informado
        $centroCustoId = null;
        if (!empty($dados['centro_custo_code'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM centro_custos
                WHERE code = :code AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute(['code' => trim($dados['centro_custo_code']), 'company_id' => $companyId]);
            $centro = $stmt->fetch();
            if ($centro) {
                $centroCustoId = $centro['id'];
            }
        }

        // Parsear valores
        $amount = $this->parseDecimal($dados['amount']);
        $amountPaid = $this->parseDecimal($dados['amount_received'] ?? $dados['amount_paid'] ?? 0);
        $amountRemaining = $amount - $amountPaid;

        // Parsear datas
        $dueDate = $this->parseDate($dados['due_date']);
        if (!$dueDate) {
            throw new Exception('Data de vencimento inválida.');
        }

        $paymentDate = null;
        if (!empty($dados['payment_date'])) {
            $paymentDate = $this->parseDate($dados['payment_date']);
        }

        $boletoEmitidoEm = null;
        if (!empty($dados['boleto_emitido_em'])) {
            $boletoEmitidoEm = $this->parseDate($dados['boleto_emitido_em']);
        }

        $shipayDueDate = null;
        if (!empty($dados['shipay_due_date'])) {
            $shipayDueDate = $this->parseDate($dados['shipay_due_date']);
        }

        // Determinar status se não informado
        $status = $dados['status'] ?? '';
        if (empty($status)) {
            if ($amountPaid > 0 && $amountPaid >= $amount) {
                $status = $temAmountPaid ? 'pago' : 'pago';
            } elseif ($amountPaid > 0) {
                $status = $temAmountPaid ? 'pago_parcial' : 'parcial';
            } elseif (strtotime($dueDate) < strtotime(date('Y-m-d'))) {
                $status = 'vencido';
            } else {
                $status = 'pendente';
            }
        }

        // Verificar se já existe (por description + pessoa_id/customer_id + due_date ou nosso_numero_boleto)
        $existe = false;
        $contaId = null;

        if (!empty($dados['nosso_numero_boleto'])) {
            $stmt = $this->db->prepare("
                SELECT id FROM contas_receber
                WHERE nosso_numero_boleto = :nosso_numero
                AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute([
                'nosso_numero' => $dados['nosso_numero_boleto'],
                'company_id' => $companyId
            ]);
            $conta = $stmt->fetch();
            if ($conta) {
                $existe = true;
                $contaId = $conta['id'];
            }
        }

        if (!$existe) {
            $campoPessoa = $temPessoaId ? 'pessoa_id' : 'customer_id';
            $stmt = $this->db->prepare("
                SELECT id FROM contas_receber
                WHERE description = :description
                AND {$campoPessoa} = :pessoa_id
                AND due_date = :due_date
                AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute([
                'description' => $dados['description'],
                'pessoa_id' => $pessoaId,
                'due_date' => $dueDate,
                'company_id' => $companyId
            ]);
            $conta = $stmt->fetch();
            if ($conta) {
                $existe = true;
                $contaId = $conta['id'];
            }
        }

        // Adicionar campo pessoa_id ou customer_id conforme estrutura
        if ($temPessoaId) {
            $campos['pessoa_id'] = $pessoaId;
        } elseif ($temCustomerId) {
            $campos['customer_id'] = $pessoaId;
        }

        // Adicionar campo amount_paid ou amount_received conforme estrutura
        if ($temAmountPaid) {
            $campos['amount_paid'] = $amountPaid;
        } elseif ($temAmountReceived) {
            $campos['amount_received'] = $amountPaid;
        }

        $campos['due_date'] = $dueDate;
        $campos['payment_date'] = $paymentDate;
        $campos['status'] = $status;
        $campos['notes'] = !empty($dados['notes']) ? $dados['notes'] : null;

        // Campos opcionais
        if (in_array('bank_account', $columnNames)) {
            $campos['bank_account'] = !empty($dados['bank_account']) ? $dados['bank_account'] : null;
        }
        if (in_array('status_id', $columnNames)) {
            $campos['status_id'] = !empty($dados['status_id']) ? (int)$dados['status_id'] : null;
        }
        if (in_array('payment_method', $columnNames)) {
            $campos['payment_method'] = !empty($dados['payment_method']) ? $dados['payment_method'] : null;
        }
        if (in_array('conta_bancaria_id', $columnNames)) {
            $campos['conta_bancaria_id'] = $contaBancariaId;
        }
        if (in_array('plano_conta_id', $columnNames)) {
            $campos['plano_conta_id'] = $planoContaId;
        }
        if (in_array('centro_custo_id', $columnNames)) {
            $campos['centro_custo_id'] = $centroCustoId;
        }
        // Campos de boleto (se existirem na tabela)
        $boletoFields = [
            'nosso_numero_boleto', 'codigo_solicitacao_boleto', 'linha_digitavel',
            'codigo_barras', 'boleto_pdf_url', 'pix_qrcode', 'pix_txid',
            'boleto_status', 'boleto_emitido_em'
        ];
        foreach ($boletoFields as $field) {
            if (in_array($field, $columnNames)) {
                if ($field === 'boleto_emitido_em') {
                    $campos[$field] = $boletoEmitidoEm;
                } else {
                    $campos[$field] = !empty($dados[$field]) ? $dados[$field] : null;
                }
            }
        }

        // Campos Shipay (se existirem na tabela)
        $shipayFields = [
            'shipay_charge_id', 'shipay_status', 'shipay_linha_digitavel',
            'shipay_qr_code', 'shipay_pdf_url', 'shipay_payload',
            'shipay_codigo_barras', 'shipay_tipo', 'shipay_due_date'
        ];
        foreach ($shipayFields as $field) {
            if (in_array($field, $columnNames)) {
                if ($field === 'shipay_due_date') {
                    $campos[$field] = $shipayDueDate;
                } else {
                    $campos[$field] = !empty($dados[$field]) ? $dados[$field] : null;
                }
            }
        }

        if ($existe) {
            // Atualizar
            $sets = [];
            foreach ($campos as $campo => $valor) {
                if ($campo !== 'company_id') {
                    $sets[] = "`{$campo}` = :{$campo}";
                }
            }
            $sql = "UPDATE contas_receber SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);
            $campos['id'] = $contaId;
            $stmt->execute($campos);
            $resultado['atualizados']++;
        } else {
            // Inserir
            $camposSql = array_keys($campos);
            $valoresSql = ':' . implode(', :', $camposSql);
            $sql = "INSERT INTO contas_receber (" . implode(', ', $camposSql) . ") VALUES ({$valoresSql})";
            $stmt = $this->db->prepare($sql);
            $stmt->execute($campos);
            $resultado['inseridos']++;
        }
    }
}

