<?php

declare(strict_types=1);

namespace App\Controllers;

use Exception;

class ComprasController extends BaseController
{
    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('compras')) {
            $this->response->forbidden('Você não tem permissão para visualizar compras.');
            return;
        }

        try {
            $companyId = $this->getCompanyId();
            $search = $this->request->get('search', '');
            $status = $this->request->get('status', '');
            $empresaFiltro = $this->request->get('empresa', '');

            // Buscar todas as empresas para o seletor
            $todasEmpresas = $this->getTodasEmpresas();

            $query = "
                SELECT c.*, p.name as supplier_name
                FROM compras c
                LEFT JOIN pessoas p ON c.fornecedor_id = p.id
                WHERE 1=1
            ";

            $params = [];

            // Filtrar por empresa se selecionada
            if (!empty($empresaFiltro)) {
                $query .= " AND c.company_id = :empresa_filtro";
                $params['empresa_filtro'] = $empresaFiltro;
            } else {
                // Se não há filtro de empresa, usar a empresa atual
                $query .= " AND c.company_id = :company_id";
                $params['company_id'] = $companyId;
            }

            if (!empty($search)) {
                $query .= " AND (c.numero LIKE :search OR p.name LIKE :search)";
                $params['search'] = "%{$search}%";
            }

            if (!empty($status)) {
                $query .= " AND c.status = :status";
                $params['status'] = $status;
            }

            $query .= " ORDER BY c.data_compra DESC, c.id DESC";

            $stmt = $this->db->prepare($query);
            $stmt->execute($params);
            $compras = $stmt->fetchAll();

            // Buscar status do módulo compras para o filtro e exibição
            $stmt = $this->db->prepare("
                SELECT codigo, nome, cor, icone
                FROM modulo_status
                WHERE company_id = :company_id
                  AND modulo = 'compras'
                  AND ativo = 1
                ORDER BY ordem ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $statusCompras = $stmt->fetchAll(\PDO::FETCH_ASSOC);

            $this->view('compras/index', [
                'compras' => $compras,
                'search' => $search,
                'status' => $status,
                'empresa' => $empresaFiltro,
                'todasEmpresas' => $todasEmpresas,
                'statusCompras' => $statusCompras,
                'pageTitle' => 'Compras',
                'activeMenu' => 'compras'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao carregar compras: " . $e->getMessage());
            $this->error('Erro ao carregar compras');
        }
    }

    public function create(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Buscar fornecedores
            try {
                $stmt = $this->db->prepare("
                    SELECT id, name, trade_name, document, phone, mobile, email FROM pessoas
                    WHERE company_id = :company_id
                    AND tipo_fornecedor = 1
                    AND is_active = 1
                    ORDER BY name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $fornecedores = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar fornecedores: " . $e->getMessage());
                $fornecedores = [];
            }

            // Buscar produtos/itens com TODOS os campos fiscais
            $produtos = [];
            try {
                $stmt = $this->db->query("SHOW TABLES LIKE 'produtos'");
                $tabelaProdutos = $stmt->rowCount() > 0;

                if ($tabelaProdutos) {
                    $stmt = $this->db->prepare("
                        SELECT id, name, sku as code, unit, purchase_price, cost_price, stock_quantity,
                               ncm, cest, cfop, origem,
                               cst_icms, aliquota_icms,
                               cst_pis, aliquota_pis,
                               cst_cofins, aliquota_cofins,
                               cst_ipi, aliquota_ipi
                        FROM produtos
                        WHERE company_id = :company_id AND is_active = 1
                        ORDER BY name ASC
                    ");
                } else {
                    $stmt = $this->db->prepare("
                        SELECT id, name, sku as code, unit, purchase_price, cost_price, stock_quantity,
                               ncm, cest, cfop, origem,
                               cst_icms, aliquota_icms,
                               cst_pis, aliquota_pis,
                               cst_cofins, aliquota_cofins,
                               cst_ipi, aliquota_ipi
                        FROM itens
                        WHERE company_id = :company_id AND is_active = 1
                        ORDER BY name ASC
                    ");
                }
                $stmt->execute(['company_id' => $companyId]);
                $produtos = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar produtos: " . $e->getMessage());
                $produtos = [];
            }

            // Buscar métodos de pagamento
            $metodosPagamento = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT id, name FROM metodos_pagamento
                    WHERE company_id = :company_id AND is_active = 1
                    ORDER BY name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $metodosPagamento = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar métodos de pagamento: " . $e->getMessage());
                $metodosPagamento = [];
            }

            // Buscar status do módulo compras
            $statusCompras = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT codigo, nome, descricao, cor, icone, ordem, is_default
                    FROM modulo_status
                    WHERE company_id = :company_id
                      AND modulo = 'compras'
                      AND ativo = 1
                    ORDER BY ordem ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $statusCompras = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar status de compras: " . $e->getMessage());
                $statusCompras = [];
            }

            // Status padrão (primeiro status ou o marcado como is_default)
            $statusPadrao = !empty($statusCompras) ? $statusCompras[0]['codigo'] : 'orcamento';
            foreach ($statusCompras as $status) {
                if (!empty($status['is_default'])) {
                    $statusPadrao = $status['codigo'];
                    break;
                }
            }

            // Gerar próximo número
            $proximoNumero = 'CPR-000001';
            try {
                $stmt = $this->db->prepare("
                    SELECT numero FROM compras
                    WHERE company_id = :company_id
                    ORDER BY id DESC LIMIT 1
                ");
                $stmt->execute(['company_id' => $companyId]);
                $ultimaCompra = $stmt->fetch();

                if ($ultimaCompra && !empty($ultimaCompra['numero'])) {
                    $ultimoNumero = $ultimaCompra['numero'];
                    if (preg_match('/CPR-(\d+)/', $ultimoNumero, $matches)) {
                        $proximoNumero = 'CPR-' . str_pad((string) ((int) $matches[1] + 1), 6, '0', STR_PAD_LEFT);
                    }
                }
            } catch (Exception $e) {
                error_log("Erro ao gerar número da compra: " . $e->getMessage());
            }

            // Buscar centros de custos disponíveis
            $centrosCustos = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT id, code, name
                    FROM centro_custos
                    WHERE company_id = :company_id
                      AND is_active = 1
                    ORDER BY code ASC, name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $centrosCustos = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar centros de custos: " . $e->getMessage());
                $centrosCustos = [];
            }

            // Buscar plano de contas
            $planoContas = $this->getPlanoContas($companyId);

            // Buscar parâmetro usar_lote_compra
            $usarLoteCompra = $this->getParametro('usar_lote_compra', $companyId);

            // Buscar empresas vinculadas ao usuário
            $empresasVinculadas = $this->getEmpresasVinculadasUsuario();

            $this->view('compras/create', [
                'fornecedores' => $fornecedores ?? [],
                'produtos' => $produtos ?? [],
                'metodosPagamento' => $metodosPagamento ?? [],
                'statusCompras' => $statusCompras,
                'statusPadrao' => $statusPadrao,
                'proximoNumero' => $proximoNumero,
                'centrosCustos' => $centrosCustos,
                'planoContas' => $planoContas,
                'usarLoteCompra' => $usarLoteCompra,
                'empresasVinculadas' => $empresasVinculadas,
                'pageTitle' => 'Nova Compra',
                'activeMenu' => 'compras'
            ]);

        } catch (Exception $e) {
            error_log("Erro GERAL ao carregar formulário de compra: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao carregar formulário: ' . $e->getMessage());
        }
    }

    public function store(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('compras')) {
            $this->response->forbidden('Você não tem permissão para criar compras.');
            return;
        }

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

            $data = [
                'company_id' => $companyId,
                'fornecedor_id' => $this->request->post('fornecedor_id') ?: null,
                'numero' => $this->request->post('numero'),
                'data_compra' => $this->request->post('data_compra'),
                'data_entrega' => $this->request->post('data_entrega') ?: null,
                'type' => $this->request->post('type') ?: 'compra',
                'status' => $this->request->post('status') ?: 'orcamento',
                'subtotal' => $this->request->post('subtotal') ?: 0.00,
                'discount' => $this->request->post('discount') ?: 0.00,
                'shipping' => $this->request->post('shipping') ?: 0.00,
                'total' => $this->request->post('total') ?: 0.00,
                'notes' => $this->request->post('notes'),
                'plano_contas_id' => $this->request->post('plano_contas_id') ?: null,
                'created_by' => $this->session->get('user_id')
            ];

            $this->db->beginTransaction();

            // Verificar se a tabela tem campo plano_contas_id
            $stmt = $this->db->query("SHOW COLUMNS FROM compras LIKE 'plano_contas_id'");
            $temPlanoContasId = $stmt->rowCount() > 0;

            if ($temPlanoContasId) {
                $stmt = $this->db->prepare("
                    INSERT INTO compras (company_id, fornecedor_id, numero, data_compra, data_entrega, type, status, subtotal, discount, shipping, total, notes, plano_contas_id, created_by, created_at, updated_at)
                    VALUES (:company_id, :fornecedor_id, :numero, :data_compra, :data_entrega, :type, :status, :subtotal, :discount, :shipping, :total, :notes, :plano_contas_id, :created_by, NOW(), NOW())
                ");
            } else {
                $stmt = $this->db->prepare("
                    INSERT INTO compras (company_id, fornecedor_id, numero, data_compra, data_entrega, type, status, subtotal, discount, shipping, total, notes, created_by, created_at, updated_at)
                    VALUES (:company_id, :fornecedor_id, :numero, :data_compra, :data_entrega, :type, :status, :subtotal, :discount, :shipping, :total, :notes, :created_by, NOW(), NOW())
                ");
                // Remover plano_contas_id dos dados se a coluna não existir
                unset($data['plano_contas_id']);
            }
            $stmt->execute($data);
            $compraIdRaw = $this->db->lastInsertId();
            $compraId = $compraIdRaw ? (int) $compraIdRaw : null;

            // Salvar itens com campos fiscais
            $itens = $this->request->post('itens') ?? [];
            if (is_array($itens) && count($itens) > 0) {
                // Verificar se a tabela tem campos de lote
                $stmt = $this->db->query("SHOW COLUMNS FROM compra_itens LIKE 'lote'");
                $temLote = $stmt->rowCount() > 0;

                if ($temLote) {
                    $stmtItem = $this->db->prepare("
                        INSERT INTO compra_itens (
                            compra_id, item_id, item_name, item_code, unit,
                            quantity, unit_price, discount, total, notes,
                            lote, data_fabricacao, data_validade,
                            ncm, cest, cfop, origem,
                            cst_icms, aliquota_icms,
                            cst_pis, aliquota_pis,
                            cst_cofins, aliquota_cofins,
                            cst_ipi, aliquota_ipi
                        ) VALUES (
                            :compra_id, :item_id, :item_name, :item_code, :unit,
                            :quantity, :unit_price, :discount, :total, :notes,
                            :lote, :data_fabricacao, :data_validade,
                            :ncm, :cest, :cfop, :origem,
                            :cst_icms, :aliquota_icms,
                            :cst_pis, :aliquota_pis,
                            :cst_cofins, :aliquota_cofins,
                            :cst_ipi, :aliquota_ipi
                        )
                    ");
                } else {
                    $stmtItem = $this->db->prepare("
                        INSERT INTO compra_itens (
                            compra_id, item_id, item_name, item_code, unit,
                            quantity, unit_price, discount, total, notes,
                            ncm, cest, cfop, origem,
                            cst_icms, aliquota_icms,
                            cst_pis, aliquota_pis,
                            cst_cofins, aliquota_cofins,
                            cst_ipi, aliquota_ipi
                        ) VALUES (
                            :compra_id, :item_id, :item_name, :item_code, :unit,
                            :quantity, :unit_price, :discount, :total, :notes,
                            :ncm, :cest, :cfop, :origem,
                            :cst_icms, :aliquota_icms,
                            :cst_pis, :aliquota_pis,
                            :cst_cofins, :aliquota_cofins,
                            :cst_ipi, :aliquota_ipi
                        )
                    ");
                }

                foreach ($itens as $item) {
                    $params = [
                        'compra_id' => $compraId,
                        'item_id' => $item['item_id'] ?? null,
                        'item_name' => $item['item_name'] ?? '',
                        'item_code' => $item['item_code'] ?? '',
                        'unit' => $item['unit'] ?? 'UN',
                        'quantity' => $item['quantity'] ?? 1,
                        'unit_price' => $item['unit_price'] ?? 0,
                        'discount' => $item['discount'] ?? 0,
                        'total' => $item['total'] ?? 0,
                        'notes' => $item['notes'] ?? '',
                        'ncm' => $item['ncm'] ?? '',
                        'cest' => $item['cest'] ?? '',
                        'cfop' => $item['cfop'] ?? '',
                        'origem' => $item['origem'] ?? '',
                        'cst_icms' => $item['cst_icms'] ?? '',
                        'aliquota_icms' => $item['aliquota_icms'] ?? 0,
                        'cst_pis' => $item['cst_pis'] ?? '',
                        'aliquota_pis' => $item['aliquota_pis'] ?? 0,
                        'cst_cofins' => $item['cst_cofins'] ?? '',
                        'aliquota_cofins' => $item['aliquota_cofins'] ?? 0,
                        'cst_ipi' => $item['cst_ipi'] ?? '',
                        'aliquota_ipi' => $item['aliquota_ipi'] ?? 0
                    ];

                    if ($temLote) {
                        $params['lote'] = $item['lote'] ?? '';
                        $params['data_fabricacao'] = !empty($item['data_fabricacao']) ? $item['data_fabricacao'] : null;
                        $params['data_validade'] = !empty($item['data_validade']) ? $item['data_validade'] : null;
                    }

                    $stmtItem->execute($params);
                }
            }

            // Processar ações baseadas no status
            $itensArray = is_array($itens) ? $itens : [];
            $this->processarAcoesStatus($compraId, $data['status'], $data, $itensArray);

            // Salvar centros de custos
            try {
                $this->salvarCentrosCustos($compraId, $companyId, $data['numero'], $data['data_compra']);
            } catch (Exception $e) {
                error_log("Erro ao salvar centros de custos da compra #{$compraId}: " . $e->getMessage());
                // Não quebra o processo, apenas loga o erro
            }

            // Log de atividade (opcional - não quebra se a tabela não existir)
            try {
                $this->logActivity('create', 'compras', $compraId, $data);
            } catch (Exception $e) {
                error_log("Erro ao registrar atividade: " . $e->getMessage());
                // Não quebra o processo
            }

            $this->db->commit();

            $this->success('Compra criada com sucesso', [
                'id' => $compraId,
                'redirect' => url('/compras')
            ]);

        } catch (Exception $e) {
            if ($this->db && $this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("=== ERRO AO CRIAR COMPRA ===");
            error_log("Mensagem: " . $e->getMessage());
            error_log("Arquivo: " . $e->getFile());
            error_log("Linha: " . $e->getLine());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao criar compra: ' . $e->getMessage());
        }
    }

    public function edit(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('compras')) {
            $this->response->forbidden('Você não tem permissão para editar compras.');
            return;
        }

        try {
            $id = (int) $this->request->get('id');
            $compra = $this->getCompra($id);

            if (!$compra) {
                $this->response->notFound('Compra não encontrada');
                return;
            }

            $companyId = $this->getCompanyId();

            // Buscar fornecedores
            try {
                $stmt = $this->db->prepare("
                    SELECT id, name, trade_name, document, phone, mobile, email FROM pessoas
                    WHERE company_id = :company_id
                    AND tipo_fornecedor = 1
                    AND is_active = 1
                    ORDER BY name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $fornecedores = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar fornecedores: " . $e->getMessage());
                $fornecedores = [];
            }

            // Buscar produtos/itens com campos fiscais
            $produtos = [];
            try {
                $stmt = $this->db->query("SHOW TABLES LIKE 'produtos'");
                $tabelaProdutos = $stmt->rowCount() > 0;

                if ($tabelaProdutos) {
                    $stmt = $this->db->prepare("
                        SELECT id, name, sku as code, unit, purchase_price, cost_price, stock_quantity,
                               ncm, cest, cfop, origem,
                               cst_icms, aliquota_icms,
                               cst_pis, aliquota_pis,
                               cst_cofins, aliquota_cofins,
                               cst_ipi, aliquota_ipi
                        FROM produtos
                        WHERE company_id = :company_id AND is_active = 1
                        ORDER BY name ASC
                    ");
                } else {
                    $stmt = $this->db->prepare("
                        SELECT id, name, sku as code, unit, purchase_price, cost_price, stock_quantity,
                               ncm, cest, cfop, origem,
                               cst_icms, aliquota_icms,
                               cst_pis, aliquota_pis,
                               cst_cofins, aliquota_cofins,
                               cst_ipi, aliquota_ipi
                        FROM itens
                        WHERE company_id = :company_id AND is_active = 1
                        ORDER BY name ASC
                    ");
                }
                $stmt->execute(['company_id' => $companyId]);
                $produtos = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar produtos: " . $e->getMessage());
                $produtos = [];
            }

            // Buscar métodos de pagamento
            $metodosPagamento = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT id, name FROM metodos_pagamento
                    WHERE company_id = :company_id AND is_active = 1
                    ORDER BY name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $metodosPagamento = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar métodos de pagamento: " . $e->getMessage());
                $metodosPagamento = [];
            }

            // Buscar status do módulo compras
            $statusCompras = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT codigo, nome, descricao, cor, icone, ordem, is_default
                    FROM modulo_status
                    WHERE company_id = :company_id
                      AND modulo = 'compras'
                      AND ativo = 1
                    ORDER BY ordem ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $statusCompras = $stmt->fetchAll() ?: [];
            } catch (Exception $e) {
                error_log("Erro ao buscar status de compras: " . $e->getMessage());
                $statusCompras = [];
            }

            // Buscar fornecedor da compra
            $fornecedor = null;
            if ($compra['fornecedor_id']) {
                try {
                    $stmt = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
                    $stmt->execute(['id' => $compra['fornecedor_id']]);
                    $fornecedor = $stmt->fetch();
                } catch (Exception $e) {
                    error_log("Erro ao buscar fornecedor: " . $e->getMessage());
                }
            }

            // Buscar itens da compra com campos fiscais
            $itens = [];
            try {
                // Verificar estrutura da tabela compra_itens
                $stmtCheck = $this->db->query("SHOW COLUMNS FROM compra_itens");
                $columns = $stmtCheck->fetchAll();
                $columnNames = array_column($columns, 'Field');

                // Verificar se usa item_id ou product_id
                $campoProdutoId = in_array('product_id', $columnNames) ? 'product_id' : 'item_id';

                // Construir query dinamicamente
                $camposSelect = [
                    'ci.*',
                    "ci.{$campoProdutoId} as item_id",
                    'ci.item_name',
                    'ci.item_code',
                    'ci.quantity',
                    'ci.unit_price',
                    'ci.discount',
                    'ci.total',
                    'ci.unit',
                    'ci.ncm',
                    'ci.cest',
                    'ci.cfop',
                    'ci.origem',
                    'ci.cst_icms',
                    'ci.aliquota_icms',
                    'ci.valor_icms',
                    'ci.cst_pis',
                    'ci.aliquota_pis',
                    'ci.valor_pis',
                    'ci.cst_cofins',
                    'ci.aliquota_cofins',
                    'ci.valor_cofins',
                    'ci.cst_ipi',
                    'ci.aliquota_ipi',
                    'ci.valor_ipi',
                    'ci.notes',
                    'ci.lote',
                    'ci.data_fabricacao',
                    'ci.data_validade'
                ];

                // Filtrar apenas campos que existem na tabela
                $camposFinais = [];
                foreach ($camposSelect as $campo) {
                    $campoLimpo = str_replace(['ci.', ' as item_id'], '', $campo);
                    $campoLimpo = trim($campoLimpo, ' ');
                    if ($campoLimpo === '*' || in_array($campoLimpo, $columnNames) || strpos($campo, ' as ') !== false) {
                        $camposFinais[] = $campo;
                    }
                }

                $sql = "SELECT " . implode(', ', $camposFinais) . "
                        FROM compra_itens ci
                        WHERE ci.compra_id = :compra_id
                        ORDER BY ci.id ASC";

                $stmt = $this->db->prepare($sql);
                $stmt->execute(['compra_id' => $id]);
                $itens = $stmt->fetchAll();

                // Garantir que item_id esteja presente mesmo se a coluna for product_id
                foreach ($itens as &$item) {
                    if (!isset($item['item_id']) && isset($item[$campoProdutoId])) {
                        $item['item_id'] = $item[$campoProdutoId];
                    }
                    // Garantir valores padrão para campos que podem estar null
                    $item['item_name'] = $item['item_name'] ?? '';
                    $item['item_code'] = $item['item_code'] ?? '';
                    $item['quantity'] = $item['quantity'] ?? 0;
                    $item['unit_price'] = $item['unit_price'] ?? 0;
                    $item['discount'] = $item['discount'] ?? 0;
                    $item['total'] = $item['total'] ?? 0;
                    $item['unit'] = $item['unit'] ?? 'UN';
                }
                unset($item);

            } catch (Exception $e) {
                error_log("Erro ao buscar itens da compra: " . $e->getMessage());
                error_log("Stack trace: " . $e->getTraceAsString());
                $itens = [];
            }

            // Buscar centros de custos disponíveis
            $centrosCustos = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT id, code, name
                    FROM centro_custos
                    WHERE company_id = :company_id
                      AND is_active = 1
                    ORDER BY code ASC, name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $centrosCustos = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar centros de custos: " . $e->getMessage());
                $centrosCustos = [];
            }

            // Buscar centros de custos da compra
            $compra['centros_custos'] = [];
            try {
                $stmt = $this->db->query("SHOW TABLES LIKE 'compras_centro_custos'");
                if ($stmt->rowCount() > 0) {
                    $stmt = $this->db->prepare("
                        SELECT ccc.centro_id, ccc.valor, cc.code, cc.name
                        FROM compras_centro_custos ccc
                        INNER JOIN centro_custos cc ON ccc.centro_id = cc.id
                        WHERE ccc.compra_id = :compra_id
                        ORDER BY ccc.id ASC
                    ");
                    $stmt->execute(['compra_id' => $id]);
                    $compra['centros_custos'] = $stmt->fetchAll();
                }
            } catch (Exception $e) {
                error_log("Erro ao buscar centros de custos da compra: " . $e->getMessage());
                $compra['centros_custos'] = [];
            }

            // Buscar plano de contas
            $planoContas = $this->getPlanoContas($companyId);

            // Buscar parâmetro usar_lote_compra
            $usarLoteCompra = $this->getParametro('usar_lote_compra', $companyId);

            // Buscar empresas vinculadas ao usuário
            $empresasVinculadas = $this->getEmpresasVinculadasUsuario();

            $this->view('compras/edit', [
                'compra' => $compra,
                'fornecedores' => $fornecedores ?? [],
                'produtos' => $produtos ?? [],
                'metodosPagamento' => $metodosPagamento ?? [],
                'statusCompras' => $statusCompras,
                'itens' => $itens ?? [],
                'fornecedor' => $fornecedor ?? null,
                'centrosCustos' => $centrosCustos,
                'planoContas' => $planoContas,
                'usarLoteCompra' => $usarLoteCompra,
                'empresasVinculadas' => $empresasVinculadas,
                'pageTitle' => 'Editar Compra',
                'activeMenu' => 'compras'
            ]);

        } catch (Exception $e) {
            error_log("Erro GERAL ao editar compra: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao carregar formulário: ' . $e->getMessage());
        }
    }

    public function update(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('compras')) {
            $this->response->forbidden('Você não tem permissão para editar compras.');
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $compra = $this->getCompra($id);

            if (!$compra) {
                $this->error('Compra não encontrada');
                return;
            }

            $companyId = $this->getCompanyId();

            $data = [
                'fornecedor_id' => $this->request->post('fornecedor_id') ?: null,
                'numero' => $this->request->post('numero'),
                'data_compra' => $this->request->post('data_compra'),
                'data_entrega' => $this->request->post('data_entrega') ?: null,
                'type' => $this->request->post('type') ?: 'compra',
                'status' => $this->request->post('status') ?: 'orcamento',
                'subtotal' => $this->request->post('subtotal') ?: 0.00,
                'discount' => $this->request->post('discount') ?: 0.00,
                'shipping' => $this->request->post('shipping') ?: 0.00,
                'total' => $this->request->post('total') ?: 0.00,
                'notes' => $this->request->post('notes'),
                'plano_contas_id' => $this->request->post('plano_contas_id') ?: null,
                'id' => $id,
                'company_id' => $companyId
            ];

            $this->db->beginTransaction();

            // Verificar se a tabela tem campo plano_contas_id
            $stmt = $this->db->query("SHOW COLUMNS FROM compras LIKE 'plano_contas_id'");
            $temPlanoContasId = $stmt->rowCount() > 0;

            if ($temPlanoContasId) {
                $stmt = $this->db->prepare("
                    UPDATE compras SET
                        fornecedor_id = :fornecedor_id,
                        numero = :numero,
                        data_compra = :data_compra,
                        data_entrega = :data_entrega,
                        type = :type,
                        status = :status,
                        subtotal = :subtotal,
                        discount = :discount,
                        shipping = :shipping,
                        total = :total,
                        notes = :notes,
                        plano_contas_id = :plano_contas_id,
                        updated_at = NOW()
                    WHERE id = :id AND company_id = :company_id
                ");
            } else {
                $stmt = $this->db->prepare("
                    UPDATE compras SET
                        fornecedor_id = :fornecedor_id,
                        numero = :numero,
                        data_compra = :data_compra,
                        data_entrega = :data_entrega,
                        type = :type,
                        status = :status,
                        subtotal = :subtotal,
                        discount = :discount,
                        shipping = :shipping,
                        total = :total,
                        notes = :notes,
                        updated_at = NOW()
                    WHERE id = :id AND company_id = :company_id
                ");
                // Remover plano_contas_id dos dados se a coluna não existir
                unset($data['plano_contas_id']);
            }
            $stmt->execute($data);

            // Processar ações baseadas no status ANTES de deletar itens (caso precise dos itens antigos)
            $statusAnterior = $compra['status'];
            $statusNovo = $data['status'];
            $itensParaAcoes = [];

            // Se o status mudou, buscar itens antigos antes de deletar
            if ($statusAnterior !== $statusNovo) {
                $stmtItensAntigos = $this->db->prepare("
                    SELECT item_id, quantity
                    FROM compra_itens
                    WHERE compra_id = :compra_id
                ");
                $stmtItensAntigos->execute(['compra_id' => $id]);
                $itensAntigos = $stmtItensAntigos->fetchAll();

                if (!empty($itensAntigos)) {
                    $itensParaAcoes = array_map(function($item) {
                        return [
                            'item_id' => $item['item_id'],
                            'quantity' => $item['quantity']
                        ];
                    }, $itensAntigos);
                }
            }

            // Deletar itens antigos
            $stmt = $this->db->prepare("DELETE FROM compra_itens WHERE compra_id = :compra_id");
            $stmt->execute(['compra_id' => $id]);

            // Salvar novos itens com campos fiscais
            $itens = $this->request->post('itens') ?? [];
            if (is_array($itens) && count($itens) > 0) {
                $stmtItem = $this->db->prepare("
                    INSERT INTO compra_itens (
                        compra_id, item_id, item_name, item_code, unit,
                        quantity, unit_price, discount, total, notes,
                        ncm, cest, cfop, origem,
                        cst_icms, aliquota_icms,
                        cst_pis, aliquota_pis,
                        cst_cofins, aliquota_cofins,
                        cst_ipi, aliquota_ipi
                    ) VALUES (
                        :compra_id, :item_id, :item_name, :item_code, :unit,
                        :quantity, :unit_price, :discount, :total, :notes,
                        :ncm, :cest, :cfop, :origem,
                        :cst_icms, :aliquota_icms,
                        :cst_pis, :aliquota_pis,
                        :cst_cofins, :aliquota_cofins,
                        :cst_ipi, :aliquota_ipi
                    )
                ");

                foreach ($itens as $item) {
                    $stmtItem->execute([
                        'compra_id' => $id,
                        'item_id' => $item['item_id'] ?? null,
                        'item_name' => $item['item_name'] ?? '',
                        'item_code' => $item['item_code'] ?? '',
                        'unit' => $item['unit'] ?? 'UN',
                        'quantity' => $item['quantity'] ?? 1,
                        'unit_price' => $item['unit_price'] ?? 0,
                        'discount' => $item['discount'] ?? 0,
                        'total' => $item['total'] ?? 0,
                        'notes' => $item['notes'] ?? '',
                        'ncm' => $item['ncm'] ?? '',
                        'cest' => $item['cest'] ?? '',
                        'cfop' => $item['cfop'] ?? '',
                        'origem' => $item['origem'] ?? '',
                        'cst_icms' => $item['cst_icms'] ?? '',
                        'aliquota_icms' => $item['aliquota_icms'] ?? 0,
                        'cst_pis' => $item['cst_pis'] ?? '',
                        'aliquota_pis' => $item['aliquota_pis'] ?? 0,
                        'cst_cofins' => $item['cst_cofins'] ?? '',
                        'aliquota_cofins' => $item['aliquota_cofins'] ?? 0,
                        'cst_ipi' => $item['cst_ipi'] ?? '',
                        'aliquota_ipi' => $item['aliquota_ipi'] ?? 0
                    ]);
                }
            }

            // Processar ações baseadas no status (apenas se o status mudou)
            if ($statusAnterior !== $statusNovo) {
                error_log("Compra #{$id}: Status mudou de '{$statusAnterior}' para '{$statusNovo}'");

                // Buscar itens do banco (já foram salvos acima)
                $itensArray = [];
                if (is_array($itens) && count($itens) > 0) {
                    // Usar itens do POST
                    $itensArray = $itens;
                } else {
                    // Buscar itens recém salvos do banco
                    $stmtItens = $this->db->prepare("
                        SELECT item_id, quantity
                        FROM compra_itens
                        WHERE compra_id = :compra_id
                    ");
                    $stmtItens->execute(['compra_id' => $id]);
                    $itensBanco = $stmtItens->fetchAll();

                    if (!empty($itensBanco)) {
                        $itensArray = array_map(function($item) {
                            return [
                                'item_id' => $item['item_id'],
                                'quantity' => $item['quantity']
                            ];
                        }, $itensBanco);
                    } elseif (!empty($itensParaAcoes)) {
                        // Fallback: usar itens antigos que foram salvos antes de deletar
                        $itensArray = $itensParaAcoes;
                    }
                }

                error_log("Compra #{$id}: Processando ações com " . count($itensArray) . " itens");

                // Tentar processar ações, mas não quebrar o fluxo se houver erro
                try {
                    $this->processarAcoesStatus($id, $statusNovo, $data, $itensArray, $statusAnterior);
                } catch (Exception $e) {
                    error_log("Compra #{$id}: Erro ao processar ações do status (não crítico): " . $e->getMessage());
                    // Não relançar - permite que a compra seja salva mesmo se as ações falharem
                }
            }

            // Salvar centros de custos
            try {
                $this->salvarCentrosCustos($id, $companyId, $data['numero'], $data['data_compra']);
            } catch (Exception $e) {
                error_log("Erro ao salvar centros de custos da compra #{$id}: " . $e->getMessage());
                // Não quebra o processo, apenas loga o erro
            }

            $this->logActivity('update', 'compras', $id, $data);
            $this->db->commit();

            $this->success('Compra atualizada com sucesso', [
                'redirect' => url('/compras')
            ]);

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao atualizar compra: " . $e->getMessage());
            $this->error('Erro ao atualizar compra');
        }
    }

    public function delete(): void
    {
        // Verificar permissão de exclusão
        if (!$this->canDelete('compras')) {
            $this->response->forbidden('Você não tem permissão para excluir compras.');
            return;
        }

        try {
            $id = (int) $this->request->post('id');
            $compra = $this->getCompra($id);

            if (!$compra) {
                $this->error('Compra não encontrada');
                return;
            }

            $this->db->beginTransaction();

            $stmt = $this->db->prepare("DELETE FROM compras WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);

            $this->logActivity('delete', 'compras', $id, $compra);
            $this->db->commit();

            $this->success('Compra excluída com sucesso');

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao excluir compra: " . $e->getMessage());
            $this->error('Erro ao excluir compra');
        }
    }

    public function show(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $compra = $this->getCompra($id);

            if (!$compra) {
                $this->response->notFound('Compra não encontrada');
                return;
            }

            // Buscar itens da compra
            $stmt = $this->db->prepare("
                SELECT ci.*, i.name as item_name, i.code as item_code, i.unit
                FROM compra_itens ci
                LEFT JOIN itens i ON ci.item_id = i.id
                WHERE ci.compra_id = :compra_id
                ORDER BY ci.id ASC
            ");
            $stmt->execute(['compra_id' => $id]);
            $itens = $stmt->fetchAll();

            // Buscar fornecedor
            $fornecedor = null;
            if ($compra['fornecedor_id']) {
                $stmt = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
                $stmt->execute(['id' => $compra['fornecedor_id']]);
                $fornecedor = $stmt->fetch();
            }

            $this->view('compras/show', [
                'compra' => $compra,
                'itens' => $itens,
                'fornecedor' => $fornecedor,
                'pageTitle' => 'Compra #' . ($compra['numero'] ?? $compra['id']),
                'activeMenu' => 'compras'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao visualizar compra: " . $e->getMessage());
            $this->error('Erro ao carregar compra: ' . $e->getMessage());
        }
    }

    public function print(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $compra = $this->getCompra($id);

            if (!$compra) {
                $this->response->notFound('Compra não encontrada');
                return;
            }

            // Buscar empresa (tenta empresas, depois companies)
            $empresa = null;
            try {
                $stmt = $this->db->prepare("SELECT * FROM empresas WHERE id = :id LIMIT 1");
                $stmt->execute(['id' => $compra['company_id']]);
                $empresa = $stmt->fetch();
            } catch (Exception $e) {
                // Tabela empresas pode não existir
            }

            if (!$empresa) {
                try {
                    $stmt = $this->db->prepare("SELECT * FROM companies WHERE id = :id LIMIT 1");
                    $stmt->execute(['id' => $compra['company_id']]);
                    $empresa = $stmt->fetch();
                } catch (Exception $e) {
                    error_log("Erro ao buscar empresa: " . $e->getMessage());
                }
            }

            // Se ainda não encontrou, criar array vazio para evitar erros
            if (!$empresa) {
                $empresa = [];
            }

            // Buscar itens
            // Primeiro tenta buscar apenas da tabela compra_itens (mais seguro)
            $stmt = $this->db->prepare("
                SELECT ci.*,
                    COALESCE(ci.item_name, 'Item sem nome') as item_name,
                    COALESCE(ci.item_code, '') as item_code,
                    COALESCE(ci.unit, 'UN') as unit
                FROM compra_itens ci
                WHERE ci.compra_id = :compra_id
                ORDER BY ci.id ASC
            ");
            $stmt->execute(['compra_id' => $id]);
            $itens = $stmt->fetchAll();

            // Se os itens não têm nome ou código, tenta buscar das tabelas relacionadas
            foreach ($itens as &$item) {
                if (empty($item['item_name']) || $item['item_name'] === 'Item sem nome') {
                    if (!empty($item['item_id'])) {
                        // Tentar buscar de itens
                        try {
                            $stmtItem = $this->db->prepare("SELECT name, code, unit FROM itens WHERE id = :id LIMIT 1");
                            $stmtItem->execute(['id' => $item['item_id']]);
                            $itemInfo = $stmtItem->fetch();
                            if ($itemInfo) {
                                $item['item_name'] = $itemInfo['name'] ?? $item['item_name'];
                                $item['item_code'] = $itemInfo['code'] ?? $item['item_code'];
                                $item['unit'] = $itemInfo['unit'] ?? $item['unit'];
                            }
                        } catch (Exception $e) {
                            // Tabela itens pode não existir
                        }

                        // Se ainda não encontrou, tentar produtos
                        if (empty($item['item_name']) || $item['item_name'] === 'Item sem nome') {
                            try {
                                // Verificar se a tabela produtos existe
                                $stmtTable = $this->db->query("SHOW TABLES LIKE 'produtos'");
                                if ($stmtTable->rowCount() > 0) {
                                    // Verificar quais colunas existem na tabela produtos
                                    $stmtCols = $this->db->query("SHOW COLUMNS FROM produtos");
                                    $columns = $stmtCols->fetchAll(\PDO::FETCH_COLUMN);

                                    $colName = in_array('name', $columns) ? 'name' : (in_array('nome', $columns) ? 'nome' : null);
                                    $colCode = in_array('code', $columns) ? 'code' : (in_array('codigo', $columns) ? 'codigo' : (in_array('sku', $columns) ? 'sku' : null));
                                    $colUnit = in_array('unit', $columns) ? 'unit' : (in_array('unidade', $columns) ? 'unidade' : null);

                                    if ($colName || $colCode || $colUnit) {
                                        $selectCols = [];
                                        if ($colName)
                                            $selectCols[] = $colName . ' as name';
                                        if ($colCode)
                                            $selectCols[] = $colCode . ' as code';
                                        if ($colUnit)
                                            $selectCols[] = $colUnit . ' as unit';

                                        if (!empty($selectCols)) {
                                            $sql = "SELECT " . implode(', ', $selectCols) . " FROM produtos WHERE id = :id LIMIT 1";
                                            $stmtProd = $this->db->prepare($sql);
                                            $stmtProd->execute(['id' => $item['item_id']]);
                                            $prodInfo = $stmtProd->fetch();
                                            if ($prodInfo) {
                                                $item['item_name'] = $prodInfo['name'] ?? $item['item_name'];
                                                $item['item_code'] = $prodInfo['code'] ?? $item['item_code'];
                                                $item['unit'] = $prodInfo['unit'] ?? $item['unit'];
                                            }
                                        }
                                    }
                                }
                            } catch (Exception $e) {
                                // Tabela produtos pode não existir ou ter estrutura diferente
                                error_log("Erro ao buscar produto: " . $e->getMessage());
                            }
                        }
                    }
                }
            }
            unset($item); // Liberar referência

            // Buscar fornecedor
            $fornecedor = null;
            if ($compra['fornecedor_id']) {
                $stmt = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
                $stmt->execute(['id' => $compra['fornecedor_id']]);
                $fornecedor = $stmt->fetch();
            }

            // Buscar usuário que criou
            $usuario = null;
            if ($compra['created_by']) {
                $stmt = $this->db->prepare("SELECT * FROM users WHERE id = :id");
                $stmt->execute(['id' => $compra['created_by']]);
                $usuario = $stmt->fetch();
            }

            // Buscar status do módulo compras
            $statusCompras = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT codigo, nome, cor, icone
                    FROM modulo_status
                    WHERE company_id = :company_id
                      AND modulo = 'compras'
                      AND ativo = 1
                    ORDER BY ordem ASC
                ");
                $stmt->execute(['company_id' => $compra['company_id']]);
                $statusCompras = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar status: " . $e->getMessage());
                $statusCompras = [];
            }

            $this->view('compras/print', [
                'compra' => $compra,
                'itens' => $itens,
                'empresa' => $empresa,
                'fornecedor' => $fornecedor,
                'usuario' => $usuario,
                'statusCompras' => $statusCompras
            ]);

        } catch (Exception $e) {
            error_log("Erro ao imprimir compra: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            echo "Erro ao carregar compra para impressão: " . htmlspecialchars($e->getMessage());
        } catch (\Throwable $e) {
            error_log("Erro fatal ao imprimir compra: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            echo "Erro ao carregar compra para impressão: " . htmlspecialchars($e->getMessage());
        }
    }

    public function enviarEmail(): void
    {
        try {
            $compraId = (int) $this->request->post('compra_id');
            $email = $this->request->post('email');
            $assunto = $this->request->post('assunto');
            $mensagem = $this->request->post('mensagem');
            $anexarPdf = $this->request->post('anexar_pdf') === 'true';

            if (!$compraId || !$email) {
                $this->error('Dados inválidos');
                return;
            }

            $compra = $this->getCompra($compraId);
            if (!$compra) {
                $this->error('Compra não encontrada');
                return;
            }

            // Buscar dados completos para o PDF (tenta empresas, depois companies)
            $stmt = $this->db->prepare("SELECT * FROM empresas WHERE id = :id");
            $stmt->execute(['id' => $compra['company_id']]);
            $empresa = $stmt->fetch();

            if (!$empresa) {
                $stmt = $this->db->prepare("SELECT * FROM companies WHERE id = :id");
                $stmt->execute(['id' => $compra['company_id']]);
                $empresa = $stmt->fetch();
            }

            $stmt = $this->db->prepare("
                SELECT ci.*, i.name as item_name, i.code as item_code, i.unit
                FROM compra_itens ci
                LEFT JOIN itens i ON ci.item_id = i.id
                WHERE ci.compra_id = :compra_id
                ORDER BY ci.id ASC
            ");
            $stmt->execute(['compra_id' => $compraId]);
            $itens = $stmt->fetchAll();

            $fornecedor = null;
            if ($compra['fornecedor_id']) {
                $stmt = $this->db->prepare("SELECT * FROM pessoas WHERE id = :id");
                $stmt->execute(['id' => $compra['fornecedor_id']]);
                $fornecedor = $stmt->fetch();
            }

            $usuario = null;
            if ($compra['created_by']) {
                $stmt = $this->db->prepare("SELECT * FROM users WHERE id = :id");
                $stmt->execute(['id' => $compra['created_by']]);
                $usuario = $stmt->fetch();
            }

            // Buscar status do módulo compras
            $statusCompras = [];
            try {
                $stmt = $this->db->prepare("
                    SELECT codigo, nome, cor, icone
                    FROM modulo_status
                    WHERE company_id = :company_id
                      AND modulo = 'compras'
                      AND ativo = 1
                    ORDER BY ordem ASC
                ");
                $stmt->execute(['company_id' => $compra['company_id']]);
                $statusCompras = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar status: " . $e->getMessage());
                $statusCompras = [];
            }

            // Garantir que empresa seja um array
            if (!$empresa) {
                $empresa = [];
            }

            // Gerar PDF
            $pdfPath = null;
            if ($anexarPdf) {
                ob_start();
                include \ROOT_PATH . '/views/compras/print.php';
                $html = ob_get_clean();

                try {
                    require_once \ROOT_PATH . '/vendor/autoload.php';
                    $mpdf = new \Mpdf\Mpdf([
                        'mode' => 'utf-8',
                        'format' => 'A4',
                        'margin_top' => 10,
                        'margin_bottom' => 10,
                        'margin_left' => 10,
                        'margin_right' => 10
                    ]);

                    $mpdf->WriteHTML($html);

                    $pdfDir = \ROOT_PATH . '/storage/temp';
                    if (!is_dir($pdfDir)) {
                        mkdir($pdfDir, 0755, true);
                    }

                    $pdfPath = $pdfDir . '/compra_' . $compra['id'] . '_' . time() . '.pdf';
                    $mpdf->Output($pdfPath, 'F');

                } catch (Exception $e) {
                    error_log("Erro ao gerar PDF: " . $e->getMessage());
                    $this->error('Erro ao gerar PDF: ' . $e->getMessage());
                    return;
                }
            }

            // Enviar e-mail
            try {
                $mail = new \PHPMailer\PHPMailer\PHPMailer(true);

                // Configurações SMTP
                $mail->isSMTP();
                $mail->Host = $_ENV['MAIL_HOST'] ?? 'smtp.gmail.com';
                $mail->SMTPAuth = true;
                $mail->Username = $_ENV['MAIL_USERNAME'] ?? '';
                $mail->Password = $_ENV['MAIL_PASSWORD'] ?? '';
                $mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'] ?? 'tls';
                $mail->Port = $_ENV['MAIL_PORT'] ?? 587;
                $mail->CharSet = 'UTF-8';

                // Remetente
                $mail->setFrom($_ENV['MAIL_FROM_ADDRESS'] ?? 'noreply@Systhema.com.br', $empresa['name'] ?? 'Systhema ERP');

                // Destinatário
                $mail->addAddress($email);

                // Conteúdo
                $mail->isHTML(true);
                $mail->Subject = $assunto ?: 'Pedido de Compra #' . ($compra['numero'] ?? $compra['id']);
                $mail->Body = nl2br($mensagem) . '<br><br>--<br>' . ($empresa['name'] ?? 'Systhema ERP');

                // Anexar PDF
                if ($pdfPath && file_exists($pdfPath)) {
                    $mail->addAttachment($pdfPath, 'compra_' . ($compra['numero'] ?? $compra['id']) . '.pdf');
                }

                $mail->send();

                // Deletar PDF temporário
                if ($pdfPath && file_exists($pdfPath)) {
                    unlink($pdfPath);
                }

                $this->success('E-mail enviado com sucesso!');

            } catch (Exception $e) {
                error_log("Erro ao enviar e-mail: " . $e->getMessage());

                // Deletar PDF temporário em caso de erro
                if ($pdfPath && file_exists($pdfPath)) {
                    unlink($pdfPath);
                }

                $this->error('Erro ao enviar e-mail: ' . $e->getMessage());
            }

        } catch (Exception $e) {
            error_log("Erro no envio de e-mail: " . $e->getMessage());
            $this->error('Erro ao processar envio de e-mail');
        }
    }

    public function monitorNFe(): void
    {
        try {
            $companyId = $this->getCompanyId();

            // Verificar se é apenas para listar empresas
            if ($this->request->get('listar_empresas') === '1') {
                error_log("Monitor NF-e: Modo listar_empresas ativado");
                $todasEmpresas = $this->getTodasEmpresasParaMonitor();
                error_log("Monitor NF-e: Empresas retornadas para listagem: " . count($todasEmpresas));
                $this->success('Empresas listadas', [
                    'empresas' => $todasEmpresas
                ]);
                return;
            }

            // Buscar empresa_id do parâmetro GET (se não informado, usar a primeira empresa disponível)
            $empresaId = $this->request->get('empresa_id');
            if (empty($empresaId)) {
                // Buscar todas as empresas e usar a primeira
                $todasEmpresas = $this->getTodasEmpresasParaMonitor();
                if (!empty($todasEmpresas)) {
                    $empresaId = $todasEmpresas[0]['id'];
                } else {
                    // Se não houver empresas, retornar dados vazios mas sucesso para abrir o modal
                    $this->success('Monitor carregado', [
                        'nfes' => [],
                        'empresa' => [
                            'id' => null,
                            'nome' => 'Nenhuma empresa',
                            'cnpj' => ''
                        ],
                        'empresas' => [],
                        'aviso' => 'Nenhuma empresa cadastrada no sistema'
                    ]);
                    return;
                }
            }

            // Buscar empresa (tenta empresas, depois companies)
            $stmt = $this->db->prepare("SELECT * FROM empresas WHERE id = :id");
            $stmt->execute(['id' => $empresaId]);
            $empresa = $stmt->fetch();

            if (!$empresa) {
                // Tentar na tabela companies
                $stmt = $this->db->prepare("SELECT * FROM companies WHERE id = :id");
                $stmt->execute(['id' => $empresaId]);
                $empresa = $stmt->fetch();
            }

            if (!$empresa) {
                $this->error('Empresa não encontrada');
                return;
            }

            // Atualizar companyId para usar o empresaId selecionado nas consultas
            $companyId = (int) $empresaId;

            error_log("Monitor NF-e: Usando company_id: {$companyId} (tipo: " . gettype($companyId) . ")");

            // SEMPRE PRIORIZAR O BANCO DE DADOS PRIMEIRO
            // Buscar NF-e já armazenadas no banco (SEMPRE, independente do certificado)
            $nfes = [];
            $mensagemCertificado = '';
            $chavesNoBanco = []; // Para evitar duplicatas

            error_log("Monitor NF-e: PRIORIZANDO busca no banco de dados para company_id: {$companyId}");

            try {
                // Log para debug
                error_log("Monitor NF-e: Buscando notas no banco para company_id: {$companyId}");

                // Verificar se a tabela existe
                $stmtCheck = $this->db->query("SHOW TABLES LIKE 'nfe_recebidas'");
                $tabelaExiste = $stmtCheck->fetch();
                if (!$tabelaExiste) {
                    error_log("Monitor NF-e: AVISO - Tabela nfe_recebidas não existe!");
                    $nfesDb = [];
                } else {
                    // Contar total de registros na tabela (sem filtro)
                    $stmtCount = $this->db->query("SELECT COUNT(*) as total FROM nfe_recebidas");
                    $totalGeral = $stmtCount->fetch()['total'] ?? 0;
                    error_log("Monitor NF-e: Total de NF-e na tabela (todas empresas): {$totalGeral}");

                    // Contar registros para esta empresa
                    $stmtCountCompany = $this->db->prepare("SELECT COUNT(*) as total FROM nfe_recebidas WHERE company_id = :company_id");
                    $stmtCountCompany->execute(['company_id' => $companyId]);
                    $totalCompany = $stmtCountCompany->fetch()['total'] ?? 0;
                    error_log("Monitor NF-e: Total de NF-e para company_id {$companyId}: {$totalCompany}");

                    // Buscar todas as notas, incluindo as manifestadas (confirmadas)
                    // Não filtrar por status_manifesto para mostrar todas
                    $stmt = $this->db->prepare("
                            SELECT
                                *,
                                COALESCE(cnpj_fornecedor, '') as cnpj_fornecedor,
                                COALESCE(razao_social_fornecedor, '') as razao_social_fornecedor
                            FROM nfe_recebidas
                            WHERE company_id = :company_id
                            ORDER BY
                                CASE
                                    WHEN status_manifesto = 'pendente' THEN 1
                                    WHEN status_manifesto = 'confirmada' THEN 2
                                    ELSE 3
                                END,
                                data_emissao DESC,
                                id DESC
                            LIMIT 200
                        ");
                    $stmt->execute(['company_id' => $companyId]);
                    $nfesDb = $stmt->fetchAll();

                    error_log("Monitor NF-e: Buscou " . count($nfesDb) . " notas (incluindo manifestadas)");

                    error_log("Monitor NF-e: Query retornou " . count($nfesDb) . " registros");
                }

                foreach ($nfesDb as $nfeDb) {
                    $cnpj = $nfeDb['cnpj_fornecedor'] ?? $nfeDb['cnpj_emitente'] ?? '';
                    $razao = $nfeDb['razao_social_fornecedor'] ?? $nfeDb['razao_social'] ?? $nfeDb['nome_emitente'] ?? '';

                    // Se os dados estão vazios e temos XML completo, extrair diretamente do XML
                    if ((empty($cnpj) || empty($razao)) && !empty($nfeDb['xml_completo'])) {
                        try {
                            $dadosEmissor = \App\Services\NFeIntegrationService::extrairDadosEmissor($nfeDb['xml_completo']);
                            if (!empty($dadosEmissor['cnpj'])) {
                                $cnpj = $dadosEmissor['cnpj'];
                            }
                            if (!empty($dadosEmissor['razao_social'])) {
                                $razao = $dadosEmissor['razao_social'];
                            }

                            // Atualizar no banco se encontrou dados
                            if (!empty($cnpj) || !empty($razao)) {
                                $stmtUpdate = $this->db->prepare("
                                        UPDATE nfe_recebidas
                                        SET cnpj_fornecedor = COALESCE(:cnpj, cnpj_fornecedor),
                                            razao_social_fornecedor = COALESCE(:razao, razao_social_fornecedor),
                                            updated_at = NOW()
                                        WHERE id = :id
                                    ");
                                $stmtUpdate->execute([
                                    'cnpj' => $cnpj ?: null,
                                    'razao' => $razao ?: null,
                                    'id' => $nfeDb['id']
                                ]);
                                error_log("✅ Atualizou dados do fornecedor do XML para NF-e {$nfeDb['chave_nfe']}: {$razao} - {$cnpj}");
                            }
                        } catch (Exception $e) {
                            error_log("Erro ao extrair dados do fornecedor do XML: " . $e->getMessage());
                        }
                    }

                    // Se ainda não tem dados, tentar buscar da tabela pessoas pelo CNPJ extraído da chave
                    if (empty($cnpj) || empty($razao)) {
                        // Extrair CNPJ da chave NFe (posições 6 a 19)
                        $chaveNfe = $nfeDb['chave_nfe'] ?? '';
                        if (strlen($chaveNfe) >= 44) {
                            $cnpjChave = substr($chaveNfe, 6, 14);

                            // Tentar buscar fornecedor pelo CNPJ
                            try {
                                // Verificar estrutura da tabela pessoas
                                $stmtCheck = $this->db->query("SHOW COLUMNS FROM pessoas");
                                $columns = $stmtCheck->fetchAll();
                                $columnNames = array_column($columns, 'Field');

                                // Construir SELECT dinamicamente
                                $selectFields = ['id'];
                                $params = ['cnpj' => $cnpjChave];

                                // Adicionar campos de nome
                                if (in_array('razao_social', $columnNames)) {
                                    $selectFields[] = 'razao_social';
                                }
                                if (in_array('razaoSocial', $columnNames)) {
                                    $selectFields[] = 'razaoSocial';
                                }
                                if (in_array('name', $columnNames)) {
                                    $selectFields[] = 'name';
                                }
                                if (in_array('nome_fantasia', $columnNames)) {
                                    $selectFields[] = 'nome_fantasia';
                                }
                                if (in_array('nomeFantasia', $columnNames)) {
                                    $selectFields[] = 'nomeFantasia';
                                }
                                if (in_array('trade_name', $columnNames)) {
                                    $selectFields[] = 'trade_name';
                                }

                                // Adicionar campos de documento e construir condições WHERE
                                $docConditions = [];
                                if (in_array('document', $columnNames)) {
                                    $selectFields[] = 'document';
                                    $docConditions[] = 'document = :cnpj';
                                }
                                if (in_array('cnpj', $columnNames)) {
                                    $selectFields[] = 'cnpj';
                                    $docConditions[] = 'cnpj = :cnpj';
                                }
                                if (in_array('documento', $columnNames)) {
                                    $selectFields[] = 'documento';
                                    $docConditions[] = 'documento = :cnpj';
                                }

                                // Construir WHERE clause
                                if (!empty($docConditions)) {
                                    $whereClause = '(' . implode(' OR ', $docConditions) . ')';

                                    // Adicionar company_id se existir
                                    if (in_array('company_id', $columnNames)) {
                                        $whereClause .= ' AND company_id = :company_id';
                                        $params['company_id'] = $companyId;
                                    }

                                    $sql = "SELECT " . implode(', ', $selectFields) . " FROM pessoas WHERE " . $whereClause . " LIMIT 1";
                                    $stmtFornecedor = $this->db->prepare($sql);
                                    $stmtFornecedor->execute($params);
                                    $fornecedor = $stmtFornecedor->fetch();

                                    if ($fornecedor) {
                                        // Extrair CNPJ
                                        $cnpj = $fornecedor['document'] ?? $fornecedor['cnpj'] ?? $fornecedor['documento'] ?? $cnpjChave;

                                        // Extrair razão social/nome
                                        $razao = $fornecedor['razao_social'] ?? $fornecedor['razaoSocial'] ?? $fornecedor['name'] ?? $fornecedor['nome_fantasia'] ?? $fornecedor['nomeFantasia'] ?? $fornecedor['trade_name'] ?? '';

                                        // Atualizar o registro no banco
                                        try {
                                            $stmtUpdate = $this->db->prepare("
                                                    UPDATE nfe_recebidas
                                                    SET cnpj_fornecedor = :cnpj,
                                                        razao_social_fornecedor = :razao,
                                                        updated_at = NOW()
                                                    WHERE id = :id
                                                ");
                                            $stmtUpdate->execute([
                                                'cnpj' => $cnpj,
                                                'razao' => $razao,
                                                'id' => $nfeDb['id']
                                            ]);
                                            error_log("✅ Atualizou dados do fornecedor para NF-e {$chaveNfe}: {$razao} - {$cnpj}");
                                        } catch (Exception $e) {
                                            error_log("Erro ao atualizar dados do fornecedor: " . $e->getMessage());
                                        }
                                    }
                                }
                            } catch (Exception $e) {
                                error_log("Erro ao buscar fornecedor: " . $e->getMessage());
                            }
                        }
                    }

                    // Se ainda não tem dados do fornecedor e tem XML completo, tentar extrair do XML
                    if ((empty($cnpj) || empty($razao)) && !empty($nfeDb['xml_completo'])) {
                        try {
                            $xmlFornecedor = $nfeDb['xml_completo'];
                            $domFornecedor = new \DOMDocument();
                            $domFornecedor->loadXML($xmlFornecedor);

                            // Tentar extrair do emitente
                            $emit = $domFornecedor->getElementsByTagName('emit')->item(0);
                            if ($emit) {
                                $cnpjEmit = $emit->getElementsByTagName('CNPJ')->item(0);
                                $cpfEmit = $emit->getElementsByTagName('CPF')->item(0);
                                $nomeEmit = $emit->getElementsByTagName('xNome')->item(0);

                                if ($cnpjEmit && empty($cnpj)) {
                                    $cnpj = $cnpjEmit->nodeValue;
                                } elseif ($cpfEmit && empty($cnpj)) {
                                    $cnpj = $cpfEmit->nodeValue;
                                }

                                if ($nomeEmit && empty($razao)) {
                                    $razao = $nomeEmit->nodeValue;
                                }

                                // Se encontrou dados, atualizar no banco
                                if (!empty($cnpj) || !empty($razao)) {
                                    try {
                                        $stmtUpdate = $this->db->prepare("
                                                UPDATE nfe_recebidas
                                                SET cnpj_fornecedor = COALESCE(:cnpj, cnpj_fornecedor),
                                                    razao_social_fornecedor = COALESCE(:razao, razao_social_fornecedor),
                                                    updated_at = NOW()
                                                WHERE id = :id
                                            ");
                                        $stmtUpdate->execute([
                                            'cnpj' => $cnpj ?: null,
                                            'razao' => $razao ?: null,
                                            'id' => $nfeDb['id']
                                        ]);
                                        error_log("✅ Atualizou dados do fornecedor do XML para NF-e {$nfeDb['chave_nfe']}: {$razao} - {$cnpj}");
                                    } catch (Exception $e) {
                                        error_log("Erro ao atualizar dados do fornecedor do XML: " . $e->getMessage());
                                    }
                                }
                            }
                        } catch (Exception $e) {
                            error_log("Erro ao extrair dados do fornecedor do XML: " . $e->getMessage());
                        }
                    }

                    $chaveNfe = $nfeDb['chave_nfe'] ?? '';
                    if (!empty($chaveNfe)) {
                        $chavesNoBanco[$chaveNfe] = true; // Marcar como já no banco

                        // Verificar se já existe uma compra com esta chave_nfe
                        $jaImportada = false;
                        try {
                            $stmtCompra = $this->db->prepare("SELECT id FROM compras WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                            $stmtCompra->execute(['chave_nfe' => $chaveNfe, 'company_id' => $companyId]);
                            $compraExistente = $stmtCompra->fetch();
                            $jaImportada = !empty($compraExistente);
                        } catch (Exception $e) {
                            error_log("Erro ao verificar se NFe já foi importada: " . $e->getMessage());
                        }

                        $nfes[] = [
                            'chave_nfe' => $chaveNfe,
                            'cnpj_fornecedor' => $cnpj,
                            'razao_social' => $razao,
                            'razao_social_fornecedor' => $razao, // Garantir que ambos os campos estejam preenchidos
                            'data_emissao' => $nfeDb['data_emissao'] ? date('d/m/Y', strtotime($nfeDb['data_emissao'])) : '',
                            'valor' => $nfeDb['valor_total'] ?? $nfeDb['valor'] ?? 0,
                            'status' => $nfeDb['status_manifesto'] ?? $nfeDb['status'] ?? 'pendente',
                            'ja_importada' => $jaImportada // Flag para indicar se já foi importada
                        ];
                    }
                }

                error_log("Monitor NF-e: Buscou " . count($nfes) . " NF-e do banco");
                if (count($nfes) > 0) {
                    error_log("Monitor NF-e: Primeira NFe - Chave: " . ($nfes[0]['chave_nfe'] ?? 'vazio') . ", CNPJ: " . ($nfes[0]['cnpj_fornecedor'] ?? 'vazio') . ", Razão: " . ($nfes[0]['razao_social'] ?? 'vazio'));
                }
            } catch (Exception $e) {
                error_log("Erro ao buscar NF-e do banco: " . $e->getMessage());
            }

            // Se certificado está configurado, buscar da SEFAZ para complementar (apenas notas que não estão no banco)
            if (!empty($empresa['certificado_path']) && !empty($empresa['senha_certificado'])) {
                error_log("Monitor NF-e: Certificado configurado, buscando da SEFAZ para complementar");
                try {
                    error_log("Monitor NF-e: Buscando da SEFAZ para complementar (apenas notas não encontradas no banco)");
                    $nfeService = new \App\Services\NFeIntegrationService();
                    $resultado = $nfeService->consultarNFeDestinatario($empresa, $this->db);
                    $nfesSefaz = $resultado['nfes'] ?? [];

                    // Adicionar apenas notas que não estão no banco
                    foreach ($nfesSefaz as $nfeSefaz) {
                        $chaveSefaz = $nfeSefaz['chave_nfe'] ?? '';
                        if (!empty($chaveSefaz) && !isset($chavesNoBanco[$chaveSefaz])) {
                            // Verificar se já foi importada antes de adicionar
                            $jaImportada = false;
                            try {
                                $stmtCompra = $this->db->prepare("SELECT id FROM compras WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                                $stmtCompra->execute(['chave_nfe' => $chaveSefaz, 'company_id' => $companyId]);
                                $compraExistente = $stmtCompra->fetch();
                                $jaImportada = !empty($compraExistente);
                            } catch (Exception $e) {
                                error_log("Erro ao verificar se NFe já foi importada: " . $e->getMessage());
                            }

                            $nfeSefaz['ja_importada'] = $jaImportada;
                            $nfes[] = $nfeSefaz;
                            error_log("Monitor NF-e: Adicionando nota da SEFAZ que não está no banco: {$chaveSefaz}");
                        } else {
                            error_log("Monitor NF-e: Ignorando nota da SEFAZ que já está no banco: {$chaveSefaz}");
                        }
                    }

                    // Se houver aviso (ex: erro 656), usar como mensagem
                    if (!empty($resultado['aviso'])) {
                        $mensagemCertificado = $resultado['aviso'];
                    }

                    // Garantir que os dados do fornecedor estejam populados nas NF-e retornadas
                    foreach ($nfes as &$nfe) {
                        // Verificar se já foi importada (existe compra com esta chave_nfe)
                        if (empty($nfe['ja_importada'])) {
                            $jaImportada = false;
                            $chaveNfe = $nfe['chave_nfe'] ?? '';
                            if (!empty($chaveNfe)) {
                                try {
                                    $stmtCompra = $this->db->prepare("SELECT id FROM compras WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                                    $stmtCompra->execute(['chave_nfe' => $chaveNfe, 'company_id' => $companyId]);
                                    $compraExistente = $stmtCompra->fetch();
                                    $jaImportada = !empty($compraExistente);
                                } catch (Exception $e) {
                                    error_log("Erro ao verificar se NFe já foi importada: " . $e->getMessage());
                                }
                            }
                            $nfe['ja_importada'] = $jaImportada;
                        }

                        // Se não tem dados do fornecedor, tentar buscar do banco ou extrair do XML
                        if (empty($nfe['cnpj_fornecedor']) || empty($nfe['razao_social'])) {
                            try {
                                $stmtNfe = $this->db->prepare("
                                    SELECT cnpj_fornecedor, razao_social_fornecedor, xml_completo
                                    FROM nfe_recebidas
                                    WHERE chave_nfe = :chave_nfe
                                    AND company_id = :company_id
                                    LIMIT 1
                                ");
                                $stmtNfe->execute([
                                    'chave_nfe' => $nfe['chave_nfe'] ?? '',
                                    'company_id' => $companyId
                                ]);
                                $nfeDb = $stmtNfe->fetch();

                                if ($nfeDb) {
                                    if (empty($nfe['cnpj_fornecedor']) && !empty($nfeDb['cnpj_fornecedor'])) {
                                        $nfe['cnpj_fornecedor'] = $nfeDb['cnpj_fornecedor'];
                                    }
                                    if (empty($nfe['razao_social']) && !empty($nfeDb['razao_social_fornecedor'])) {
                                        $nfe['razao_social'] = $nfeDb['razao_social_fornecedor'];
                                        $nfe['razao_social_fornecedor'] = $nfeDb['razao_social_fornecedor'];
                                    }

                                    // Se ainda não tem e tem XML completo, tentar extrair
                                    if ((empty($nfe['cnpj_fornecedor']) || empty($nfe['razao_social'])) && !empty($nfeDb['xml_completo'])) {
                                        try {
                                            $domXml = new \DOMDocument();
                                            $domXml->loadXML($nfeDb['xml_completo']);
                                            $emit = $domXml->getElementsByTagName('emit')->item(0);

                                            if ($emit) {
                                                $cnpjEmit = $emit->getElementsByTagName('CNPJ')->item(0);
                                                $cpfEmit = $emit->getElementsByTagName('CPF')->item(0);
                                                $nomeEmit = $emit->getElementsByTagName('xNome')->item(0);

                                                if ($cnpjEmit && empty($nfe['cnpj_fornecedor'])) {
                                                    $nfe['cnpj_fornecedor'] = $cnpjEmit->nodeValue;
                                                } elseif ($cpfEmit && empty($nfe['cnpj_fornecedor'])) {
                                                    $nfe['cnpj_fornecedor'] = $cpfEmit->nodeValue;
                                                }

                                                if ($nomeEmit && empty($nfe['razao_social'])) {
                                                    $nfe['razao_social'] = $nomeEmit->nodeValue;
                                                    $nfe['razao_social_fornecedor'] = $nomeEmit->nodeValue;
                                                }

                                                // Atualizar no banco se encontrou dados
                                                if (!empty($nfe['cnpj_fornecedor']) || !empty($nfe['razao_social'])) {
                                                    $stmtUpdate = $this->db->prepare("
                                                        UPDATE nfe_recebidas
                                                        SET cnpj_fornecedor = COALESCE(:cnpj, cnpj_fornecedor),
                                                            razao_social_fornecedor = COALESCE(:razao, razao_social_fornecedor),
                                                            updated_at = NOW()
                                                        WHERE chave_nfe = :chave_nfe AND company_id = :company_id
                                                    ");
                                                    $stmtUpdate->execute([
                                                        'cnpj' => $nfe['cnpj_fornecedor'] ?: null,
                                                        'razao' => $nfe['razao_social'] ?: null,
                                                        'chave_nfe' => $nfe['chave_nfe'] ?? '',
                                                        'company_id' => $companyId
                                                    ]);
                                                }
                                            }
                                        } catch (Exception $e) {
                                            error_log("Erro ao extrair dados do fornecedor do XML: " . $e->getMessage());
                                        }
                                    }
                                }
                            } catch (Exception $e) {
                                error_log("Erro ao buscar dados do fornecedor do banco: " . $e->getMessage());
                            }
                        }
                    }
                    unset($nfe); // Liberar referência
                } catch (Exception $e) {
                    error_log("Erro ao consultar NF-e SEFAZ: " . $e->getMessage());
                    $mensagemCertificado = 'Erro ao consultar SEFAZ: ' . $e->getMessage();
                }

                // Se não conseguiu buscar da SEFAZ, continuar com as notas do banco (já carregadas acima)
                if (empty($nfesSefaz)) {
                    try {
                        // Log para debug
                        error_log("Monitor NF-e: SEFAZ retornou vazio, buscando do banco para company_id: {$companyId}");

                        // Verificar se a tabela existe
                        $stmtCheck = $this->db->query("SHOW TABLES LIKE 'nfe_recebidas'");
                        $tabelaExiste = $stmtCheck->fetch();
                        if (!$tabelaExiste) {
                            error_log("Monitor NF-e: AVISO - Tabela nfe_recebidas não existe!");
                            $nfesDb = [];
                        } else {
                            // Contar total de registros para esta empresa
                            $stmtCountCompany = $this->db->prepare("SELECT COUNT(*) as total FROM nfe_recebidas WHERE company_id = :company_id");
                            $stmtCountCompany->execute(['company_id' => $companyId]);
                            $totalCompany = $stmtCountCompany->fetch()['total'] ?? 0;
                            error_log("Monitor NF-e: Total de NF-e no banco para company_id {$companyId}: {$totalCompany}");

                            // Se não encontrou para este company_id, verificar se há notas com outros company_id (debug)
                            if ($totalCompany == 0) {
                                $stmtAll = $this->db->query("SELECT company_id, COUNT(*) as total FROM nfe_recebidas GROUP BY company_id");
                                $todosCompanyIds = $stmtAll->fetchAll();
                                if (!empty($todosCompanyIds)) {
                                    error_log("Monitor NF-e: AVISO - Encontradas notas com outros company_ids: " . json_encode($todosCompanyIds));
                                } else {
                                    // Verificar se há notas sem filtro de company_id
                                    $stmtTotal = $this->db->query("SELECT COUNT(*) as total FROM nfe_recebidas");
                                    $totalGeral = $stmtTotal->fetch()['total'] ?? 0;
                                    error_log("Monitor NF-e: Total geral de NF-e na tabela (todas empresas): {$totalGeral}");
                                }
                            }

                            $stmt = $this->db->prepare("
                                SELECT * FROM nfe_recebidas
                                WHERE company_id = :company_id
                                ORDER BY data_emissao DESC, id DESC
                                LIMIT 100
                            ");
                            $stmt->execute(['company_id' => $companyId]);
                            $nfesDb = $stmt->fetchAll();

                            error_log("Monitor NF-e: Query retornou " . count($nfesDb) . " registros");
                        }

                        foreach ($nfesDb as $nfeDb) {
                            $cnpj = $nfeDb['cnpj_fornecedor'] ?? $nfeDb['cnpj_emitente'] ?? '';
                            $razao = $nfeDb['razao_social_fornecedor'] ?? $nfeDb['razao_social'] ?? $nfeDb['nome_emitente'] ?? '';

                            // Se os dados estão vazios, tentar buscar da tabela pessoas pelo CNPJ extraído da chave
                            if (empty($cnpj) || empty($razao)) {
                                // Extrair CNPJ da chave NFe (posições 6 a 19)
                                $chaveNfe = $nfeDb['chave_nfe'] ?? '';
                                if (strlen($chaveNfe) >= 44) {
                                    $cnpjChave = substr($chaveNfe, 6, 14);

                                    // Tentar buscar fornecedor pelo CNPJ
                                    try {
                                        // Verificar estrutura da tabela pessoas
                                        $stmtCheck = $this->db->query("SHOW COLUMNS FROM pessoas");
                                        $columns = $stmtCheck->fetchAll();
                                        $columnNames = array_column($columns, 'Field');

                                        // Construir SELECT dinamicamente
                                        $selectFields = ['id'];
                                        $whereConditions = [];
                                        $params = ['cnpj' => $cnpjChave];

                                        // Adicionar campos de nome
                                        if (in_array('razao_social', $columnNames)) {
                                            $selectFields[] = 'razao_social';
                                        }
                                        if (in_array('razaoSocial', $columnNames)) {
                                            $selectFields[] = 'razaoSocial';
                                        }
                                        if (in_array('name', $columnNames)) {
                                            $selectFields[] = 'name';
                                        }
                                        if (in_array('nome_fantasia', $columnNames)) {
                                            $selectFields[] = 'nome_fantasia';
                                        }
                                        if (in_array('nomeFantasia', $columnNames)) {
                                            $selectFields[] = 'nomeFantasia';
                                        }
                                        if (in_array('trade_name', $columnNames)) {
                                            $selectFields[] = 'trade_name';
                                        }

                                        // Adicionar campos de documento e construir condições WHERE
                                        $docConditions = [];
                                        if (in_array('document', $columnNames)) {
                                            $selectFields[] = 'document';
                                            $docConditions[] = 'document = :cnpj';
                                        }
                                        if (in_array('cnpj', $columnNames)) {
                                            $selectFields[] = 'cnpj';
                                            $docConditions[] = 'cnpj = :cnpj';
                                        }
                                        if (in_array('documento', $columnNames)) {
                                            $selectFields[] = 'documento';
                                            $docConditions[] = 'documento = :cnpj';
                                        }

                                        // Construir WHERE clause
                                        if (!empty($docConditions)) {
                                            $whereClause = '(' . implode(' OR ', $docConditions) . ')';

                                            // Adicionar company_id se existir
                                            if (in_array('company_id', $columnNames)) {
                                                $whereClause .= ' AND company_id = :company_id';
                                                $params['company_id'] = $companyId;
                                            }

                                            $sql = "SELECT " . implode(', ', $selectFields) . " FROM pessoas WHERE " . $whereClause . " LIMIT 1";
                                            $stmtFornecedor = $this->db->prepare($sql);
                                            $stmtFornecedor->execute($params);
                                            $fornecedor = $stmtFornecedor->fetch();

                                            if ($fornecedor) {
                                                // Extrair CNPJ
                                                $cnpj = $fornecedor['document'] ?? $fornecedor['cnpj'] ?? $fornecedor['documento'] ?? $cnpjChave;

                                                // Extrair razão social/nome
                                                $razao = $fornecedor['razao_social'] ?? $fornecedor['razaoSocial'] ?? $fornecedor['name'] ?? $fornecedor['nome_fantasia'] ?? $fornecedor['nomeFantasia'] ?? $fornecedor['trade_name'] ?? '';

                                                // Atualizar o registro no banco
                                                try {
                                                    $stmtUpdate = $this->db->prepare("
                                                        UPDATE nfe_recebidas
                                                        SET cnpj_fornecedor = :cnpj,
                                                            razao_social_fornecedor = :razao,
                                                            updated_at = NOW()
                                                        WHERE id = :id
                                                    ");
                                                    $stmtUpdate->execute([
                                                        'cnpj' => $cnpj,
                                                        'razao' => $razao,
                                                        'id' => $nfeDb['id']
                                                    ]);
                                                    error_log("✅ Atualizou dados do fornecedor para NF-e {$chaveNfe}: {$razao} - {$cnpj}");
                                                } catch (Exception $e) {
                                                    error_log("Erro ao atualizar dados do fornecedor: " . $e->getMessage());
                                                }
                                            }
                                        }
                                    } catch (Exception $e) {
                                        error_log("Erro ao buscar fornecedor: " . $e->getMessage());
                                    }
                                }
                            }

                            $chaveNfe = $nfeDb['chave_nfe'] ?? '';

                            // Verificar se já existe uma compra com esta chave_nfe
                            $jaImportada = false;
                            if (!empty($chaveNfe)) {
                                try {
                                    $stmtCompra = $this->db->prepare("SELECT id FROM compras WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                                    $stmtCompra->execute(['chave_nfe' => $chaveNfe, 'company_id' => $companyId]);
                                    $compraExistente = $stmtCompra->fetch();
                                    $jaImportada = !empty($compraExistente);
                                } catch (Exception $e) {
                                    error_log("Erro ao verificar se NFe já foi importada: " . $e->getMessage());
                                }
                            }

                            $nfes[] = [
                                'chave_nfe' => $chaveNfe,
                                'cnpj_fornecedor' => $cnpj,
                                'razao_social' => $razao,
                                'data_emissao' => $nfeDb['data_emissao'] ? date('d/m/Y', strtotime($nfeDb['data_emissao'])) : '',
                                'valor' => $nfeDb['valor_total'] ?? $nfeDb['valor'] ?? 0,
                                'status' => $nfeDb['status_manifesto'] ?? $nfeDb['status'] ?? 'pendente',
                                'ja_importada' => $jaImportada // Flag para indicar se já foi importada
                            ];
                        }

                        error_log("Monitor NF-e: Buscou " . count($nfes) . " NF-e do banco (fallback)");
                        if (count($nfes) > 0) {
                            error_log("Monitor NF-e: Primeira NFe - CNPJ: " . ($nfes[0]['cnpj_fornecedor'] ?? 'vazio') . ", Razão: " . ($nfes[0]['razao_social'] ?? 'vazio'));
                        }
                    } catch (Exception $e) {
                        error_log("Erro ao buscar NF-e do banco: " . $e->getMessage());
                    }
                }
            }

            // Mapear nomes das colunas (empresas usa PT, companies usa EN)
            $nomeEmpresa = $empresa['razao_social'] ?? $empresa['name'] ?? $empresa['nome_fantasia'] ?? $empresa['trade_name'] ?? 'Empresa';
            $cnpjEmpresa = $empresa['cnpj'] ?? $empresa['document'] ?? '';

            // Debug log
            error_log("Monitor NF-e - Empresa encontrada: " . json_encode([
                'id' => $empresa['id'] ?? null,
                'nome' => $nomeEmpresa,
                'cnpj' => $cnpjEmpresa,
                'certificado' => $empresa['certificado_path'] ?? 'não configurado'
            ]));

            // Remover duplicatas por chave_nfe e ordenar de forma consistente
            $nfesUnicas = [];
            $chavesProcessadas = [];
            foreach ($nfes as $nfe) {
                $chave = $nfe['chave_nfe'] ?? '';
                if (!empty($chave) && !isset($chavesProcessadas[$chave])) {
                    $chavesProcessadas[$chave] = true;
                    $nfesUnicas[] = $nfe;
                }
            }

            // Ordenar de forma consistente: pendentes primeiro, depois confirmadas, depois por data
            usort($nfesUnicas, function ($a, $b) {
                $statusA = $a['status'] ?? 'pendente';
                $statusB = $b['status'] ?? 'pendente';

                // Prioridade: pendente = 1, confirmada = 2, outros = 3
                $prioridadeA = ($statusA === 'pendente') ? 1 : (($statusA === 'confirmada') ? 2 : 3);
                $prioridadeB = ($statusB === 'pendente') ? 1 : (($statusB === 'confirmada') ? 2 : 3);

                if ($prioridadeA !== $prioridadeB) {
                    return $prioridadeA - $prioridadeB;
                }

                // Se mesmo status, ordenar por data (mais recente primeiro)
                $dataA = $a['data_emissao'] ?? '';
                $dataB = $b['data_emissao'] ?? '';
                if (!empty($dataA) && !empty($dataB)) {
                    $timestampA = strtotime(str_replace('/', '-', $dataA));
                    $timestampB = strtotime(str_replace('/', '-', $dataB));
                    if ($timestampA !== $timestampB) {
                        return $timestampB - $timestampA; // Mais recente primeiro
                    }
                }

                // Se mesma data, ordenar por chave (para consistência)
                $chaveA = $a['chave_nfe'] ?? '';
                $chaveB = $b['chave_nfe'] ?? '';
                return strcmp($chaveB, $chaveA); // Ordem decrescente
            });

            $nfes = $nfesUnicas;

            // Debug: verificar dados das NF-e
            error_log("Monitor NF-e - Total de NF-e retornadas (após remoção de duplicatas): " . count($nfes));
            if (count($nfes) > 0) {
                error_log("Monitor NF-e - Primeira NFe retornada: " . json_encode($nfes[0]));
            }

            // Buscar todas as empresas disponíveis para o seletor
            $todasEmpresas = $this->getTodasEmpresasParaMonitor();

            $this->success('Monitor carregado', [
                'nfes' => $nfes,
                'empresa' => [
                    'id' => $empresaId,
                    'nome' => $nomeEmpresa,
                    'cnpj' => $cnpjEmpresa
                ],
                'empresas' => $todasEmpresas,
                'aviso' => $mensagemCertificado
            ]);

        } catch (Exception $e) {
            error_log("Erro no monitor NF-e: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao carregar monitor de NF-e: ' . $e->getMessage());
        }
    }

    public function manifestarNFe(): void
    {
        try {
            $chaveNfe = $this->request->post('chave_nfe');
            $tipoManifesto = $this->request->post('tipo_manifesto');

            if (empty($chaveNfe) || empty($tipoManifesto)) {
                $this->error('Dados inválidos');
                return;
            }

            $companyId = $this->getCompanyId();

            // Validar e corrigir chave NFe (deve ter 44 dígitos)
            $chaveNfeLimpa = preg_replace('/\D/', '', $chaveNfe);

            if (strlen($chaveNfeLimpa) !== 44) {
                error_log("⚠️ Chave NF-e recebida tem tamanho incorreto: {$chaveNfeLimpa} (tamanho: " . strlen($chaveNfeLimpa) . "). Buscando chave completa no banco...");

                // Tentar buscar a chave completa no banco de dados
                try {
                    // Buscar por chave parcial (pode estar salva truncada)
                    $stmtChave = $this->db->prepare("
                        SELECT chave_nfe, xml_completo
                        FROM nfe_recebidas
                        WHERE (chave_nfe LIKE :chave_parcial OR chave_nfe = :chave_exata)
                        AND company_id = :company_id
                        LIMIT 1
                    ");
                    $stmtChave->execute([
                        'chave_parcial' => $chaveNfeLimpa . '%',
                        'chave_exata' => $chaveNfeLimpa,
                        'company_id' => $companyId
                    ]);
                    $nfeDb = $stmtChave->fetch();

                    if ($nfeDb) {
                        // Se encontrou no banco e tem 44 dígitos, usar
                        if (strlen($nfeDb['chave_nfe']) === 44) {
                            $chaveNfeLimpa = preg_replace('/\D/', '', $nfeDb['chave_nfe']);
                            error_log("✅ Chave completa encontrada no banco: {$chaveNfeLimpa}");
                        }
                        // Se não tem 44 dígitos mas tem XML, extrair do XML
                        elseif (!empty($nfeDb['xml_completo'])) {
                            try {
                                $dom = new \DOMDocument();
                                $dom->loadXML($nfeDb['xml_completo']);

                                // Tentar extrair do infProt
                                $infProt = $dom->getElementsByTagName('infProt')->item(0);
                                if ($infProt) {
                                    $chaveCompleta = $infProt->getAttribute('Id') ?? '';
                                    $chaveCompleta = str_replace('NFe', '', $chaveCompleta);
                                    if (strlen($chaveCompleta) === 44) {
                                        $chaveNfeLimpa = $chaveCompleta;
                                        error_log("✅ Chave completa extraída do XML (infProt): {$chaveNfeLimpa}");
                                    }
                                }

                                // Se não encontrou no infProt, tentar no chNFe
                                if (strlen($chaveNfeLimpa) !== 44) {
                                    $chNFe = $dom->getElementsByTagName('chNFe')->item(0);
                                    if ($chNFe && strlen($chNFe->nodeValue) === 44) {
                                        $chaveNfeLimpa = preg_replace('/\D/', '', $chNFe->nodeValue);
                                        error_log("✅ Chave completa extraída do XML (chNFe): {$chaveNfeLimpa}");
                                    }
                                }

                                // Se ainda não encontrou, tentar no Id da NFe
                                if (strlen($chaveNfeLimpa) !== 44) {
                                    $nfeNode = $dom->getElementsByTagName('NFe')->item(0);
                                    if ($nfeNode) {
                                        $idNFe = $nfeNode->getAttribute('Id') ?? '';
                                        $idNFe = str_replace('NFe', '', $idNFe);
                                        if (strlen($idNFe) === 44) {
                                            $chaveNfeLimpa = $idNFe;
                                            error_log("✅ Chave completa extraída do XML (Id NFe): {$chaveNfeLimpa}");
                                        }
                                    }
                                }
                            } catch (\Exception $e) {
                                error_log("Erro ao extrair chave do XML: " . $e->getMessage());
                            }
                        }
                    }
                } catch (\Exception $e) {
                    error_log("Erro ao buscar chave no banco: " . $e->getMessage());
                }

                // Se ainda não tem 44 dígitos, retornar erro
                if (strlen($chaveNfeLimpa) !== 44) {
                    error_log("❌ ERRO: Não foi possível encontrar chave completa de 44 dígitos. Chave recebida: {$chaveNfe}, Tamanho: " . strlen($chaveNfeLimpa));
                    $this->error("Chave da NF-e inválida. A chave deve ter 44 dígitos, mas foi recebida com " . strlen($chaveNfeLimpa) . " dígitos. Chave recebida: {$chaveNfe}");
                    return;
                }
            }

            // Usar a chave corrigida
            $chaveNfe = $chaveNfeLimpa;

            // Buscar empresa (tenta empresas, depois companies)
            $stmt = $this->db->prepare("SELECT * FROM empresas WHERE id = :id");
            $stmt->execute(['id' => $companyId]);
            $empresa = $stmt->fetch();

            if (!$empresa) {
                $stmt = $this->db->prepare("SELECT * FROM companies WHERE id = :id");
                $stmt->execute(['id' => $companyId]);
                $empresa = $stmt->fetch();
            }

            if (!$empresa) {
                $this->error('Empresa não encontrada');
                return;
            }

            // Enviar manifestação para SEFAZ
            try {
                $nfeService = new \App\Services\NFeIntegrationService();

                // Mapear tipo de manifesto
                $tipoMap = [
                    'ciencia' => 'ciencia',
                    'confirmar' => 'confirmacao',
                    'desconhecimento' => 'desconhecimento',
                    'nao_realizada' => 'nao_realizada'
                ];

                $tipo = $tipoMap[$tipoManifesto] ?? 'ciencia';

                $resultado = $nfeService->manifestarDestinatario($empresa, $chaveNfe, $tipo);

                if ($resultado['sucesso'] ?? false) {
                    $this->success('Manifestação enviada com sucesso!');
                } else {
                    $this->error($resultado['mensagem'] ?? 'Erro ao enviar manifestação');
                }

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

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

    private function getCompra(int $id): ?array
    {
        $stmt = $this->db->prepare("SELECT * FROM compras WHERE id = :id AND company_id = :company_id");
        $stmt->execute(['id' => $id, 'company_id' => $this->getCompanyId()]);
        return $stmt->fetch() ?: null;
    }

    /**
     * Cadastra fornecedor automaticamente e cria compra
     */
    /**
     * Função auxiliar para construir INSERT seguro - garante correspondência exata entre placeholders e valores
     * Esta função resolve definitivamente o erro SQLSTATE[HY093]
     */
    /**
     * Escreve log detalhado em arquivo para debug de importação de NFe
     */
    private function logNFeDetalhado(string $mensagem, array $contexto = []): void
    {
        $logDir = __DIR__ . '/../../storage/logs';

        // Criar diretório se não existir
        if (!is_dir($logDir)) {
            @mkdir($logDir, 0755, true);
        }

        $logFile = $logDir . '/nfe_importacao_' . date('Y-m-d') . '.log';
        $timestamp = date('Y-m-d H:i:s.u');
        $memory = round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB';
        $peakMemory = round(memory_get_peak_usage(true) / 1024 / 1024, 2) . 'MB';

        $logEntry = "[{$timestamp}] [Mem: {$memory} / Peak: {$peakMemory}] {$mensagem}\n";

        if (!empty($contexto)) {
            $logEntry .= "Contexto:\n";
            foreach ($contexto as $key => $value) {
                // Limitar tamanho de strings muito grandes (como XML)
                if (is_string($value)) {
                    $maxLength = 5000; // Limite de 5000 caracteres para strings
                    if (strlen($value) > $maxLength) {
                        $value = substr($value, 0, $maxLength) . "\n... [TRUNCADO: " . (strlen($value) - $maxLength) . " caracteres restantes] ...";
                    }
                    $logEntry .= "  {$key}: {$value}\n";
                } elseif (is_array($value) || is_object($value)) {
                    $jsonValue = json_encode($value, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
                    // Limitar também JSON muito grande
                    if (strlen($jsonValue) > 10000) {
                        $jsonValue = substr($jsonValue, 0, 10000) . "\n... [JSON TRUNCADO] ...";
                    }
                    $logEntry .= "  {$key}: " . $jsonValue . "\n";
                } else {
                    $logEntry .= "  {$key}: {$value}\n";
                }
            }
        }

        $logEntry .= str_repeat('-', 100) . "\n\n";

        @file_put_contents($logFile, $logEntry, FILE_APPEND | LOCK_EX);

        // Também escrever no error_log padrão para garantir (sem contexto para evitar spam)
        error_log("NFe Import: {$mensagem}");
    }

    private function construirInsertSeguro(array $campos, array $valores, array $dados): array
    {
        $this->logNFeDetalhado("construirInsertSeguro: INÍCIO", [
            'total_campos' => count($campos),
            'total_valores' => count($valores),
            'total_dados' => count($dados),
            'campos' => $campos,
            'valores' => $valores,
            'dados_keys' => array_keys($dados)
        ]);

        $camposFinais = [];
        $valoresFinais = [];
        $dadosFinais = [];

        // Validar que os arrays têm o mesmo tamanho
        if (count($campos) !== count($valores)) {
            $this->logNFeDetalhado("ERRO: Arrays desalinhados", [
                'count_campos' => count($campos),
                'count_valores' => count($valores)
            ]);
            throw new Exception("Arrays de campos e valores têm tamanhos diferentes: " . count($campos) . " vs " . count($valores));
        }

        for ($i = 0; $i < count($campos); $i++) {
            $campo = $campos[$i];
            $valor = $valores[$i];

            // Se é um placeholder (começa com :)
            if (strpos($valor, ':') === 0) {
                $placeholder = substr($valor, 1);
                // Só adiciona se o placeholder existe no array de dados
                if (array_key_exists($placeholder, $dados)) {
                    $camposFinais[] = $campo;
                    $valoresFinais[] = $valor;
                    $dadosFinais[$placeholder] = $dados[$placeholder];
                } else {
                    // Placeholder sem valor - não adiciona ao SQL
                    error_log("⚠️ Placeholder '{$placeholder}' sem valor no array de dados - removendo do INSERT");
                }
            } else {
                // Valor fixo (CURDATE(), NOW(), '0', etc) - não precisa de binding
                $camposFinais[] = $campo;
                $valoresFinais[] = $valor;
            }
        }

        // Construir SQL temporário para validação
        $sqlTemp = "INSERT INTO temp (" . implode(', ', $camposFinais) . ") VALUES (" . implode(', ', $valoresFinais) . ")";

        // Validação final: garantir que não há placeholders duplicados
        preg_match_all('/:(\w+)/', $sqlTemp, $matches);
        $placeholdersNaQuery = $matches[1] ?? [];

        if (!empty($placeholdersNaQuery)) {
            $placeholdersCount = array_count_values($placeholdersNaQuery);
            $duplicados = array_filter($placeholdersCount, function ($count) {
                return $count > 1;
            });
            if (!empty($duplicados)) {
                $errorMsg = "Placeholders duplicados na query: " . implode(', ', array_keys($duplicados));
                error_log("❌ ERRO: {$errorMsg}");
                throw new Exception($errorMsg);
            }

            // Verificar se todos os placeholders têm valores
            $placeholdersSemValor = array_diff($placeholdersNaQuery, array_keys($dadosFinais));
            if (!empty($placeholdersSemValor)) {
                $errorMsg = "Placeholders sem valores: " . implode(', ', $placeholdersSemValor);
                error_log("❌ ERRO: {$errorMsg}");
                error_log("   Placeholders na query: " . implode(', ', $placeholdersNaQuery));
                error_log("   Dados disponíveis: " . implode(', ', array_keys($dadosFinais)));
                throw new Exception($errorMsg);
            }

            // Verificar se não há dados extras que não são placeholders
            $dadosExtras = array_diff(array_keys($dadosFinais), $placeholdersNaQuery);
            if (!empty($dadosExtras)) {
                error_log("⚠️ Aviso: Dados fornecidos sem placeholders correspondentes: " . implode(', ', $dadosExtras));
                error_log("   Placeholders esperados: " . implode(', ', $placeholdersNaQuery));
                error_log("   Dados fornecidos: " . implode(', ', array_keys($dadosFinais)));
                // Remover dados extras para evitar erro PDO
                foreach ($dadosExtras as $extra) {
                    unset($dadosFinais[$extra]);
                    error_log("   Removido dado extra: {$extra}");
                }
            }

            // Validação final crítica: garantir que cada placeholder tem um valor E cada valor tem um placeholder
            $dadosFinaisKeys = array_keys($dadosFinais);
            if (count($placeholdersNaQuery) !== count($dadosFinaisKeys)) {
                $errorMsg = "Número de placeholders (" . count($placeholdersNaQuery) . ") não corresponde ao número de dados (" . count($dadosFinaisKeys) . ")";
                error_log("❌ ERRO CRÍTICO: {$errorMsg}");
                error_log("   Placeholders: " . implode(', ', $placeholdersNaQuery));
                error_log("   Dados: " . implode(', ', $dadosFinaisKeys));
                throw new Exception($errorMsg);
            }
        }

        // Garantir que os dados finais contêm apenas os placeholders que estão na query
        $dadosFinaisLimpos = [];
        foreach ($placeholdersNaQuery as $placeholder) {
            if (isset($dadosFinais[$placeholder])) {
                $dadosFinaisLimpos[$placeholder] = $dadosFinais[$placeholder];
            } else {
                $this->logNFeDetalhado("❌ ERRO CRÍTICO: Placeholder sem dados", [
                    'placeholder' => $placeholder,
                    'placeholders_na_query' => $placeholdersNaQuery,
                    'dados_finais_keys' => array_keys($dadosFinais)
                ]);
            }
        }

        // Se houver diferença, usar os dados limpos
        if (count($dadosFinaisLimpos) !== count($dadosFinais)) {
            $this->logNFeDetalhado("⚠️ Limpando dados finais", [
                'total_antes' => count($dadosFinais),
                'total_depois' => count($dadosFinaisLimpos),
                'removidos' => count($dadosFinais) - count($dadosFinaisLimpos),
                'dados_removidos' => array_diff(array_keys($dadosFinais), array_keys($dadosFinaisLimpos))
            ]);
            $dadosFinais = $dadosFinaisLimpos;
        }

        $this->logNFeDetalhado("construirInsertSeguro: RESULTADO FINAL", [
            'total_campos_finais' => count($camposFinais),
            'total_valores_finais' => count($valoresFinais),
            'total_dados_finais' => count($dadosFinais),
            'campos_finais' => $camposFinais,
            'valores_finais' => $valoresFinais,
            'dados_finais_keys' => array_keys($dadosFinais),
            'placeholders_na_query' => $placeholdersNaQuery,
            'correspondencia_perfeita' => count($placeholdersNaQuery) === count($dadosFinais) && empty(array_diff($placeholdersNaQuery, array_keys($dadosFinais)))
        ]);

        return [
            'campos' => $camposFinais,
            'valores' => $valoresFinais,
            'dados' => $dadosFinais
        ];
    }

    public function cadastrarFornecedorECriarCompra(): void
    {
        try {
            $cnpj = $this->request->post('cnpj');
            $dadosEmitente = $this->request->post('dados_emitente', []);
            $chaveNfe = $this->request->post('chave_nfe');
            $xmlCompleto = $this->request->post('xml_completo');

            if (empty($cnpj)) {
                $this->error('CNPJ não informado');
                return;
            }

            $companyId = $this->getCompanyId();

            // Se não recebeu XML no POST, buscar da tabela nfe_recebidas usando a chave
            if (empty($xmlCompleto) && !empty($chaveNfe)) {
                try {
                    $stmt = $this->db->prepare("SELECT xml_completo FROM nfe_recebidas WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                    $stmt->execute(['chave_nfe' => $chaveNfe, 'company_id' => $companyId]);
                    $nfe = $stmt->fetch();
                    if ($nfe && !empty($nfe['xml_completo'])) {
                        $xmlCompleto = $nfe['xml_completo'];
                    }
                } catch (Exception $e) {
                    error_log("Erro ao buscar XML da NF-e: " . $e->getMessage());
                }
            }

            // Verificar se já existe (usar mesma lógica do verificarOuCadastrarFornecedor)
            $stmt = $this->db->prepare("
                SELECT id FROM pessoas
                WHERE company_id = :company_id
                AND document = :document
                LIMIT 1
            ");
            $stmt->execute(['company_id' => $companyId, 'document' => $cnpj]);
            $fornecedorExistente = $stmt->fetch();

            if ($fornecedorExistente) {
                $fornecedorId = (int) $fornecedorExistente['id'];
            } else {
                // Verificar estrutura da tabela
                $stmtCheck = $this->db->query("SHOW COLUMNS FROM pessoas");
                $columns = $stmtCheck->fetchAll();
                $columnNames = array_column($columns, 'Field');

                // Cadastrar fornecedor usando a mesma lógica do verificarOuCadastrarFornecedor
                $campos = ['company_id', 'name', 'document', 'is_active'];
                $valores = [':company_id', ':name', ':document', '1'];
                $dados = [
                    'company_id' => $companyId,
                    'name' => $dadosEmitente['nome'] ?? 'Fornecedor',
                    'document' => $cnpj
                ];

                // Adicionar campos opcionais
                if (in_array('trade_name', $columnNames)) {
                    $campos[] = 'trade_name';
                    $valores[] = ':trade_name';
                    $dados['trade_name'] = $dadosEmitente['nome_fantasia'] ?? null;
                }

                if (in_array('rg_ie', $columnNames) && !empty($dadosEmitente['ie'])) {
                    $campos[] = 'rg_ie';
                    $valores[] = ':rg_ie';
                    $dados['rg_ie'] = $dadosEmitente['ie'];
                }

                if (in_array('type', $columnNames)) {
                    $campos[] = 'type';
                    $valores[] = ':type';
                    $dados['type'] = 'fornecedor';
                }

                if (in_array('tipo_fornecedor', $columnNames)) {
                    $campos[] = 'tipo_fornecedor';
                    $valores[] = '1';
                }

                if (in_array('person_type', $columnNames)) {
                    $campos[] = 'person_type';
                    $valores[] = ':person_type';
                    $dados['person_type'] = 'juridica';
                }

                // Endereço
                if (in_array('address', $columnNames) && !empty($dadosEmitente['endereco'])) {
                    $campos[] = 'address';
                    $valores[] = ':address';
                    $dados['address'] = $dadosEmitente['endereco'];
                }
                if (in_array('numero', $columnNames) && !empty($dadosEmitente['numero'])) {
                    $campos[] = 'numero';
                    $valores[] = ':numero';
                    $dados['numero'] = $dadosEmitente['numero'];
                }
                if (in_array('complemento', $columnNames) && !empty($dadosEmitente['complemento'])) {
                    $campos[] = 'complemento';
                    $valores[] = ':complemento';
                    $dados['complemento'] = $dadosEmitente['complemento'];
                }
                if (in_array('bairro', $columnNames) && !empty($dadosEmitente['bairro'])) {
                    $campos[] = 'bairro';
                    $valores[] = ':bairro';
                    $dados['bairro'] = $dadosEmitente['bairro'];
                }
                if (in_array('city', $columnNames) && !empty($dadosEmitente['cidade'])) {
                    $campos[] = 'city';
                    $valores[] = ':city';
                    $dados['city'] = $dadosEmitente['cidade'];
                }
                if (in_array('state', $columnNames) && !empty($dadosEmitente['estado'])) {
                    $campos[] = 'state';
                    $valores[] = ':state';
                    $dados['state'] = $dadosEmitente['estado'];
                }
                if (in_array('zip_code', $columnNames) && !empty($dadosEmitente['cep'])) {
                    $campos[] = 'zip_code';
                    $valores[] = ':zip_code';
                    $dados['zip_code'] = preg_replace('/[^0-9]/', '', $dadosEmitente['cep']);
                }
                if (in_array('phone', $columnNames) && !empty($dadosEmitente['telefone'])) {
                    $campos[] = 'phone';
                    $valores[] = ':phone';
                    $dados['phone'] = $dadosEmitente['telefone'];
                }

                $campos[] = 'created_at';
                $valores[] = 'NOW()';

                $sql = "INSERT INTO pessoas (" . implode(', ', $campos) . ") VALUES (" . implode(', ', $valores) . ")";
                $stmt = $this->db->prepare($sql);
                $stmt->execute($dados);
                $fornecedorId = (int) $this->db->lastInsertId();
            }

            // Verificar estrutura da tabela compras
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM compras");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');

            // Criar compra
            $numeroCompra = 'NFe ' . (!empty($chaveNfe) ? substr($chaveNfe, 0, 8) : date('YmdHis'));
            $campos = ['company_id', 'fornecedor_id', 'numero', 'data_compra', 'total', 'status', 'created_at', 'updated_at'];
            $valores = [':company_id', ':fornecedor_id', ':numero', 'CURDATE()', ':total', ':status', 'NOW()', 'NOW()'];
            $dados = [
                'company_id' => $companyId,
                'fornecedor_id' => $fornecedorId,
                'numero' => $numeroCompra,
                'total' => 0.00,
                'status' => 'rascunho'
            ];

            // Adicionar chave_nfe se a coluna existir
            if (in_array('chave_nfe', $columnNames) && !empty($chaveNfe)) {
                $campos[] = 'chave_nfe';
                $valores[] = ':chave_nfe';
                $dados['chave_nfe'] = $chaveNfe;
            }

            // Adicionar xml_completo se a coluna existir (pode ser uma coluna TEXT ou LONGTEXT)
            if (in_array('xml_completo', $columnNames) && !empty($xmlCompleto)) {
                $campos[] = 'xml_completo';
                $valores[] = ':xml_completo';
                $dados['xml_completo'] = $xmlCompleto;
            }

            // Usar função auxiliar para garantir INSERT seguro
            try {
                error_log("🔍 ANTES construirInsertSeguro (cadastrarFornecedor):");
                error_log("   Campos: " . json_encode($campos));
                error_log("   Valores: " . json_encode($valores));
                error_log("   Dados: " . json_encode($dados));

                $insertData = $this->construirInsertSeguro($campos, $valores, $dados);
                $sql = "INSERT INTO compras (" . implode(', ', $insertData['campos']) . ") VALUES (" . implode(', ', $insertData['valores']) . ")";

                error_log("🔍 DEPOIS construirInsertSeguro (cadastrarFornecedor):");
                error_log("SQL gerado: " . $sql);
                error_log("Campos finais: " . json_encode($insertData['campos']));
                error_log("Valores finais: " . json_encode($insertData['valores']));
                error_log("Dados para binding: " . json_encode($insertData['dados']));

                // Verificar correspondência manual
                preg_match_all('/:(\w+)/', $sql, $matches);
                $placeholdersNaSql = $matches[1] ?? [];
                $chavesDados = array_keys($insertData['dados']);
                $diff1 = array_diff($placeholdersNaSql, $chavesDados);
                $diff2 = array_diff($chavesDados, $placeholdersNaSql);
                if (!empty($diff1)) {
                    error_log("⚠️ Placeholders na SQL sem dados: " . json_encode($diff1));
                }
                if (!empty($diff2)) {
                    error_log("⚠️ Dados sem placeholders na SQL: " . json_encode($diff2));
                }

                $stmt = $this->db->prepare($sql);
                $stmt->execute($insertData['dados']);
                $compraId = (int) $this->db->lastInsertId();
            } catch (\PDOException $e) {
                error_log("❌ ERRO PDO ao inserir compra: " . $e->getMessage());
                error_log("   SQL: " . ($sql ?? 'N/A'));
                error_log("   Dados: " . json_encode($insertData['dados'] ?? []));
                error_log("   Error Info: " . json_encode($e->errorInfo ?? []));

                // Debug adicional
                if (isset($sql) && isset($insertData)) {
                    preg_match_all('/:(\w+)/', $sql, $matches);
                    error_log("   Placeholders na SQL: " . json_encode($matches[1] ?? []));
                    error_log("   Chaves dos dados: " . json_encode(array_keys($insertData['dados'] ?? [])));
                }

                throw $e;
            }

            error_log("✅ Compra criada: ID {$compraId}, tem_xml: " . (!empty($xmlCompleto) ? 'sim' : 'não'));

            $this->success('Fornecedor cadastrado e compra criada com sucesso!', [
                'compra_id' => $compraId,
                'fornecedor_id' => $fornecedorId,
                'tem_xml' => !empty($xmlCompleto),
                'redirect_to_relacionamento' => !empty($xmlCompleto),
                'chave_nfe' => $chaveNfe
            ]);
        } catch (Exception $e) {
            error_log("Erro ao cadastrar fornecedor e criar compra: " . $e->getMessage());
            $this->error('Erro ao cadastrar fornecedor: ' . $e->getMessage());
        }
    }

    public function importarNFeManual(): void
    {
        $this->logNFeDetalhado("=== INÍCIO IMPORTAR NFE MANUAL ===", [
            'timestamp' => date('Y-m-d H:i:s'),
            'request_method' => $_SERVER['REQUEST_METHOD'] ?? 'N/A',
            'request_uri' => $_SERVER['REQUEST_URI'] ?? 'N/A',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'N/A',
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'N/A'
        ]);

        try {
            $chaveNfe = $this->request->post('chave_nfe');

            $this->logNFeDetalhado("Requisição recebida", [
                'chave_nfe_original' => $chaveNfe,
                'post_data' => $_POST ?? [],
                'request_data' => $this->request->all()
            ]);

            if (empty($chaveNfe)) {
                $this->logNFeDetalhado("ERRO: Chave da NF-e não informada");
                $this->error('Chave da NF-e não informada');
                return;
            }

            // Remover formatação (pontos, traços, espaços) da chave
            $chaveNfe = preg_replace('/[^0-9]/', '', $chaveNfe);

            $this->logNFeDetalhado("Chave NFe processada", [
                'chave_nfe_formatada' => $chaveNfe,
                'tamanho' => strlen($chaveNfe),
                'e_numero' => ctype_digit($chaveNfe)
            ]);

            // Validar formato da chave
            if (strlen($chaveNfe) !== 44 || !ctype_digit($chaveNfe)) {
                $this->logNFeDetalhado("ERRO: Chave de NF-e inválida", [
                    'chave' => $chaveNfe,
                    'tamanho' => strlen($chaveNfe),
                    'esperado' => 44
                ]);
                $this->error('Chave de NF-e inválida. Deve conter exatamente 44 números.');
                return;
            }

            $companyId = $this->getCompanyId();

            $this->logNFeDetalhado("Company ID obtido", [
                'company_id' => $companyId,
                'tipo' => gettype($companyId)
            ]);

            // Buscar empresa
            $empresa = null;
            try {
                $stmt = $this->db->prepare("SELECT * FROM empresas WHERE company_id = :company_id AND ativo = 'Sim' LIMIT 1");
                $stmt->execute(['company_id' => $companyId]);
                $empresa = $stmt->fetch();
            } catch (Exception $e) {
                error_log("Erro ao buscar em empresas: " . $e->getMessage());
            }

            if (!$empresa) {
                try {
                    $stmt = $this->db->prepare("SELECT * FROM companies WHERE id = :company_id AND is_active = 1 LIMIT 1");
                    $stmt->execute(['company_id' => $companyId]);
                    $empresa = $stmt->fetch();
                } catch (Exception $e) {
                    error_log("Erro ao buscar em companies: " . $e->getMessage());
                }
            }

            if (!$empresa) {
                $this->error('Empresa não encontrada ou inativa');
                return;
            }

            // Normalizar campos da empresa
            $empresaNormalizada = [
                'cnpj' => $empresa['cnpj'] ?? $empresa['document'] ?? '',
                'razao_social' => $empresa['razao_social'] ?? $empresa['name'] ?? '',
                'certificado_path' => $empresa['certificado_path'] ?? '',
                'senha_certificado' => $empresa['senha_certificado'] ?? '',
                'ambiente_nfe' => $empresa['ambiente_nfe'] ?? 'producao'
            ];

            // Verificar certificado
            if (empty($empresaNormalizada['certificado_path']) || empty($empresaNormalizada['senha_certificado'])) {
                $this->error('Certificado digital não configurado para esta empresa');
                return;
            }

            // Chamar serviço de integração NF-e para download específico
            require_once \ROOT_PATH . '/src/Services/NFeIntegrationService.php';

            $resultado = \App\Services\NFeIntegrationService::downloadNFeManual(
                $empresaNormalizada,
                $chaveNfe,
                $this->db
            );

            if ($resultado['sucesso']) {
                error_log("✅ Download bem-sucedido. Verificando XML completo...");
                error_log("xml_completo presente: " . (isset($resultado['xml_completo']) ? 'sim' : 'não'));

                // Se o XML foi baixado, processar para criar a compra
                if (!empty($resultado['xml_completo'])) {
                    error_log("✅ XML completo encontrado, iniciando processamento...");
                    error_log("Tamanho do XML: " . strlen($resultado['xml_completo']) . " bytes");
                    error_log("Primeiros 500 caracteres: " . substr($resultado['xml_completo'], 0, 500));

                    try {
                        // Sempre extrair e salvar dados do fornecedor, mesmo se for apenas resumo
                        $dadosEmissor = \App\Services\NFeIntegrationService::extrairDadosEmissor($resultado['xml_completo']);
                        if (!empty($dadosEmissor['cnpj']) || !empty($dadosEmissor['razao_social'])) {
                            // Atualizar dados do fornecedor no banco
                            try {
                                $stmtUpdate = $this->db->prepare("
                                    UPDATE nfe_recebidas
                                    SET cnpj_fornecedor = COALESCE(:cnpj, cnpj_fornecedor),
                                        razao_social_fornecedor = COALESCE(:razao, razao_social_fornecedor),
                                        updated_at = NOW()
                                    WHERE chave_nfe = :chave_nfe AND company_id = :company_id
                                ");
                                $stmtUpdate->execute([
                                    'cnpj' => $dadosEmissor['cnpj'] ?: null,
                                    'razao' => $dadosEmissor['razao_social'] ?: null,
                                    'chave_nfe' => $chaveNfe,
                                    'company_id' => $companyId
                                ]);
                                error_log("✅ Dados do fornecedor atualizados: {$dadosEmissor['razao_social']} - {$dadosEmissor['cnpj']}");
                            } catch (Exception $e) {
                                error_log("Erro ao atualizar dados do fornecedor: " . $e->getMessage());
                            }
                        }

                        // Verificar se é resumo ou completo - resNFe não é aceito, apenas procNFe
                        if (
                            strpos($resultado['xml_completo'], '<resNFe') !== false &&
                            strpos($resultado['xml_completo'], '<procNFe') === false &&
                            strpos($resultado['xml_completo'], '<NFe') === false
                        ) {

                            error_log("❌ XML é apenas resumo (resNFe). O XML completo (procNFe) não está disponível na SEFAZ.");
                            error_log("ℹ️ Isso pode acontecer quando a NF-e foi autorizada há muito tempo ou quando o XML completo ainda não foi disponibilizado no DistDFe.");
                            error_log("ℹ️ Soluções: 1) Aguardar e tentar novamente mais tarde, 2) Solicitar o XML completo (procNFe) diretamente ao fornecedor.");

                            $this->error('Apenas resumo (resNFe) foi retornado pela SEFAZ. O XML completo (procNFe) não está disponível no momento. Isso pode acontecer quando a NF-e foi autorizada há muito tempo. Soluções: 1) Aguardar e tentar novamente mais tarde, 2) Solicitar o XML completo (procNFe) diretamente ao fornecedor.');
                            return;
                        }

                        // Garantir que temos procNFe ou NFe (não apenas resNFe)
                        if (
                            strpos($resultado['xml_completo'], '<procNFe') === false &&
                            strpos($resultado['xml_completo'], '<NFe') === false
                        ) {
                            error_log("❌ XML não contém procNFe ou NFe");
                            $this->error('O XML recebido não contém o formato completo (procNFe). O sistema precisa do XML completo para criar a compra.');
                            return;
                        }

                        // Processar XML para extrair CNPJ do emitente
                        libxml_use_internal_errors(true);
                        $xml = simplexml_load_string($resultado['xml_completo']);

                        if ($xml === false) {
                            $errors = libxml_get_errors();
                            $errorMsg = 'Erro ao processar XML baixado: ';
                            foreach ($errors as $error) {
                                $errorMsg .= trim($error->message) . ' ';
                            }
                            libxml_clear_errors();
                            throw new Exception($errorMsg);
                        }

                        error_log("✅ XML carregado com sucesso");

                        // Extrair CNPJ do emitente
                        $cnpjEmitente = null;
                        $nomeEmitente = null;

                        // Tentar diferentes caminhos do XML (procNFe ou NFe)
                        if (isset($xml->NFe->infNFe->emit)) {
                            $emit = $xml->NFe->infNFe->emit;
                        } elseif (isset($xml->infNFe->emit)) {
                            $emit = $xml->infNFe->emit;
                        } else {
                            throw new Exception('Não foi possível encontrar tag <emit> no XML');
                        }

                        if (isset($emit->CNPJ)) {
                            $cnpjEmitente = (string) $emit->CNPJ;
                        } elseif (isset($emit->CPF)) {
                            $cnpjEmitente = (string) $emit->CPF;
                        } else {
                            throw new Exception('Não foi possível encontrar CNPJ/CPF do emitente no XML');
                        }

                        if (isset($emit->xNome)) {
                            $nomeEmitente = (string) $emit->xNome;
                        }

                        // Remover formatação do CNPJ
                        $cnpjEmitente = preg_replace('/[^0-9]/', '', $cnpjEmitente);

                        error_log("CNPJ do emitente extraído: {$cnpjEmitente}");
                        error_log("Nome do emitente: {$nomeEmitente}");

                        $this->logNFeDetalhado("Extraindo dados do emitente do XML", [
                            'cnpj_emitente' => $cnpjEmitente,
                            'nome_emitente' => $nomeEmitente
                        ]);

                        // Verificar se fornecedor existe - comparar apenas CNPJ (sem formatação)
                        $fornecedorId = null;
                        // Normalizar CNPJ para comparação (remover formatação)
                        $cnpjNormalizado = preg_replace('/[^0-9]/', '', $cnpjEmitente);

                        $this->logNFeDetalhado("Buscando fornecedor por CNPJ", [
                            'cnpj_normalizado' => $cnpjNormalizado,
                            'company_id' => $companyId
                        ]);

                        // Verificar se existe fornecedor com este CNPJ (verificar múltiplas possibilidades)
                        // IMPORTANTE: Usar placeholders diferentes pois :cnpj aparece duas vezes na query
                        $sqlFornecedor = "
                            SELECT id, name, document
                            FROM pessoas
                            WHERE company_id = :company_id
                            AND (REPLACE(REPLACE(REPLACE(REPLACE(document, '.', ''), '/', ''), '-', ''), ' ', '') = :cnpj1
                                 OR document = :cnpj2)
                            LIMIT 1
                        ";
                        $paramsFornecedor = [
                            'cnpj1' => $cnpjNormalizado,
                            'cnpj2' => $cnpjNormalizado,
                            'company_id' => $companyId
                        ];

                        $this->logNFeDetalhado("ANTES de preparar query de busca de fornecedor", [
                            'sql' => $sqlFornecedor,
                            'parametros' => $paramsFornecedor,
                            'total_parametros' => count($paramsFornecedor),
                            'placeholders_no_sql' => preg_match_all('/:(\w+)/', $sqlFornecedor, $m) ? $m[1] : []
                        ]);

                        try {
                            $stmt = $this->db->prepare($sqlFornecedor);

                            $this->logNFeDetalhado("Query preparada, executando...", [
                                'parametros_keys' => array_keys($paramsFornecedor),
                                'parametros_values' => $paramsFornecedor
                            ]);

                            $stmt->execute($paramsFornecedor);

                            $this->logNFeDetalhado("Query de busca de fornecedor executada com sucesso");

                            $fornecedor = $stmt->fetch();
                        } catch (\PDOException $e) {
                            preg_match_all('/:(\w+)/', $sqlFornecedor, $matches);
                            $placeholders = $matches[1] ?? [];

                            $this->logNFeDetalhado("❌ ERRO PDO ao buscar fornecedor", [
                                'mensagem' => $e->getMessage(),
                                'codigo' => $e->getCode(),
                                'error_info' => $e->errorInfo ?? [],
                                'sql' => $sqlFornecedor,
                                'placeholders_na_query' => $placeholders,
                                'parametros_fornecidos' => array_keys($paramsFornecedor),
                                'total_placeholders' => count($placeholders),
                                'total_parametros' => count($paramsFornecedor),
                                'diff_placeholders' => array_diff($placeholders, array_keys($paramsFornecedor)),
                                'diff_parametros' => array_diff(array_keys($paramsFornecedor), $placeholders),
                                'stack_trace' => $e->getTraceAsString()
                            ]);

                            throw $e;
                        }

                        $this->logNFeDetalhado("Resultado da busca do fornecedor", [
                            'fornecedor_encontrado' => !empty($fornecedor),
                            'fornecedor_data' => $fornecedor
                        ]);

                        if ($fornecedor) {
                            // Fornecedor existe - criar compra apenas setando o fornecedor
                            $fornecedorId = (int) $fornecedor['id'];

                            $this->logNFeDetalhado("Fornecedor encontrado - Iniciando criação de compra", [
                                'fornecedor_id' => $fornecedorId,
                                'fornecedor_nome' => $fornecedor['name'],
                                'fornecedor_documento' => $fornecedor['document'] ?? 'N/A'
                            ]);

                            // Verificar estrutura da tabela compras
                            $stmtCheck = $this->db->query("SHOW COLUMNS FROM compras");
                            $columns = $stmtCheck->fetchAll();
                            $columnNames = array_column($columns, 'Field');

                            $this->logNFeDetalhado("Estrutura da tabela compras", [
                                'colunas' => $columnNames,
                                'total_colunas' => count($columnNames),
                                'tem_chave_nfe' => in_array('chave_nfe', $columnNames),
                                'tem_xml_completo' => in_array('xml_completo', $columnNames)
                            ]);

                            // Criar compra vazia apenas com o fornecedor
                            $numeroCompra = 'NFe ' . (!empty($chaveNfe) ? substr($chaveNfe, 0, 8) : date('YmdHis'));
                            $campos = ['company_id', 'fornecedor_id', 'numero', 'data_compra', 'total', 'status', 'created_at', 'updated_at'];
                            $valores = [':company_id', ':fornecedor_id', ':numero', 'CURDATE()', ':total', ':status', 'NOW()', 'NOW()'];
                            $dados = [
                                'company_id' => $companyId,
                                'fornecedor_id' => $fornecedorId,
                                'numero' => $numeroCompra,
                                'total' => 0.00,
                                'status' => 'rascunho'
                            ];

                            $this->logNFeDetalhado("Preparando dados iniciais para INSERT", [
                                'numero_compra' => $numeroCompra,
                                'campos_iniciais' => $campos,
                                'valores_iniciais' => $valores,
                                'dados_iniciais' => $dados,
                                'tamanho_campos' => count($campos),
                                'tamanho_valores' => count($valores),
                                'tamanho_dados' => count($dados)
                            ]);

                            // Adicionar chave_nfe se a coluna existir
                            if (in_array('chave_nfe', $columnNames) && !empty($chaveNfe)) {
                                $campos[] = 'chave_nfe';
                                $valores[] = ':chave_nfe';
                                $dados['chave_nfe'] = $chaveNfe;
                                $this->logNFeDetalhado("Adicionado campo chave_nfe", [
                                    'chave_nfe' => $chaveNfe,
                                    'tamanho_chave' => strlen($chaveNfe)
                                ]);
                            }

                            // Adicionar xml_completo se a coluna existir
                            if (in_array('xml_completo', $columnNames) && !empty($resultado['xml_completo'])) {
                                $campos[] = 'xml_completo';
                                $valores[] = ':xml_completo';
                                $dados['xml_completo'] = $resultado['xml_completo'];
                                $xmlTamanho = strlen($resultado['xml_completo']);
                                $this->logNFeDetalhado("Adicionado campo xml_completo", [
                                    'tamanho_xml' => $xmlTamanho,
                                    'primeiros_100_chars' => substr($resultado['xml_completo'], 0, 100)
                                ]);
                            }

                            $this->logNFeDetalhado("Dados finais antes de construirInsertSeguro", [
                                'campos_finais' => $campos,
                                'valores_finais' => $valores,
                                'dados_finais' => array_map(function ($v) {
                                    if (is_string($v) && strlen($v) > 1000) {
                                        return '[STRING LONGA: ' . strlen($v) . ' caracteres]';
                                    }
                                    return $v;
                                }, $dados),
                                'total_campos' => count($campos),
                                'total_valores' => count($valores),
                                'total_dados' => count($dados),
                                'arrays_alinhados' => count($campos) === count($valores)
                            ]);

                            // Usar função auxiliar para garantir INSERT seguro
                            try {
                                $this->logNFeDetalhado("CHAMANDO construirInsertSeguro", [
                                    'campos' => $campos,
                                    'valores' => $valores,
                                    'dados_keys' => array_keys($dados),
                                    'dados_count' => count($dados)
                                ]);

                                $insertData = $this->construirInsertSeguro($campos, $valores, $dados);
                                $sql = "INSERT INTO compras (" . implode(', ', $insertData['campos']) . ") VALUES (" . implode(', ', $insertData['valores']) . ")";

                                preg_match_all('/:(\w+)/', $sql, $matches);
                                $placeholdersNaSql = $matches[1] ?? [];
                                $chavesDados = array_keys($insertData['dados']);

                                $this->logNFeDetalhado("APÓS construirInsertSeguro - ANTES DE EXECUTAR", [
                                    'sql_completo' => $sql,
                                    'campos_finais' => $insertData['campos'],
                                    'valores_finais' => $insertData['valores'],
                                    'dados_keys' => $chavesDados,
                                    'dados_valores' => array_map(function ($v) {
                                        if (is_string($v) && strlen($v) > 500) {
                                            return '[STRING: ' . strlen($v) . ' chars]';
                                        }
                                        return $v;
                                    }, $insertData['dados']),
                                    'placeholders_na_sql' => $placeholdersNaSql,
                                    'total_placeholders' => count($placeholdersNaSql),
                                    'total_dados' => count($insertData['dados']),
                                    'correspondencia_ok' => count($placeholdersNaSql) === count($insertData['dados']) && empty(array_diff($placeholdersNaSql, $chavesDados))
                                ]);

                                $diff1 = array_diff($placeholdersNaSql, $chavesDados);
                                $diff2 = array_diff($chavesDados, $placeholdersNaSql);
                                if (!empty($diff1)) {
                                    $this->logNFeDetalhado("⚠️ ERRO: Placeholders na SQL sem dados correspondentes", [
                                        'placeholders_sem_dados' => $diff1
                                    ]);
                                }
                                if (!empty($diff2)) {
                                    $this->logNFeDetalhado("⚠️ ERRO: Dados sem placeholders na SQL", [
                                        'dados_sem_placeholders' => $diff2
                                    ]);
                                }

                                $this->logNFeDetalhado("EXECUTANDO PREPARE E EXECUTE", [
                                    'sql_preparado' => $sql,
                                    'parametros_binding' => $insertData['dados']
                                ]);

                                $stmt = $this->db->prepare($sql);
                                $stmt->execute($insertData['dados']);
                                $compraId = (int) $this->db->lastInsertId();

                                $this->logNFeDetalhado("✅ COMPRA CRIADA COM SUCESSO", [
                                    'compra_id' => $compraId,
                                    'sql_executado' => $sql
                                ]);
                            } catch (\PDOException $e) {
                                preg_match_all('/:(\w+)/', $sql ?? '', $matches);

                                $this->logNFeDetalhado("❌ ERRO PDO CRÍTICO AO INSERIR COMPRA", [
                                    'mensagem_erro' => $e->getMessage(),
                                    'codigo_erro' => $e->getCode(),
                                    'sql_gerado' => $sql ?? 'N/A',
                                    'dados_tentados' => array_map(function ($v) {
                                        if (is_string($v) && strlen($v) > 500) {
                                            return '[STRING: ' . strlen($v) . ' chars]';
                                        }
                                        return $v;
                                    }, $insertData['dados'] ?? []),
                                    'error_info' => $e->errorInfo ?? [],
                                    'placeholders_na_sql' => $matches[1] ?? [],
                                    'chaves_dos_dados' => array_keys($insertData['dados'] ?? []),
                                    'stack_trace' => $e->getTraceAsString(),
                                    'file' => $e->getFile(),
                                    'line' => $e->getLine()
                                ]);

                                throw $e;
                            }

                            error_log("✅ Compra criada (fornecedor encontrado): ID {$compraId}, tem_xml: " . (!empty($resultado['xml_completo']) ? 'sim' : 'não'));

                            $this->success('Fornecedor encontrado! Compra criada com sucesso.', [
                                'nfe' => $resultado['nfe'] ?? null,
                                'compra_id' => $compraId,
                                'fornecedor_id' => $fornecedorId,
                                'fornecedor_nome' => $fornecedor['name'],
                                'redirect_to_relacionamento' => !empty($resultado['xml_completo']),
                                'chave_nfe' => $chaveNfe
                            ]);
                        } else {
                            // Fornecedor não existe - perguntar se deseja cadastrar
                            error_log("⚠️ Fornecedor não encontrado: CNPJ {$cnpjEmitente}");

                            // Extrair mais dados do emitente do XML para cadastro
                            $dadosEmitente = [
                                'cnpj' => $cnpjEmitente,
                                'nome' => $nomeEmitente,
                                'nome_fantasia' => isset($emit->xFant) ? (string) $emit->xFant : null,
                                'ie' => isset($emit->IE) ? (string) $emit->IE : null,
                                'endereco' => isset($emit->enderEmit->xLgr) ? (string) $emit->enderEmit->xLgr : null,
                                'numero' => isset($emit->enderEmit->nro) ? (string) $emit->enderEmit->nro : null,
                                'complemento' => isset($emit->enderEmit->xCpl) ? (string) $emit->enderEmit->xCpl : null,
                                'bairro' => isset($emit->enderEmit->xBairro) ? (string) $emit->enderEmit->xBairro : null,
                                'cidade' => isset($emit->enderEmit->xMun) ? (string) $emit->enderEmit->xMun : null,
                                'estado' => isset($emit->enderEmit->UF) ? (string) $emit->enderEmit->UF : null,
                                'cep' => isset($emit->enderEmit->CEP) ? (string) $emit->enderEmit->CEP : null,
                                'telefone' => isset($emit->enderEmit->fone) ? (string) $emit->enderEmit->fone : null,
                                'xml_completo' => $resultado['xml_completo'] ?? null
                            ];

                            $this->success('Fornecedor não encontrado', [
                                'nfe' => $resultado['nfe'] ?? null,
                                'fornecedor_nao_encontrado' => true,
                                'dados_emitente' => $dadosEmitente,
                                'mensagem' => "O fornecedor com CNPJ {$cnpjEmitente} não foi encontrado. Deseja cadastrá-lo?"
                            ]);
                        }
                    } catch (Exception $e) {
                        if ($this->db->inTransaction()) {
                            $this->db->rollBack();
                            $this->logNFeDetalhado("Transação revertida devido a erro");
                        }

                        $this->logNFeDetalhado("❌ ERRO CRÍTICO ao processar XML após download", [
                            'mensagem' => $e->getMessage(),
                            'codigo' => $e->getCode(),
                            'tipo_excecao' => get_class($e),
                            'arquivo' => $e->getFile(),
                            'linha' => $e->getLine(),
                            'stack_trace' => $e->getTraceAsString(),
                            'previous' => $e->getPrevious() ? [
                                'mensagem' => $e->getPrevious()->getMessage(),
                                'codigo' => $e->getPrevious()->getCode()
                            ] : null
                        ]);

                        $this->error('NF-e baixada, mas erro ao criar compra: ' . $e->getMessage());
                    }
                } else {
                    error_log("⚠️ XML completo não está presente no resultado");
                    $this->success('NF-e importada com sucesso!', [
                        'nfe' => $resultado['nfe']
                    ]);
                }
            } else {
                $this->error($resultado['erro'] ?? 'Erro ao importar NF-e');
            }

        } catch (Exception $e) {
            $this->logNFeDetalhado("❌ ERRO GERAL ao importar NF-e manual", [
                'mensagem' => $e->getMessage(),
                'codigo' => $e->getCode(),
                'tipo_excecao' => get_class($e),
                'arquivo' => $e->getFile(),
                'linha' => $e->getLine(),
                'chave_nfe_recebida' => $this->request->post('chave_nfe') ?? 'N/A',
                'company_id' => $this->getCompanyId() ?? 'N/A',
                'stack_trace_completo' => $e->getTraceAsString()
            ]);

            $this->error('Erro ao importar NF-e: ' . $e->getMessage(), ['exception' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
        } finally {
            $this->logNFeDetalhado("=== FIM IMPORTAR NFE MANUAL ===", [
                'tempo_execucao' => microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true))
            ]);
        }
    }

    /**
     * Download PDF (DANFE) da NF-e recebida
     */
    public function downloadNFePdf(): void
    {
        try {
            $chaveNfe = $this->request->get('chave');
            $companyId = $this->getCompanyId();

            if (empty($chaveNfe)) {
                http_response_code(400);
                echo "Chave da NF-e não informada";
                return;
            }

            // Buscar NF-e no banco
            $stmt = $this->db->prepare("
                SELECT xml_completo, chave_nfe
                FROM nfe_recebidas
                WHERE chave_nfe = :chave_nfe
                AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute([
                'chave_nfe' => $chaveNfe,
                'company_id' => $companyId
            ]);
            $nfe = $stmt->fetch();

            if (!$nfe || empty($nfe['xml_completo'])) {
                // Se não tem XML no banco, tentar baixar novamente
                error_log("XML não encontrado no banco para chave: {$chaveNfe}, tentando baixar...");

                // Buscar empresa
                $empresa = null;
                try {
                    $stmtEmpresa = $this->db->prepare("SELECT * FROM empresas WHERE company_id = :company_id AND ativo = 'Sim' LIMIT 1");
                    $stmtEmpresa->execute(['company_id' => $companyId]);
                    $empresa = $stmtEmpresa->fetch();
                } catch (Exception $e) {
                    error_log("Erro ao buscar em empresas: " . $e->getMessage());
                }

                if (!$empresa) {
                    try {
                        $stmtEmpresa = $this->db->prepare("SELECT * FROM companies WHERE id = :company_id AND is_active = 1 LIMIT 1");
                        $stmtEmpresa->execute(['company_id' => $companyId]);
                        $empresa = $stmtEmpresa->fetch();
                    } catch (Exception $e) {
                        error_log("Erro ao buscar em companies: " . $e->getMessage());
                    }
                }

                if ($empresa && !empty($empresa['certificado_path']) && !empty($empresa['senha_certificado'])) {
                    $empresaNormalizada = [
                        'cnpj' => $empresa['cnpj'] ?? $empresa['document'] ?? '',
                        'razao_social' => $empresa['razao_social'] ?? $empresa['name'] ?? '',
                        'certificado_path' => $empresa['certificado_path'] ?? '',
                        'senha_certificado' => $empresa['senha_certificado'] ?? '',
                        'ambiente_nfe' => $empresa['ambiente_nfe'] ?? 'producao'
                    ];

                    $resultado = \App\Services\NFeIntegrationService::downloadNFeManual(
                        $empresaNormalizada,
                        $chaveNfe,
                        $this->db
                    );

                    if ($resultado['sucesso'] && !empty($resultado['xml_completo'])) {
                        $xml = $resultado['xml_completo'];
                        error_log("✅ XML baixado com sucesso para download");
                    } else {
                        http_response_code(404);
                        echo "NF-e não encontrada ou XML não disponível";
                        return;
                    }
                } else {
                    http_response_code(404);
                    echo "NF-e não encontrada ou XML não disponível";
                    return;
                }
            } else {
                $xml = $nfe['xml_completo'];
            }

            // Verificar se o XML é procNFe ou NFe (não aceitar resNFe)
            if (
                strpos($xml, '<resNFe') !== false &&
                strpos($xml, '<procNFe') === false &&
                strpos($xml, '<NFe') === false
            ) {
                error_log("❌ XML é apenas resumo (resNFe). Tentando buscar procNFe via consulta...");

                // Buscar empresa para consulta
                $empresa = null;
                try {
                    $stmtEmpresa = $this->db->prepare("SELECT * FROM empresas WHERE company_id = :company_id AND ativo = 'Sim' LIMIT 1");
                    $stmtEmpresa->execute(['company_id' => $companyId]);
                    $empresa = $stmtEmpresa->fetch();
                } catch (Exception $e) {
                    error_log("Erro ao buscar em empresas: " . $e->getMessage());
                }

                if (!$empresa) {
                    try {
                        $stmtEmpresa = $this->db->prepare("SELECT * FROM companies WHERE id = :company_id AND is_active = 1 LIMIT 1");
                        $stmtEmpresa->execute(['company_id' => $companyId]);
                        $empresa = $stmtEmpresa->fetch();
                    } catch (Exception $e) {
                        error_log("Erro ao buscar em companies: " . $e->getMessage());
                    }
                }

                if ($empresa && !empty($empresa['certificado_path']) && !empty($empresa['senha_certificado'])) {
                    $empresaNormalizada = [
                        'cnpj' => $empresa['cnpj'] ?? $empresa['document'] ?? '',
                        'razao_social' => $empresa['razao_social'] ?? $empresa['name'] ?? '',
                        'certificado_path' => $empresa['certificado_path'] ?? '',
                        'senha_certificado' => $empresa['senha_certificado'] ?? '',
                        'ambiente_nfe' => $empresa['ambiente_nfe'] ?? 'producao'
                    ];

                    $resultadoConsulta = \App\Services\NFeIntegrationService::buscarXmlCompletoPorConsulta(
                        $empresaNormalizada,
                        $chaveNfe,
                        $this->db
                    );

                    if ($resultadoConsulta['sucesso'] && !empty($resultadoConsulta['xml_completo'])) {
                        $xml = $resultadoConsulta['xml_completo'];
                        error_log("✅ XML completo (procNFe) obtido via consulta para PDF");
                    } else {
                        http_response_code(400);
                        echo "O XML disponível é apenas resumo (resNFe). É necessário o XML completo (procNFe) para gerar o PDF. Não foi possível obter o XML completo da SEFAZ.";
                        return;
                    }
                } else {
                    http_response_code(400);
                    echo "O XML disponível é apenas resumo (resNFe). É necessário o XML completo (procNFe) para gerar o PDF. Certificado digital não configurado.";
                    return;
                }
            }

            // Verificar se realmente é procNFe ou NFe antes de gerar PDF
            if (strpos($xml, '<procNFe') === false && strpos($xml, '<NFe') === false) {
                http_response_code(400);
                echo "O XML não está no formato correto (procNFe ou NFe). Não é possível gerar o PDF.";
                error_log("❌ XML não é procNFe ou NFe. Primeiros 200 caracteres: " . substr($xml, 0, 200));
                return;
            }

            // Gerar DANFE usando NFePHP
            // Tentar carregar autoload do módulo NFe primeiro (tem NFePHP)
            $nfeAutoload = \ROOT_PATH . '/src/Integrations/NFe/vendor/autoload.php';
            if (file_exists($nfeAutoload)) {
                require_once $nfeAutoload;
            } else {
                // Fallback: tentar autoload da raiz
                require_once \ROOT_PATH . '/vendor/autoload.php';
            }

            // Verificar se a classe existe
            if (!class_exists('\NFePHP\DA\NFe\Danfe')) {
                http_response_code(500);
                echo "Biblioteca NFePHP não encontrada. Verifique se o módulo NF-e está instalado corretamente.";
                error_log("Erro: Classe NFePHP\\DA\\NFe\\Danfe não encontrada");
                return;
            }

            error_log("Gerando PDF com XML de " . strlen($xml) . " bytes. Contém procNFe: " . (strpos($xml, '<procNFe') !== false ? 'sim' : 'não') . ", contém NFe: " . (strpos($xml, '<NFe') !== false ? 'sim' : 'não'));

            $danfe = new \NFePHP\DA\NFe\Danfe($xml);
            $danfe->debugMode(false);
            $danfe->creditsIntegratorFooter('Systhema ERP');

            $pdf = $danfe->render();

            // Headers para download
            header('Content-Type: application/pdf');
            header('Content-Disposition: attachment; filename="NFe_' . $chaveNfe . '.pdf"');
            header('Cache-Control: private, max-age=0, must-revalidate');
            header('Pragma: public');

            echo $pdf;
            exit;

        } catch (Exception $e) {
            error_log("Erro ao gerar PDF da NF-e: " . $e->getMessage());
            http_response_code(500);
            echo "Erro ao gerar PDF: " . $e->getMessage();
        }
    }

    /**
     * Download XML da NF-e recebida
     */
    public function downloadNFeXml(): void
    {
        try {
            $chaveNfe = $this->request->get('chave');
            $companyId = $this->getCompanyId();

            if (empty($chaveNfe)) {
                http_response_code(400);
                echo "Chave da NF-e não informada";
                return;
            }

            // Buscar NF-e no banco
            $stmt = $this->db->prepare("
                SELECT xml_completo, chave_nfe
                FROM nfe_recebidas
                WHERE chave_nfe = :chave_nfe
                AND company_id = :company_id
                LIMIT 1
            ");
            $stmt->execute([
                'chave_nfe' => $chaveNfe,
                'company_id' => $companyId
            ]);
            $nfe = $stmt->fetch();

            if (!$nfe || empty($nfe['xml_completo'])) {
                // Se não tem XML no banco, tentar baixar novamente
                error_log("XML não encontrado no banco para chave: {$chaveNfe}, tentando baixar...");

                // Buscar empresa
                $empresa = null;
                try {
                    $stmtEmpresa = $this->db->prepare("SELECT * FROM empresas WHERE company_id = :company_id AND ativo = 'Sim' LIMIT 1");
                    $stmtEmpresa->execute(['company_id' => $companyId]);
                    $empresa = $stmtEmpresa->fetch();
                } catch (Exception $e) {
                    error_log("Erro ao buscar em empresas: " . $e->getMessage());
                }

                if (!$empresa) {
                    try {
                        $stmtEmpresa = $this->db->prepare("SELECT * FROM companies WHERE id = :company_id AND is_active = 1 LIMIT 1");
                        $stmtEmpresa->execute(['company_id' => $companyId]);
                        $empresa = $stmtEmpresa->fetch();
                    } catch (Exception $e) {
                        error_log("Erro ao buscar em companies: " . $e->getMessage());
                    }
                }

                if ($empresa && !empty($empresa['certificado_path']) && !empty($empresa['senha_certificado'])) {
                    $empresaNormalizada = [
                        'cnpj' => $empresa['cnpj'] ?? $empresa['document'] ?? '',
                        'razao_social' => $empresa['razao_social'] ?? $empresa['name'] ?? '',
                        'certificado_path' => $empresa['certificado_path'] ?? '',
                        'senha_certificado' => $empresa['senha_certificado'] ?? '',
                        'ambiente_nfe' => $empresa['ambiente_nfe'] ?? 'producao'
                    ];

                    $resultado = \App\Services\NFeIntegrationService::downloadNFeManual(
                        $empresaNormalizada,
                        $chaveNfe,
                        $this->db
                    );

                    if ($resultado['sucesso'] && !empty($resultado['xml_completo'])) {
                        $xml = $resultado['xml_completo'];
                        error_log("✅ XML baixado com sucesso para download");
                    } else {
                        http_response_code(404);
                        echo "NF-e não encontrada ou XML não disponível";
                        return;
                    }
                } else {
                    http_response_code(404);
                    echo "NF-e não encontrada ou XML não disponível";
                    return;
                }
            } else {
                $xml = $nfe['xml_completo'];
            }

            // Headers para download
            header('Content-Type: application/xml; charset=utf-8');
            header('Content-Disposition: attachment; filename="NFe_' . $chaveNfe . '.xml"');
            header('Cache-Control: private, max-age=0, must-revalidate');
            header('Pragma: public');

            echo $xml;
            exit;

        } catch (Exception $e) {
            error_log("Erro ao baixar XML da NF-e: " . $e->getMessage());
            http_response_code(500);
            echo "Erro ao baixar XML: " . $e->getMessage();
        }
    }

    /**
     * Gera contas a pagar baseado na compra
     */
    private function gerarContasPagar(int $compraId, array $data): void
    {
        try {
            $companyId = $this->getCompanyId();
            $userId = $this->session->get('user_id');

            $total = (float) ($data['total'] ?? 0);
            $fornecedorId = $data['fornecedor_id'] ?? null;
            $paymentMethodId = $this->request->post('payment_method_id');
            $installments = (int) ($this->request->post('installments') ?? 1);
            $dataCompra = $data['data_compra'];

            // Calcular parcelas
            $valorParcela = floor(($total / $installments) * 100) / 100;
            $valorUltimaParcela = $total - ($valorParcela * ($installments - 1));

            for ($i = 1; $i <= $installments; $i++) {
                $valor = ($i == $installments) ? $valorUltimaParcela : $valorParcela;

                // Calcular vencimento (30 dias por parcela)
                $vencimento = date('Y-m-d', strtotime($dataCompra . " + " . ($i * 30) . " days"));

                $descricao = "Compra #{$data['numero']} - Parcela {$i}/{$installments}";

                // Buscar nome do método de pagamento
                $nomeMetodo = '';
                if ($paymentMethodId) {
                    $stmtMetodo = $this->db->prepare("SELECT name FROM metodos_pagamento WHERE id = :id");
                    $stmtMetodo->execute(['id' => $paymentMethodId]);
                    $metodo = $stmtMetodo->fetch();
                    $nomeMetodo = $metodo['name'] ?? '';
                }

                $stmt = $this->db->prepare("
                    INSERT INTO contas_pagar (
                        company_id, pessoa_id, supplier_id, plano_conta_id, compra_id,
                        numero, description, amount, amount_paid, amount_remaining,
                        due_date, status, metodo_pagamento_id, conta_bancaria_id,
                        payment_method, notes, created_by, created_at, updated_at
                    ) VALUES (
                        :company_id, :pessoa_id, :supplier_id, :plano_conta_id, :compra_id,
                        :numero, :description, :amount, :amount_paid, :amount_remaining,
                        :due_date, :status, :metodo_pagamento_id, :conta_bancaria_id,
                        :payment_method, :notes, :created_by, NOW(), NOW()
                    )
                ");

                $stmt->execute([
                    'company_id' => $companyId,
                    'pessoa_id' => $fornecedorId,
                    'supplier_id' => $fornecedorId,
                    'plano_conta_id' => null,
                    'compra_id' => $compraId,
                    'numero' => "CP-{$compraId}-{$i}",
                    'description' => $descricao,
                    'amount' => $valor,
                    'amount_paid' => 0.00,
                    'amount_remaining' => $valor,
                    'due_date' => $vencimento,
                    'status' => 'pendente',
                    'metodo_pagamento_id' => $paymentMethodId,
                    'conta_bancaria_id' => null,
                    'payment_method' => $nomeMetodo,
                    'notes' => "Gerado automaticamente da compra #{$data['numero']}",
                    'created_by' => $userId
                ]);
            }

        } catch (Exception $e) {
            error_log("Compra #{$compraId}: ❌ Erro ao gerar contas a pagar: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Movimenta estoque de compra (entrada positiva)
     */
    private function movimentarEstoqueCompra(int $compraId, array $itens): void
    {
        try {
            $companyId = $this->getCompanyId();
            $userId = $this->session->get('user_id');

            error_log("Compra #{$compraId}: Iniciando movimentação de estoque");

            foreach ($itens as $item) {
                $itemId = $item['item_id'] ?? null;
                $quantity = (float) ($item['quantity'] ?? 0);

                if (empty($itemId) || $quantity <= 0) {
                    continue;
                }

                // Verificar se estoque_movimentos existe
                $stmt = $this->db->query("SHOW TABLES LIKE 'estoque_movimentos'");
                if ($stmt->rowCount() == 0) {
                    error_log("Compra #{$compraId}: Tabela estoque_movimentos não existe - pulando");
                    continue;
                }

                // Movimentar estoque REAL (entrada)
                // Tentar primeiro com item_id (mais comum)
                try {
                    // Verificar se created_by existe na tabela
                    $stmtCols = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'created_by'");
                    $temCreatedBy = $stmtCols->rowCount() > 0;

                    if ($temCreatedBy) {
                        $stmt = $this->db->prepare("
                            INSERT INTO estoque_movimentos (
                                company_id, item_id, type, quantity,
                                reference_type, reference_id, created_by, created_at
                            ) VALUES (
                                :company_id, :item_id, 'entrada', :quantity,
                                'compra', :reference_id, :created_by, NOW()
                            )
                        ");
                        $stmt->execute([
                            'company_id' => $companyId,
                            'item_id' => $itemId,
                            'quantity' => $quantity,
                            'reference_id' => $compraId,
                            'created_by' => $userId
                        ]);
                    } else {
                        $stmt = $this->db->prepare("
                            INSERT INTO estoque_movimentos (
                                company_id, item_id, type, quantity,
                                reference_type, reference_id, created_at
                            ) VALUES (
                                :company_id, :item_id, 'entrada', :quantity,
                                'compra', :reference_id, NOW()
                            )
                        ");
                        $stmt->execute([
                            'company_id' => $companyId,
                            'item_id' => $itemId,
                            'quantity' => $quantity,
                            'reference_id' => $compraId
                        ]);
                    }
                } catch (\Exception $e) {
                    // Se falhar, tentar com product_id
                    try {
                        $stmtCols = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'created_by'");
                        $temCreatedBy = $stmtCols->rowCount() > 0;

                        if ($temCreatedBy) {
                            $stmt = $this->db->prepare("
                                INSERT INTO estoque_movimentos (
                                    company_id, product_id, type, quantity,
                                    reference_type, reference_id, created_by, created_at
                                ) VALUES (
                                    :company_id, :product_id, 'entrada', :quantity,
                                    'compra', :reference_id, :created_by, NOW()
                                )
                            ");
                            $stmt->execute([
                                'company_id' => $companyId,
                                'product_id' => $itemId,
                                'quantity' => $quantity,
                                'reference_id' => $compraId,
                                'created_by' => $userId
                            ]);
                        } else {
                            $stmt = $this->db->prepare("
                                INSERT INTO estoque_movimentos (
                                    company_id, product_id, type, quantity,
                                    reference_type, reference_id, created_at
                                ) VALUES (
                                    :company_id, :product_id, 'entrada', :quantity,
                                    'compra', :reference_id, NOW()
                                )
                            ");
                            $stmt->execute([
                                'company_id' => $companyId,
                                'product_id' => $itemId,
                                'quantity' => $quantity,
                                'reference_id' => $compraId
                            ]);
                        }
                    } catch (\Exception $e2) {
                        error_log("Compra #{$compraId}: Erro ao inserir movimentação de estoque: " . $e2->getMessage());
                        // Não quebra o processo, apenas loga o erro
                    }
                }

                // Atualizar estoque do produto
                $stmtUpdate = $this->db->prepare("
                    UPDATE produtos SET stock_quantity = stock_quantity + :quantity
                    WHERE id = :id AND company_id = :company_id
                ");
                $stmtUpdate->execute([
                    'quantity' => $quantity,
                    'id' => $itemId,
                    'company_id' => $companyId
                ]);

                error_log("Compra #{$compraId}: Item {$itemId} - Estoque atualizado: +{$quantity}");
            }

            error_log("Compra #{$compraId}: ✅ Estoque movimentado com sucesso");

        } catch (Exception $e) {
            error_log("Compra #{$compraId}: ❌ Erro ao movimentar estoque: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Salva centros de custos da compra
     */
    private function salvarCentrosCustos(int $compraId, int $companyId, string $documentoNumero, string $dataMovimentacao): void
    {
        try {
            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'compras_centro_custos'");
            if ($stmt->rowCount() === 0) {
                // Criar tabela se não existir
                $this->db->exec("
                    CREATE TABLE IF NOT EXISTS `compras_centro_custos` (
                        `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                        `compra_id` INT UNSIGNED NOT NULL,
                        `centro_id` INT UNSIGNED NOT NULL,
                        `valor` DECIMAL(15,2) NOT NULL DEFAULT 0.00,
                        `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
                        INDEX `idx_compra` (`compra_id`),
                        INDEX `idx_centro` (`centro_id`),
                        FOREIGN KEY (`compra_id`) REFERENCES `compras`(`id`) ON DELETE CASCADE,
                        FOREIGN KEY (`centro_id`) REFERENCES `centro_custos`(`id`) ON DELETE CASCADE
                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                ");
            }

            // Deletar centros de custos antigos
            $stmt = $this->db->prepare("DELETE FROM compras_centro_custos WHERE compra_id = :compra_id");
            $stmt->execute(['compra_id' => $compraId]);

            // Deletar movimentações antigas desta compra
            $stmt = $this->db->query("SHOW TABLES LIKE 'movimentacao_centro_custos'");
            if ($stmt->rowCount() > 0) {
                $stmt = $this->db->prepare("DELETE FROM movimentacao_centro_custos WHERE documento_tipo = 'compra' AND documento_id = :compra_id");
                $stmt->execute(['compra_id' => $compraId]);
            }

            // Salvar novos centros de custos
            $centrosCustos = $this->request->post('centro_custos');

            if (is_array($centrosCustos) && count($centrosCustos) > 0) {
                // Preparar statement para inserir em compras_centro_custos
                $stmtInsert = $this->db->prepare("
                    INSERT INTO compras_centro_custos (compra_id, centro_id, valor)
                    VALUES (:compra_id, :centro_id, :valor)
                ");

                // Usar os parâmetros passados ao invés de buscar novamente
                $numeroCompra = $documentoNumero;
                $dataCompra = $dataMovimentacao;

                // Verificar se a tabela de movimentação existe e criar se necessário
                $stmtCheck = $this->db->query("SHOW TABLES LIKE 'movimentacao_centro_custos'");
                $tabelaMovimentacaoExiste = $stmtCheck->rowCount() > 0;

                if (!$tabelaMovimentacaoExiste) {
                    $this->criarTabelaMovimentacaoCentroCustos();
                }

                $userId = $this->session->get('user_id');

                foreach ($centrosCustos as $cc) {
                    $centroId = (int) ($cc['centro_id'] ?? 0);
                    $valor = (float) ($cc['valor'] ?? 0);

                    if ($centroId > 0 && $valor > 0) {
                        // Salvar na tabela compras_centro_custos
                        $stmtInsert->execute([
                            'compra_id' => $compraId,
                            'centro_id' => $centroId,
                            'valor' => $valor
                        ]);

                        // Registrar na tabela de movimentação (se a tabela existir)
                        if ($tabelaMovimentacaoExiste) {
                            $stmtMov = $this->db->prepare("
                                INSERT INTO movimentacao_centro_custos (
                                    company_id, centro_id, tipo_movimentacao, tipo_operacao,
                                    valor, documento_tipo, documento_id, documento_numero,
                                    descricao, data_movimentacao, created_by
                                ) VALUES (
                                    :company_id, :centro_id, 'financeira', 'saida',
                                    :valor, 'compra', :documento_id, :documento_numero,
                                    :descricao, :data_movimentacao, :created_by
                                )
                            ");
                            $stmtMov->execute([
                                'company_id' => $companyId,
                                'centro_id' => $centroId,
                                'valor' => $valor,
                                'documento_id' => $compraId,
                                'documento_numero' => $numeroCompra,
                                'descricao' => 'Compra ' . $numeroCompra . ' - Distribuição por centro de custos',
                                'data_movimentacao' => $dataCompra,
                                'created_by' => $userId
                            ]);
                        }
                    }
                }
            }
        } catch (Exception $e) {
            error_log("Erro ao salvar centros de custos da compra #{$compraId}: " . $e->getMessage());
            // Não lançar exceção para não quebrar o fluxo principal
        }
    }

    /**
     * Busca parâmetro do sistema
     */
    private function getParametro(string $chave, int $companyId): bool
    {
        try {
            // Verificar se a tabela parametros existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'parametros'");
            if ($stmt->rowCount() === 0) {
                return false;
            }

            // Verificar se a coluna 'ativo' existe
            $stmt = $this->db->query("SHOW COLUMNS FROM parametros LIKE 'ativo'");
            $temAtivo = $stmt->rowCount() > 0;

            // Construir query dinamicamente
            $whereAtivo = $temAtivo ? 'AND ativo = 1' : '';

            // Tentar buscar com empresa_id
            $stmt = $this->db->prepare("
                SELECT valor FROM parametros
                WHERE chave = :chave AND empresa_id = :empresa_id {$whereAtivo}
                LIMIT 1
            ");
            $stmt->execute(['chave' => $chave, 'empresa_id' => $companyId]);
            $result = $stmt->fetch();

            if ($result && $result['valor'] == '1') {
                return true;
            }

            // Tentar buscar sem empresa_id (parâmetro global)
            $stmt = $this->db->prepare("
                SELECT valor FROM parametros
                WHERE chave = :chave AND (empresa_id IS NULL OR empresa_id = 0) {$whereAtivo}
                LIMIT 1
            ");
            $stmt->execute(['chave' => $chave]);
            $result = $stmt->fetch();

            return ($result && $result['valor'] == '1');
        } catch (Exception $e) {
            error_log("Erro ao buscar parâmetro {$chave}: " . $e->getMessage());
            return false;
        }
    }

    /**
     * Busca plano de contas
     */
    private function getPlanoContas(int $companyId): array
    {
        try {
            // Verificar se a tabela existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'plano_contas'");
            if ($stmt->rowCount() === 0) {
                return [];
            }

            // Detectar estrutura da tabela
            $stmtColumns = $this->db->query("SHOW COLUMNS FROM plano_contas");
            $columns = $stmtColumns->fetchAll();
            $columnNames = array_column($columns, 'Field');

            // Detectar nome das colunas
            $colCodigo = in_array('codigo', $columnNames) ? 'codigo' : (in_array('code', $columnNames) ? 'code' : 'id');
            $colNome = in_array('nome', $columnNames) ? 'nome' : (in_array('name', $columnNames) ? 'name' : 'id');
            $colAtivo = in_array('ativo', $columnNames) ? 'ativo' : (in_array('is_active', $columnNames) ? 'is_active' : null);

            // Montar WHERE
            $where = "company_id = :company_id";
            if ($colAtivo) {
                $where .= " AND {$colAtivo} = 1";
            }

            $sql = "SELECT id, {$colCodigo} as codigo, {$colNome} as nome FROM plano_contas WHERE {$where} ORDER BY {$colCodigo} ASC";

            $stmt = $this->db->prepare($sql);
            $stmt->execute(['company_id' => $companyId]);
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar plano de contas: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Cria a tabela de movimentação por centro de custos
     */
    private function criarTabelaMovimentacaoCentroCustos(): void
    {
        try {
            $this->db->exec("
                CREATE TABLE IF NOT EXISTS `movimentacao_centro_custos` (
                    `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    `company_id` INT UNSIGNED NOT NULL,
                    `centro_id` INT UNSIGNED NOT NULL COMMENT 'ID do centro de custo',
                    `tipo_movimentacao` ENUM('financeira', 'estoque', 'outra') NOT NULL DEFAULT 'financeira' COMMENT 'Tipo de movimentação',
                    `tipo_operacao` ENUM('entrada', 'saida') NOT NULL COMMENT 'Entrada ou saída',
                    `valor` DECIMAL(15,2) NOT NULL DEFAULT 0.00 COMMENT 'Valor da movimentação',
                    `quantidade` DECIMAL(15,3) NULL COMMENT 'Quantidade (para movimentações de estoque)',
                    `item_id` INT UNSIGNED NULL COMMENT 'ID do item (para movimentações de estoque)',

                    -- Referência ao documento origem
                    `documento_tipo` VARCHAR(50) NULL COMMENT 'Tipo do documento: compra, venda, contas_pagar, contas_receber, fluxo_caixa, etc',
                    `documento_id` INT UNSIGNED NULL COMMENT 'ID do documento origem',
                    `documento_numero` VARCHAR(100) NULL COMMENT 'Número do documento (ex: CPR-000001)',

                    -- Informações adicionais
                    `descricao` TEXT NULL COMMENT 'Descrição da movimentação',
                    `data_movimentacao` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data da movimentação',
                    `data_vencimento` DATE NULL COMMENT 'Data de vencimento (para contas a pagar/receber)',
                    `status` VARCHAR(50) NULL COMMENT 'Status da movimentação',

                    -- Controle
                    `created_by` INT UNSIGNED NULL COMMENT 'Usuário que criou a movimentação',
                    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
                    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

                    -- Índices
                    INDEX `idx_company` (`company_id`),
                    INDEX `idx_centro` (`centro_id`),
                    INDEX `idx_tipo_movimentacao` (`tipo_movimentacao`),
                    INDEX `idx_tipo_operacao` (`tipo_operacao`),
                    INDEX `idx_documento` (`documento_tipo`, `documento_id`),
                    INDEX `idx_data_movimentacao` (`data_movimentacao`),
                    INDEX `idx_item` (`item_id`),
                    INDEX `idx_status` (`status`),

                    -- Índices compostos para otimização
                    INDEX `idx_centro_tipo_data` (`centro_id`, `tipo_movimentacao`, `data_movimentacao`),
                    INDEX `idx_company_centro_data` (`company_id`, `centro_id`, `data_movimentacao`),
                    INDEX `idx_documento_completo` (`documento_tipo`, `documento_id`, `centro_id`),

                    -- Foreign Keys
                    FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE CASCADE,
                    FOREIGN KEY (`centro_id`) REFERENCES `centro_custos`(`id`) ON DELETE RESTRICT,
                    FOREIGN KEY (`created_by`) REFERENCES `users`(`id`) ON DELETE SET NULL
                    -- Nota: item_id não tem FK pois pode referenciar 'itens' ou 'produtos' dependendo da configuração

                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                COMMENT='Movimentações financeiras e de estoque por centro de custos'
            ");
        } catch (Exception $e) {
            error_log("Erro ao criar tabela movimentacao_centro_custos: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Exibe formulário de importação de XML
     */
    public function importarXml(): void
    {
        try {
            $this->view('compras/importar-xml', [
                'pageTitle' => 'Importar NFe XML',
                'activeMenu' => 'compras'
            ]);
        } catch (Exception $e) {
            error_log("Erro ao carregar formulário de importação: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

    /**
     * Processa importação de XML de NFe
     */
    public function processarXml(): void
    {
        try {
            $companyId = $this->getCompanyId();

            if (!isset($_FILES['xml_file']) || $_FILES['xml_file']['error'] !== UPLOAD_ERR_OK) {
                $this->error('Nenhum arquivo XML enviado ou erro no upload');
                return;
            }

            $xmlFile = $_FILES['xml_file']['tmp_name'];

            // Validar se é XML
            $xmlContent = file_get_contents($xmlFile);
            if (empty($xmlContent)) {
                $this->error('Arquivo XML vazio ou inválido');
                return;
            }

            // Suprimir warnings do XML
            libxml_use_internal_errors(true);
            $xml = simplexml_load_string($xmlContent);

            if ($xml === false) {
                $errors = libxml_get_errors();
                $errorMsg = 'Erro ao processar XML: ';
                foreach ($errors as $error) {
                    $errorMsg .= trim($error->message) . ' ';
                }
                libxml_clear_errors();
                $this->error($errorMsg);
                return;
            }

            // Extrair dados da NFe
            error_log("=== INÍCIO IMPORTAÇÃO XML ===");
            error_log("1. Extraindo dados da NFe...");
            $nfeData = $this->extrairDadosNFe($xml);

            if (empty($nfeData)) {
                error_log("❌ ERRO: Não foi possível extrair dados da NFe");
                $this->error('Não foi possível extrair dados da NFe');
                return;
            }

            error_log("✅ Dados extraídos:");
            error_log("   - Emitente: " . ($nfeData['emitente']['nome'] ?? 'N/A'));
            error_log("   - CNPJ: " . ($nfeData['emitente']['cnpj'] ?? 'N/A'));
            error_log("   - Total de itens: " . count($nfeData['itens'] ?? []));
            error_log("   - Valor total: " . ($nfeData['total']['total'] ?? 0));

            $this->db->beginTransaction();

            // 1. Verificar/Cadastrar Fornecedor (emitente)
            error_log("2. Verificando/Cadastrando fornecedor...");
            try {
                $fornecedorId = $this->verificarOuCadastrarFornecedor($nfeData['emitente'], $companyId);
                error_log("✅ Fornecedor ID: {$fornecedorId}");
            } catch (Exception $e) {
                error_log("❌ ERRO ao cadastrar fornecedor: " . $e->getMessage());
                throw $e;
            }

            // 2. Verificar/Cadastrar Produtos
            error_log("3. Verificando/Cadastrando produtos...");
            $produtosMap = [];
            foreach ($nfeData['itens'] as $index => $item) {
                try {
                    error_log("   Processando item " . ($index + 1) . ": " . ($item['nome'] ?? 'N/A'));
                    $produtoId = $this->verificarOuCadastrarProduto($item, $companyId);
                    error_log("   ✅ Produto ID: {$produtoId}");
                    $produtosMap[] = [
                        'produto_id' => $produtoId,
                        'item' => $item
                    ];
                } catch (Exception $e) {
                    error_log("   ❌ ERRO ao cadastrar produto: " . $e->getMessage());
                    throw $e;
                }
            }
            error_log("✅ Total de produtos processados: " . count($produtosMap));

            // 3. Criar Compra
            error_log("4. Criando compra...");
            try {
                $compraId = $this->criarCompraDoXml($nfeData, $fornecedorId, $produtosMap, $companyId);
                error_log("✅ Compra criada com ID: {$compraId}");
            } catch (Exception $e) {
                error_log("❌ ERRO ao criar compra: " . $e->getMessage());
                throw $e;
            }

            $this->db->commit();
            error_log("✅ Transação commitada com sucesso");

            $this->logActivity('importar_xml', 'compras', $compraId, [
                'numero_nfe' => $nfeData['numero_nfe'] ?? '',
                'chave_nfe' => $nfeData['chave_nfe'] ?? ''
            ]);

            $this->success('NFe importada com sucesso! Compra #' . $compraId . ' criada.', [
                'compra_id' => $compraId,
                'redirect' => \App\Helpers\UrlHelper::url('/compras/editar?id=' . $compraId)
            ]);

        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao processar XML: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            $this->error('Erro ao processar XML: ' . $e->getMessage());
        }
    }

    /**
     * Extrai dados da NFe do XML
     */
    private function extrairDadosNFe(\SimpleXMLElement $xml): array
    {
        $data = [];
        error_log("   Iniciando extração de dados do XML...");

        // Namespace
        $nfeNs = 'http://www.portalfiscal.inf.br/nfe';

        // Registrar namespace
        $xml->registerXPathNamespace('nfe', $nfeNs);

        // Função auxiliar para buscar com ou sem namespace
        $getElement = function ($parent, $name) {
            $namespaces = $parent->getNamespaces(true);
            $nfeNs = 'http://www.portalfiscal.inf.br/nfe';

            // Tentar com namespace primeiro
            if (isset($namespaces['']) || isset($namespaces[$nfeNs])) {
                $children = $parent->children($nfeNs);
                if (isset($children->$name)) {
                    return $children->$name;
                }
            }

            // Tentar sem namespace
            if (isset($parent->$name)) {
                return $parent->$name;
            }

            return null;
        };

        // Buscar NFe (pode estar em nfeProc/NFe ou diretamente)
        error_log("   Buscando estrutura NFe no XML...");

        // Tentar 1: nfeProc/NFe/infNFe
        $nfeProc = $xml->nfeProc ?? $xml->children($nfeNs)->nfeProc ?? null;
        if ($nfeProc) {
            error_log("   ✅ Encontrado nfeProc");
            $nfe = $nfeProc->NFe ?? $nfeProc->children($nfeNs)->NFe ?? null;
            if ($nfe) {
                error_log("   ✅ Encontrado NFe dentro de nfeProc");
                $infNFe = $nfe->infNFe ?? $nfe->children($nfeNs)->infNFe ?? null;
            }
        }

        // Tentar 2: NFe direto
        if (!isset($infNFe) || !$infNFe) {
            $nfe = $xml->NFe ?? $xml->children($nfeNs)->NFe ?? null;
            if ($nfe) {
                error_log("   ✅ Encontrado NFe direto");
                $infNFe = $nfe->infNFe ?? $nfe->children($nfeNs)->infNFe ?? null;
            }
        }

        // Tentar 3: infNFe direto
        if (!isset($infNFe) || !$infNFe) {
            $infNFe = $xml->infNFe ?? $xml->children($nfeNs)->infNFe ?? null;
            if ($infNFe) {
                error_log("   ✅ Encontrado infNFe direto");
            }
        }

        // Tentar 4: xpath
        if (!isset($infNFe) || !$infNFe) {
            $infNFeArray = $xml->xpath('//infNFe') ?: $xml->xpath('//nfe:infNFe') ?: [];
            if (!empty($infNFeArray)) {
                $infNFe = $infNFeArray[0];
                error_log("   ✅ Encontrado infNFe via xpath");
            }
        }

        if (!isset($infNFe) || !$infNFe) {
            error_log("   ❌ ERRO: Estrutura XML inválida - não foi possível encontrar infNFe");
            // Debug: listar elementos raiz
            $rootChildren = $xml->children();
            $rootNames = [];
            foreach ($rootChildren as $name => $child) {
                $rootNames[] = $name;
            }
            error_log("   Elementos raiz encontrados: " . implode(', ', $rootNames));
            throw new Exception('Estrutura XML inválida: não foi possível encontrar infNFe');
        }

        error_log("   ✅ infNFe encontrado com sucesso");

        // Chave da NFe
        $attrs = $infNFe->attributes();
        $data['chave_nfe'] = (string) ($attrs['Id'] ?? '');
        if (!empty($data['chave_nfe'])) {
            $data['chave_nfe'] = str_replace('NFe', '', $data['chave_nfe']);
        }

        // Dados do emitente (fornecedor)
        $emit = $infNFe->emit ?? $infNFe->children($nfeNs)->emit ?? null;
        if ($emit) {
            $data['emitente'] = [
                'cnpj' => (string) ($emit->CNPJ ?? $emit->CPF ?? ''),
                'nome' => (string) ($emit->xNome ?? ''),
                'fantasia' => (string) ($emit->xFant ?? ''),
                'ie' => (string) ($emit->IE ?? ''),
                'crt' => (string) ($emit->CRT ?? ''),
                'endereco' => [
                    'logradouro' => (string) ($emit->enderEmit->xLgr ?? $emit->enderEmit->children($nfeNs)->xLgr ?? ''),
                    'numero' => (string) ($emit->enderEmit->nro ?? $emit->enderEmit->children($nfeNs)->nro ?? ''),
                    'complemento' => (string) ($emit->enderEmit->xCpl ?? $emit->enderEmit->children($nfeNs)->xCpl ?? ''),
                    'bairro' => (string) ($emit->enderEmit->xBairro ?? $emit->enderEmit->children($nfeNs)->xBairro ?? ''),
                    'municipio' => (string) ($emit->enderEmit->xMun ?? $emit->enderEmit->children($nfeNs)->xMun ?? ''),
                    'uf' => (string) ($emit->enderEmit->UF ?? $emit->enderEmit->children($nfeNs)->UF ?? ''),
                    'cep' => (string) ($emit->enderEmit->CEP ?? $emit->enderEmit->children($nfeNs)->CEP ?? ''),
                    'pais' => (string) ($emit->enderEmit->xPais ?? $emit->enderEmit->children($nfeNs)->xPais ?? 'Brasil'),
                    'fone' => (string) ($emit->enderEmit->fone ?? $emit->enderEmit->children($nfeNs)->fone ?? '')
                ]
            ];
            error_log("   ✅ Emitente extraído: " . ($data['emitente']['nome'] ?? 'N/A') . " - CNPJ: " . ($data['emitente']['cnpj'] ?? 'N/A'));
        } else {
            error_log("   ❌ ERRO: Emitente não encontrado no XML!");
        }

        // Dados da nota
        $ide = $infNFe->ide ?? $infNFe->children($nfeNs)->ide ?? null;
        if ($ide) {
            $data['numero_nfe'] = (string) ($ide->nNF ?? '');
            $data['serie'] = (string) ($ide->serie ?? '');
            $data['data_emissao'] = (string) ($ide->dhEmi ?? '');
            $data['data_entrada'] = (string) ($ide->dhSaiEnt ?? '');
            $data['natureza_operacao'] = (string) ($ide->natOp ?? '');
        }

        // Itens da nota - tentar múltiplas formas de busca
        $dets = [];

        // Tentar 1: xpath com namespace
        $dets = $infNFe->xpath('.//nfe:det') ?: [];
        error_log("   Tentativa 1 (xpath nfe:det): " . count($dets) . " encontrados");

        // Tentar 2: xpath sem namespace
        if (empty($dets)) {
            $dets = $infNFe->xpath('.//det') ?: [];
            error_log("   Tentativa 2 (xpath det): " . count($dets) . " encontrados");
        }

        // Tentar 3: buscar diretamente no XML raiz
        if (empty($dets)) {
            $dets = $xml->xpath('//det') ?: $xml->xpath('//nfe:det') ?: [];
            error_log("   Tentativa 3 (xpath raiz): " . count($dets) . " encontrados");
        }

        // Tentar 4: acessar diretamente como propriedade
        if (empty($dets) && isset($infNFe->det)) {
            $detsArray = [];
            if (is_array($infNFe->det)) {
                $detsArray = $infNFe->det;
            } else {
                $detsArray = [$infNFe->det];
            }
            $dets = $detsArray;
            error_log("   Tentativa 4 (propriedade direta): " . count($dets) . " encontrados");
        }

        // Tentar 5: buscar com children
        if (empty($dets)) {
            $children = $infNFe->children($nfeNs);
            if (isset($children->det)) {
                if (is_array($children->det)) {
                    $dets = $children->det;
                } else {
                    $dets = [$children->det];
                }
                error_log("   Tentativa 5 (children): " . count($dets) . " encontrados");
            }
        }

        // Tentar 6: buscar sem namespace em children
        if (empty($dets)) {
            $children = $infNFe->children();
            if (isset($children->det)) {
                if (is_array($children->det)) {
                    $dets = $children->det;
                } else {
                    $dets = [$children->det];
                }
                error_log("   Tentativa 6 (children sem ns): " . count($dets) . " encontrados");
            }
        }

        $data['itens'] = [];
        error_log("   Total de <det> encontrados: " . count($dets));

        if (empty($dets)) {
            error_log("   ❌ ERRO: Nenhum item <det> encontrado no XML!");
            error_log("   Debug: Tentando listar elementos filhos de infNFe...");
            $children = $infNFe->children();
            $childNames = [];
            foreach ($children as $name => $child) {
                $childNames[] = $name;
            }
            error_log("   Elementos filhos encontrados: " . implode(', ', $childNames));
        }

        foreach ($dets as $index => $det) {
            // Tentar múltiplas formas de acessar <prod>
            $prod = null;

            // Tentar 1: propriedade direta
            if (isset($det->prod)) {
                $prod = $det->prod;
            }
            // Tentar 2: com namespace
            elseif (isset($det->children($nfeNs)->prod)) {
                $prod = $det->children($nfeNs)->prod;
            }
            // Tentar 3: sem namespace
            elseif (isset($det->children()->prod)) {
                $prod = $det->children()->prod;
            }
            // Tentar 4: xpath
            else {
                $prodArray = $det->xpath('.//prod') ?: $det->xpath('.//nfe:prod') ?: [];
                if (!empty($prodArray)) {
                    $prod = $prodArray[0];
                }
            }

            if (!$prod) {
                error_log("   ⚠️ Item " . ($index + 1) . ": <prod> não encontrado");
                // Debug: listar elementos do det
                $detChildren = $det->children();
                $detChildNames = [];
                foreach ($detChildren as $name => $child) {
                    $detChildNames[] = $name;
                }
                error_log("     Elementos do <det>: " . implode(', ', $detChildNames));
                continue;
            }

            // Função auxiliar para extrair valor com fallback
            $getValue = function ($element, $name) use ($nfeNs) {
                // Tentar direto
                if (isset($element->$name)) {
                    return (string) $element->$name;
                }
                // Tentar com namespace
                $children = $element->children($nfeNs);
                if (isset($children->$name)) {
                    return (string) $children->$name;
                }
                // Tentar sem namespace
                $childrenNoNs = $element->children();
                if (isset($childrenNoNs->$name)) {
                    return (string) $childrenNoNs->$name;
                }
                return '';
            };

            $item = [
                'codigo_produto' => $getValue($prod, 'cProd'),
                'ean' => $getValue($prod, 'cEAN'),
                'nome' => $getValue($prod, 'xProd'),
                'ncm' => $getValue($prod, 'NCM'),
                'cfop' => $getValue($prod, 'CFOP'),
                'unidade' => $getValue($prod, 'uCom'),
                'quantidade' => (float) ($getValue($prod, 'qCom') ?: 0),
                'valor_unitario' => (float) ($getValue($prod, 'vUnCom') ?: 0),
                'valor_total' => (float) ($getValue($prod, 'vProd') ?: 0),
                'lotes' => []
            ];

            // Se ainda estiver vazio, tentar acessar diretamente
            if (empty($item['nome'])) {
                $item['nome'] = (string) ($prod->xProd ?? $prod->children($nfeNs)->xProd ?? $prod->children()->xProd ?? '');
            }
            if (empty($item['codigo_produto'])) {
                $item['codigo_produto'] = (string) ($prod->cProd ?? $prod->children($nfeNs)->cProd ?? $prod->children()->cProd ?? '');
            }
            if (empty($item['quantidade'])) {
                $item['quantidade'] = (float) ($prod->qCom ?? $prod->children($nfeNs)->qCom ?? $prod->children()->qCom ?? 0);
            }
            if (empty($item['valor_total'])) {
                $item['valor_total'] = (float) ($prod->vProd ?? $prod->children($nfeNs)->vProd ?? $prod->children()->vProd ?? 0);
            }

            error_log("   ✅ Item " . ($index + 1) . " extraído: " . ($item['nome'] ?: 'Sem nome') . " - Qtd: {$item['quantidade']} - Valor: {$item['valor_total']}");

            // Extrair lotes (rastro)
            $rastros = $det->xpath('.//rastro') ?: $det->xpath('.//nfe:rastro') ?: [];
            foreach ($rastros as $rastro) {
                $item['lotes'][] = [
                    'numero' => (string) ($rastro->nLote ?? ''),
                    'quantidade' => (float) ($rastro->qLote ?? 0),
                    'data_fabricacao' => (string) ($rastro->dFab ?? ''),
                    'data_validade' => (string) ($rastro->dVal ?? '')
                ];
            }

            $data['itens'][] = $item;
        }

        error_log("   ✅ Total de itens extraídos: " . count($data['itens']));

        // Totais - tentar múltiplas formas
        $total = null;

        // Tentar 1: xpath com namespace
        $totalArray = $infNFe->xpath('.//nfe:total/nfe:ICMSTot') ?: [];
        if (!empty($totalArray)) {
            $total = $totalArray[0];
        }

        // Tentar 2: xpath sem namespace
        if (!$total) {
            $totalArray = $infNFe->xpath('.//total/ICMSTot') ?: [];
            if (!empty($totalArray)) {
                $total = $totalArray[0];
            }
        }

        // Tentar 3: propriedade direta
        if (!$total && isset($infNFe->total)) {
            $totalObj = $infNFe->total;
            if (isset($totalObj->ICMSTot)) {
                $total = $totalObj->ICMSTot;
            } elseif (isset($totalObj->children($nfeNs)->ICMSTot)) {
                $total = $totalObj->children($nfeNs)->ICMSTot;
            }
        }

        // Tentar 4: xpath no XML raiz
        if (!$total) {
            $totalArray = $xml->xpath('//ICMSTot') ?: $xml->xpath('//nfe:ICMSTot') ?: [];
            if (!empty($totalArray)) {
                $total = $totalArray[0];
            }
        }

        if ($total) {
            // Função auxiliar para extrair valor
            $getTotalValue = function ($element, $name) use ($nfeNs) {
                if (isset($element->$name)) {
                    return (float) $element->$name;
                }
                $children = $element->children($nfeNs);
                if (isset($children->$name)) {
                    return (float) $children->$name;
                }
                $childrenNoNs = $element->children();
                if (isset($childrenNoNs->$name)) {
                    return (float) $childrenNoNs->$name;
                }
                return 0.0;
            };

            $data['total'] = [
                'produtos' => $getTotalValue($total, 'vProd'),
                'frete' => $getTotalValue($total, 'vFrete'),
                'seguro' => $getTotalValue($total, 'vSeg'),
                'desconto' => $getTotalValue($total, 'vDesc'),
                'outros' => $getTotalValue($total, 'vOutro'),
                'total' => $getTotalValue($total, 'vNF')
            ];

            // Se o total ainda estiver 0, calcular pela soma dos itens
            if ($data['total']['total'] == 0 && !empty($data['itens'])) {
                $somaItens = 0;
                foreach ($data['itens'] as $item) {
                    $somaItens += $item['valor_total'] ?? 0;
                }
                $data['total']['total'] = $somaItens;
                $data['total']['produtos'] = $somaItens;
                error_log("   ⚠️ Total não encontrado no XML, calculado pela soma dos itens: {$somaItens}");
            }

            error_log("   ✅ Total extraído: R$ " . number_format($data['total']['total'], 2, ',', '.'));
        } else {
            // Se não encontrou total, calcular pela soma dos itens
            $somaItens = 0;
            foreach ($data['itens'] as $item) {
                $somaItens += $item['valor_total'] ?? 0;
            }
            $data['total'] = [
                'produtos' => $somaItens,
                'frete' => 0,
                'seguro' => 0,
                'desconto' => 0,
                'outros' => 0,
                'total' => $somaItens
            ];
            error_log("   ⚠️ Total não encontrado no XML, calculado pela soma dos itens: {$somaItens}");
        }

        // Duplicatas (parcelas)
        $dups = $infNFe->xpath('.//dup') ?: $infNFe->xpath('.//nfe:dup') ?: [];
        $data['duplicatas'] = [];
        foreach ($dups as $dup) {
            $data['duplicatas'][] = [
                'numero' => (string) ($dup->nDup ?? ''),
                'vencimento' => (string) ($dup->dVenc ?? ''),
                'valor' => (float) ($dup->vDup ?? 0)
            ];
        }

        return $data;
    }

    /**
     * Verifica se fornecedor existe ou cadastra novo
     */
    private function verificarOuCadastrarFornecedor(array $emitente, int $companyId): int
    {
        $cnpj = preg_replace('/[^0-9]/', '', $emitente['cnpj'] ?? '');

        if (empty($cnpj)) {
            throw new Exception('CNPJ do emitente não encontrado no XML');
        }

        // Verificar se já existe
        $stmt = $this->db->prepare("
            SELECT id FROM pessoas
            WHERE company_id = :company_id
            AND document = :document
            LIMIT 1
        ");
        $stmt->execute(['company_id' => $companyId, 'document' => $cnpj]);
        $fornecedor = $stmt->fetch();

        if ($fornecedor) {
            return (int) $fornecedor['id'];
        }

        // Verificar estrutura da tabela
        $stmtCheck = $this->db->query("SHOW COLUMNS FROM pessoas");
        $columns = $stmtCheck->fetchAll();
        $columnNames = array_column($columns, 'Field');

        $campos = ['company_id', 'name', 'document', 'is_active'];
        $valores = [':company_id', ':name', ':document', '1'];

        $dados = [
            'company_id' => $companyId,
            'name' => $emitente['nome'] ?? 'Fornecedor NFe',
            'document' => $cnpj
        ];

        // Adicionar campos opcionais
        if (in_array('trade_name', $columnNames)) {
            $campos[] = 'trade_name';
            $valores[] = ':trade_name';
            $dados['trade_name'] = $emitente['fantasia'] ?? '';
        }

        if (in_array('rg_ie', $columnNames) && !empty($emitente['ie'])) {
            $campos[] = 'rg_ie';
            $valores[] = ':rg_ie';
            $dados['rg_ie'] = $emitente['ie'];
        }

        if (in_array('type', $columnNames)) {
            $campos[] = 'type';
            $valores[] = ':type';
            $dados['type'] = 'fornecedor';
        }

        if (in_array('tipo_fornecedor', $columnNames)) {
            $campos[] = 'tipo_fornecedor';
            $valores[] = '1';
        }

        if (in_array('person_type', $columnNames)) {
            $campos[] = 'person_type';
            $valores[] = ':person_type';
            $dados['person_type'] = 'juridica';
        }

        // Endereço
        if (!empty($emitente['endereco'])) {
            $end = $emitente['endereco'];
            if (in_array('address', $columnNames)) {
                $campos[] = 'address';
                $valores[] = ':address';
                $dados['address'] = $end['logradouro'] ?? '';
            }
            if (in_array('numero', $columnNames)) {
                $campos[] = 'numero';
                $valores[] = ':numero';
                $dados['numero'] = $end['numero'] ?? '';
            }
            if (in_array('complemento', $columnNames)) {
                $campos[] = 'complemento';
                $valores[] = ':complemento';
                $dados['complemento'] = $end['complemento'] ?? '';
            }
            if (in_array('bairro', $columnNames)) {
                $campos[] = 'bairro';
                $valores[] = ':bairro';
                $dados['bairro'] = $end['bairro'] ?? '';
            }
            if (in_array('city', $columnNames)) {
                $campos[] = 'city';
                $valores[] = ':city';
                $dados['city'] = $end['municipio'] ?? '';
            }
            if (in_array('state', $columnNames)) {
                $campos[] = 'state';
                $valores[] = ':state';
                $dados['state'] = $end['uf'] ?? '';
            }
            if (in_array('zip_code', $columnNames)) {
                $campos[] = 'zip_code';
                $valores[] = ':zip_code';
                $dados['zip_code'] = preg_replace('/[^0-9]/', '', $end['cep'] ?? '');
            }
            if (in_array('phone', $columnNames) && !empty($end['fone'])) {
                $campos[] = 'phone';
                $valores[] = ':phone';
                $dados['phone'] = $end['fone'];
            }
        }

        $campos[] = 'created_at';
        $valores[] = 'NOW()';

        $sql = "INSERT INTO pessoas (" . implode(', ', $campos) . ") VALUES (" . implode(', ', $valores) . ")";
        $stmt = $this->db->prepare($sql);
        $stmt->execute($dados);

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

    /**
     * Verifica se produto existe ou cadastra novo
     */
    private function verificarOuCadastrarProduto(array $item, int $companyId): int
    {
        error_log("     Verificando produto: " . ($item['nome'] ?? 'Sem nome') . " - EAN: " . ($item['ean'] ?? 'N/A') . " - Código: " . ($item['codigo_produto'] ?? 'N/A'));

        $ean = $item['ean'] ?? '';
        $codigo = $item['codigo_produto'] ?? '';

        // Verificar qual tabela usar (produtos ou itens)
        $tabelaProdutos = 'produtos';
        try {
            $stmtTest = $this->db->query("SHOW TABLES LIKE 'produtos'");
            if ($stmtTest->rowCount() == 0) {
                $stmtTest = $this->db->query("SHOW TABLES LIKE 'itens'");
                if ($stmtTest->rowCount() > 0) {
                    $tabelaProdutos = 'itens';
                    error_log("     ℹ️ Usando tabela 'itens' em vez de 'produtos'");
                }
            }
        } catch (Exception $e) {
            error_log("     ⚠️ Erro ao verificar tabela: " . $e->getMessage());
        }

        // Verificar estrutura da tabela primeiro
        $stmtCheck = $this->db->query("SHOW COLUMNS FROM {$tabelaProdutos}");
        $columns = $stmtCheck->fetchAll();
        $columnNames = array_column($columns, 'Field');
        $temSku = in_array('sku', $columnNames);
        $temCode = in_array('code', $columnNames);
        $temBarcode = in_array('barcode', $columnNames);

        // Tentar encontrar por EAN primeiro
        if (!empty($ean) && $ean !== 'SEM GTIN') {
            $whereConditions = ['company_id = :company_id'];
            $params = ['company_id' => $companyId, 'ean' => $ean];

            // Construir condições dinamicamente
            $eanConditions = [];
            if ($temBarcode) {
                $eanConditions[] = 'barcode = :ean';
            }
            if ($temSku) {
                $eanConditions[] = 'sku = :ean';
            }
            if ($temCode) {
                $eanConditions[] = 'code = :ean';
            }

            if (!empty($eanConditions)) {
                $whereConditions[] = '(' . implode(' OR ', $eanConditions) . ')';
                $sql = "SELECT id FROM {$tabelaProdutos} WHERE " . implode(' AND ', $whereConditions) . " LIMIT 1";
                error_log("     SQL busca EAN: {$sql}");
                $stmt = $this->db->prepare($sql);
                $stmt->execute($params);
                $produto = $stmt->fetch();

                if ($produto) {
                    error_log("     ✅ Produto encontrado por EAN - ID: " . $produto['id']);
                    return (int) $produto['id'];
                } else {
                    error_log("     ℹ️ Produto não encontrado por EAN");
                }
            }
        }

        // Verificar estrutura da tabela antes de buscar por código
        $stmtCheck = $this->db->query("SHOW COLUMNS FROM {$tabelaProdutos}");
        $columns = $stmtCheck->fetchAll();
        $columnNames = array_column($columns, 'Field');
        $temSku = in_array('sku', $columnNames);
        $temCode = in_array('code', $columnNames);
        $temBarcode = in_array('barcode', $columnNames);

        // Tentar encontrar por código do produto
        if (!empty($codigo)) {
            $whereConditions = ['company_id = :company_id'];
            $params = ['company_id' => $companyId];

            // Construir condições dinamicamente baseado nas colunas disponíveis
            $codigoConditions = [];
            if ($temSku) {
                $codigoConditions[] = 'sku = :codigo';
            }
            if ($temCode) {
                $codigoConditions[] = 'code = :codigo';
            }
            if ($temBarcode) {
                $codigoConditions[] = 'barcode = :codigo';
            }

            if (!empty($codigoConditions)) {
                $whereConditions[] = '(' . implode(' OR ', $codigoConditions) . ')';
                $params['codigo'] = $codigo;
            }

            // Adicionar busca por nome se a coluna name existir e nome estiver disponível
            if (in_array('name', $columnNames) && !empty($item['nome'])) {
                $whereConditions[] = 'name LIKE :nome';
                $params['nome'] = '%' . $item['nome'] . '%';
            }

            // Só executar se tiver pelo menos company_id + uma condição adicional
            if (count($whereConditions) > 1) {
                $sql = "SELECT id FROM {$tabelaProdutos} WHERE " . implode(' AND ', $whereConditions) . " LIMIT 1";
                error_log("     SQL busca: {$sql}");
                error_log("     Parâmetros: " . json_encode(array_keys($params)));
                $stmt = $this->db->prepare($sql);
                $stmt->execute($params);
                $produto = $stmt->fetch();

                if ($produto) {
                    error_log("     ✅ Produto encontrado por código/nome - ID: " . $produto['id']);
                    return (int) $produto['id'];
                } else {
                    error_log("     ℹ️ Produto não encontrado por código/nome");
                }
            }
        }

        // Verificar estrutura da tabela produtos (já verificada acima, reutilizar)
        if (!isset($columnNames)) {
            error_log("     📋 Verificando estrutura da tabela {$tabelaProdutos}...");
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM {$tabelaProdutos}");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');
        }
        error_log("     📋 Colunas disponíveis: " . implode(', ', $columnNames));

        // Criar novo produto
        $campos = ['company_id', 'name', 'type', 'is_active', 'created_at', 'updated_at'];
        $valores = [':company_id', ':name', ':type', '1', 'NOW()', 'NOW()'];

        $dados = [
            'company_id' => $companyId,
            'name' => $item['nome'] ?? 'Produto NFe',
            'type' => 'produto'
        ];

        // Barcode/SKU
        if (in_array('barcode', $columnNames) && !empty($ean) && $ean !== 'SEM GTIN') {
            $campos[] = 'barcode';
            $valores[] = ':barcode';
            $dados['barcode'] = $ean;
        } elseif (in_array('sku', $columnNames)) {
            $campos[] = 'sku';
            $valores[] = ':sku';
            $dados['sku'] = !empty($codigo) ? $codigo : $ean;
        } elseif (in_array('code', $columnNames)) {
            $campos[] = 'code';
            $valores[] = ':code';
            $dados['code'] = !empty($codigo) ? $codigo : $ean;
        }

        // Preço de compra
        if (in_array('purchase_price', $columnNames)) {
            $campos[] = 'purchase_price';
            $valores[] = ':purchase_price';
            $dados['purchase_price'] = $item['valor_unitario'] ?? 0;
        } elseif (in_array('cost_price', $columnNames)) {
            $campos[] = 'cost_price';
            $valores[] = ':cost_price';
            $dados['cost_price'] = $item['valor_unitario'] ?? 0;
        }

        // Preço de venda (pode ser o mesmo ou calcular margem)
        if (in_array('price', $columnNames)) {
            $campos[] = 'price';
            $valores[] = ':price';
            $dados['price'] = $item['valor_unitario'] ?? 0;
        }

        // NCM
        if (in_array('ncm', $columnNames) && !empty($item['ncm'])) {
            $campos[] = 'ncm';
            $valores[] = ':ncm';
            $dados['ncm'] = $item['ncm'];
        }

        // Unidade
        if (in_array('unit', $columnNames) && !empty($item['unidade'])) {
            $campos[] = 'unit';
            $valores[] = ':unit';
            $dados['unit'] = $item['unidade'];
        }

        $sql = "INSERT INTO {$tabelaProdutos} (" . implode(', ', $campos) . ") VALUES (" . implode(', ', $valores) . ")";
        error_log("     SQL Produto: {$sql}");
        error_log("     Dados Produto: " . json_encode($dados));

        try {
            $stmt = $this->db->prepare($sql);
            $stmt->execute($dados);
            $produtoId = (int) $this->db->lastInsertId();
            error_log("     ✅ Produto cadastrado na tabela '{$tabelaProdutos}' com ID: {$produtoId}");

            // Gerar SKU se não foi definido
            if (empty($dados['sku'] ?? '') && in_array('sku', $columnNames)) {
                $sku = 'PROD' . str_pad($produtoId, 4, '0', STR_PAD_LEFT);
                $stmtSku = $this->db->prepare("UPDATE {$tabelaProdutos} SET sku = :sku WHERE id = :id");
                $stmtSku->execute(['sku' => $sku, 'id' => $produtoId]);
                error_log("     ✅ SKU gerado: {$sku}");
            }

            return $produtoId;
        } catch (Exception $e) {
            error_log("     ❌ ERRO ao cadastrar produto: " . $e->getMessage());
            error_log("     SQL Error Info: " . json_encode($this->db->errorInfo()));
            throw $e;
        }
    }

    /**
     * Cria compra a partir dos dados do XML
     */
    private function criarCompraDoXml(array $nfeData, int $fornecedorId, array $produtosMap, int $companyId): int
    {
        // Verificar estrutura da tabela compras
        $stmtCheck = $this->db->query("SHOW COLUMNS FROM compras");
        $columns = $stmtCheck->fetchAll();
        $columnNames = array_column($columns, 'Field');

        $campos = ['company_id', 'fornecedor_id', 'numero', 'data_compra', 'total', 'status', 'created_at', 'updated_at'];
        $valores = [':company_id', ':fornecedor_id', ':numero', ':data_compra', ':total', ':status', 'NOW()', 'NOW()'];

        // Data de entrada
        $dataEntrada = !empty($nfeData['data_entrada']) ? date('Y-m-d', strtotime($nfeData['data_entrada'])) : date('Y-m-d');

        $dados = [
            'company_id' => $companyId,
            'fornecedor_id' => $fornecedorId,
            'numero' => 'NFe ' . ($nfeData['numero_nfe'] ?? ''),
            'data_compra' => $dataEntrada,
            'total' => $nfeData['total']['total'] ?? 0,
            'status' => 'pedido'
        ];

        // Adicionar campos opcionais
        if (in_array('notes', $columnNames)) {
            $notas = [];
            if (!empty($nfeData['natureza_operacao'])) {
                $notas[] = 'Natureza: ' . $nfeData['natureza_operacao'];
            }
            if (!empty($nfeData['chave_nfe'])) {
                $notas[] = 'Chave NFe: ' . $nfeData['chave_nfe'];
            }
            $notesValue = implode("\n", $notas);
            // Só adicionar se tiver conteúdo
            if (!empty($notesValue)) {
                $campos[] = 'notes';
                $valores[] = ':notes';
                $dados['notes'] = $notesValue;
            }
        }

        if (in_array('chave_nfe', $columnNames) && !empty($nfeData['chave_nfe'])) {
            $campos[] = 'chave_nfe';
            $valores[] = ':chave_nfe';
            $dados['chave_nfe'] = $nfeData['chave_nfe'];
        }

        // Construir SQL e dados de forma segura - garantir sincronização perfeita
        $camposFinais = [];
        $valoresFinais = [];
        $dadosFinais = [];

        // Validação inicial: garantir que arrays têm o mesmo tamanho
        if (count($campos) !== count($valores)) {
            throw new Exception("Erro interno: arrays de campos e valores têm tamanhos diferentes. Campos: " . count($campos) . ", Valores: " . count($valores));
        }

        // Iterar pelos campos e valores de forma sincronizada
        for ($i = 0; $i < count($campos); $i++) {
            $campo = $campos[$i];
            $valor = $valores[$i];

            if (strpos($valor, ':') === 0) {
                // É um placeholder
                $placeholder = substr($valor, 1);
                // Verificar se o placeholder existe em $dados (mesmo que seja NULL)
                // array_key_exists permite NULL, isset() não
                if (array_key_exists($placeholder, $dados)) {
                    $camposFinais[] = $campo;
                    $valoresFinais[] = $valor;
                    $dadosFinais[$placeholder] = $dados[$placeholder];
                } else {
                    // Placeholder não tem valor - isso causaria HY093, então não adicionamos
                    error_log("   ⚠️ Placeholder :{$placeholder} não encontrado em \$dados, pulando campo {$campo}");
                }
            } else {
                // É um valor literal (como NOW())
                $camposFinais[] = $campo;
                $valoresFinais[] = $valor;
            }
        }

        // Validação final: garantir que todos os placeholders na SQL têm valores
        preg_match_all('/:(\w+)/', implode(' ', $valoresFinais), $matches);
        $placeholdersNaQuery = $matches[1] ?? [];

        // Verificar placeholders duplicados (pode causar HY093)
        $placeholdersCount = array_count_values($placeholdersNaQuery);
        $duplicados = array_filter($placeholdersCount, function ($count) {
            return $count > 1;
        });
        if (!empty($duplicados)) {
            $errorMsg = "Placeholders duplicados na query: " . implode(', ', array_keys($duplicados));
            error_log("   ❌ ERRO: {$errorMsg}");
            throw new Exception($errorMsg);
        }

        $placeholdersSemValor = array_diff($placeholdersNaQuery, array_keys($dadosFinais));

        if (!empty($placeholdersSemValor)) {
            $errorMsg = "Placeholders na query sem valores: " . implode(', ', $placeholdersSemValor);
            error_log("   ❌ ERRO: {$errorMsg}");
            error_log("   Campos finais: " . implode(', ', $camposFinais));
            error_log("   Valores finais: " . implode(', ', $valoresFinais));
            error_log("   Dados disponíveis: " . implode(', ', array_keys($dados)));
            throw new Exception($errorMsg);
        }

        // Validação extra: garantir que não há dados sem placeholders
        $dadosSemPlaceholder = array_diff(array_keys($dadosFinais), $placeholdersNaQuery);
        if (!empty($dadosSemPlaceholder)) {
            error_log("   ⚠️ AVISO: Dados sem placeholders na query (serão ignorados): " . implode(', ', $dadosSemPlaceholder));
        }

        $sql = "INSERT INTO compras (" . implode(', ', $camposFinais) . ") VALUES (" . implode(', ', $valoresFinais) . ")";

        // Preparar dados para execute() - garantir que chaves não tenham ':' e valores são válidos
        $dadosParaExecute = [];
        foreach ($dadosFinais as $key => $value) {
            // Remover ':' se existir no início da chave (PDO não aceita ':' nas chaves)
            $cleanKey = (strpos($key, ':') === 0) ? substr($key, 1) : $key;
            // PDO aceita NULL, então manter NULL se for o valor
            $dadosParaExecute[$cleanKey] = $value;
        }

        // Validação crítica: contar placeholders na SQL vs parâmetros
        $countPlaceholders = count($placeholdersNaQuery);
        $countParams = count($dadosParaExecute);
        if ($countPlaceholders !== $countParams) {
            $errorMsg = "CRÍTICO: Contagem não corresponde! Placeholders: {$countPlaceholders}, Parâmetros: {$countParams}";
            error_log("   ❌ {$errorMsg}");
            error_log("   Placeholders: " . implode(', ', $placeholdersNaQuery));
            error_log("   Parâmetros: " . implode(', ', array_keys($dadosParaExecute)));
            throw new Exception($errorMsg);
        }

        $logMsg = "   SQL Compra: {$sql}\n   Dados Compra (original): " . json_encode($dadosFinais) . "\n   Dados para execute: " . json_encode($dadosParaExecute) . "\n   Placeholders: " . implode(', ', $placeholdersNaQuery) . " (total: {$countPlaceholders})";
        error_log($logMsg);
        $this->logToFile($logMsg, 'compras-importacao-nfe.log');

        try {
            $stmt = $this->db->prepare($sql);
            $stmt->execute($dadosParaExecute);
            $compraId = (int) $this->db->lastInsertId();
            error_log("   ✅ Compra criada com ID: {$compraId}");
        } catch (Exception $e) {
            $errorMsg = $e->getMessage();
            $errorInfo = $this->db->errorInfo();

            $logDetails = [
                "❌ ERRO ao criar compra: {$errorMsg}",
                "SQL Error Code: " . ($errorInfo[0] ?? 'N/A'),
                "SQL Error Message: " . ($errorInfo[2] ?? 'N/A'),
                "SQL: {$sql}",
                "Dados enviados: " . json_encode($dadosFinais),
                "Contagem placeholders na SQL: " . substr_count($sql, ':'),
                "Contagem dados: " . count($dadosFinais)
            ];

            // Verificar se é o erro de parâmetro inválido
            if (strpos($errorMsg, 'Invalid parameter number') !== false || strpos($errorMsg, 'HY093') !== false) {
                preg_match_all('/:(\w+)/', $sql, $matches);
                $logDetails[] = "⚠️ ERRO CONFIRMADO: Invalid parameter number (HY093)";
                $logDetails[] = "Placeholders na SQL: " . (isset($matches[1]) ? implode(', ', $matches[1]) : 'nenhum');
                $logDetails[] = "Chaves nos dados: " . implode(', ', array_keys($dadosFinais));
            }

            $logMessage = implode("\n", $logDetails);
            error_log($logMessage);
            $this->logToFile($logMessage, 'compras-importacao-nfe.log');

            throw $e;
        }

        // Inserir itens da compra
        if (empty($produtosMap)) {
            error_log("   ⚠️ AVISO: Nenhum item para inserir na compra!");
        } else {
            $this->inserirItensCompra($compraId, $produtosMap, $companyId);
        }

        return $compraId;
    }

    /**
     * Cria tabela para armazenar relacionamentos entre produtos e códigos de fornecedores
     */
    private function criarTabelaProdutoFornecedorCodigos(): void
    {
        try {
            $stmt = $this->db->query("SHOW TABLES LIKE 'produto_fornecedor_codigos'");
            if ($stmt->rowCount() > 0) {
                return; // Tabela já existe
            }

            // Criar tabela com ambos os campos (produto_id e item_id) para compatibilidade
            // O sistema detecta qual usar baseado na existência das tabelas produtos/itens
            $this->db->exec("
                CREATE TABLE IF NOT EXISTS `produto_fornecedor_codigos` (
                    `id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
                    `company_id` INT UNSIGNED NOT NULL COMMENT 'ID da empresa',
                    `produto_id` INT UNSIGNED NULL COMMENT 'ID do produto (se usar tabela produtos)',
                    `item_id` INT UNSIGNED NULL COMMENT 'ID do item (se usar tabela itens)',
                    `fornecedor_id` INT UNSIGNED NOT NULL COMMENT 'ID do fornecedor (pessoas)',
                    `codigo_fornecedor` VARCHAR(100) NOT NULL COMMENT 'Código do produto no fornecedor',
                    `ean_fornecedor` VARCHAR(20) NULL COMMENT 'EAN/GTIN do produto no fornecedor',
                    `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
                    `updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

                    -- Índices
                    INDEX `idx_company` (`company_id`),
                    INDEX `idx_produto` (`produto_id`),
                    INDEX `idx_item` (`item_id`),
                    INDEX `idx_fornecedor` (`fornecedor_id`),
                    INDEX `idx_codigo` (`codigo_fornecedor`),
                    INDEX `idx_ean` (`ean_fornecedor`),
                    INDEX `idx_fornecedor_codigo` (`fornecedor_id`, `codigo_fornecedor`),

                    -- Constraint única: mesmo produto/item, mesmo fornecedor, mesmo código
                    UNIQUE KEY `uk_produto_fornecedor_codigo` (`company_id`, `fornecedor_id`, `codigo_fornecedor`, `produto_id`, `item_id`),

                    -- Foreign Keys
                    FOREIGN KEY (`company_id`) REFERENCES `companies`(`id`) ON DELETE CASCADE,
                    FOREIGN KEY (`fornecedor_id`) REFERENCES `pessoas`(`id`) ON DELETE CASCADE,

                    -- Constraint: deve ter produto_id OU item_id, mas não ambos
                    CHECK ((`produto_id` IS NOT NULL AND `item_id` IS NULL) OR (`produto_id` IS NULL AND `item_id` IS NOT NULL))
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
                COMMENT='Relacionamento entre produtos do sistema e códigos de fornecedores'
            ");

            error_log("✅ Tabela produto_fornecedor_codigos criada com sucesso");
        } catch (Exception $e) {
            error_log("Erro ao criar tabela produto_fornecedor_codigos: " . $e->getMessage());
            // Não lançar exceção para não quebrar o fluxo
        }
    }


    /**
     * Atualiza SKU de um produto (usado após criação rápida)
     */
    public function atualizarSkuProduto(): void
    {
        try {
            $produtoId = (int) $this->request->post('produto_id');
            $sku = trim($this->request->post('sku', ''));
            $companyId = $this->getCompanyId();

            if (empty($produtoId) || empty($sku)) {
                $this->response->json([
                    'success' => false,
                    'message' => 'ID do produto e SKU são obrigatórios'
                ], 400);
                return;
            }

            // Verificar se produto pertence à empresa
            $stmt = $this->db->prepare("SELECT id FROM produtos WHERE id = :id AND company_id = :company_id LIMIT 1");
            $stmt->execute(['id' => $produtoId, 'company_id' => $companyId]);
            $produto = $stmt->fetch();

            if (!$produto) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Produto não encontrado'
                ], 404);
                return;
            }

            // Atualizar SKU
            $stmt = $this->db->prepare("UPDATE produtos SET sku = :sku WHERE id = :id AND company_id = :company_id");
            $stmt->execute(['sku' => $sku, 'id' => $produtoId, 'company_id' => $companyId]);

            $this->response->json([
                'success' => true,
                'message' => 'SKU atualizado com sucesso'
            ]);
        } catch (Exception $e) {
            error_log("Erro ao atualizar SKU: " . $e->getMessage());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao atualizar SKU'
            ], 500);
        }
    }

    /**
     * Exibe tela de relacionamento de produtos do XML com produtos do sistema
     */
    public function relacionarProdutosXml(): void
    {
        try {
            $compraId = (int) $this->request->get('compra_id');
            $companyId = $this->getCompanyId();

            error_log("🔍 relacionarProdutosXml - compra_id: {$compraId}, company_id: {$companyId}");

            if (empty($compraId)) {
                error_log("❌ ID da compra não informado");
                $this->error('ID da compra não informado');
                return;
            }

            // Buscar compra
            $stmt = $this->db->prepare("SELECT * FROM compras WHERE id = :id AND company_id = :company_id LIMIT 1");
            $stmt->execute(['id' => $compraId, 'company_id' => $companyId]);
            $compra = $stmt->fetch();

            if (!$compra) {
                error_log("❌ Compra não encontrada: ID {$compraId}");
                $this->error('Compra não encontrada');
                return;
            }

            error_log("✅ Compra encontrada: ID {$compraId}, chave_nfe: " . ($compra['chave_nfe'] ?? 'não informada'));

            // Verificar se tem XML
            $xmlCompleto = null;
            if (isset($compra['xml_completo']) && !empty($compra['xml_completo'])) {
                $xmlCompleto = $compra['xml_completo'];
                error_log("✅ XML encontrado na coluna xml_completo da compra");
            } elseif (isset($compra['chave_nfe']) && !empty($compra['chave_nfe'])) {
                // Buscar XML da tabela nfe_recebidas
                error_log("🔍 Buscando XML na tabela nfe_recebidas para chave: {$compra['chave_nfe']}");
                $stmt = $this->db->prepare("SELECT xml_completo FROM nfe_recebidas WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                $stmt->execute(['chave_nfe' => $compra['chave_nfe'], 'company_id' => $companyId]);
                $nfe = $stmt->fetch();
                if ($nfe && !empty($nfe['xml_completo'])) {
                    $xmlCompleto = $nfe['xml_completo'];
                    error_log("✅ XML encontrado na tabela nfe_recebidas");
                } else {
                    error_log("❌ XML não encontrado na tabela nfe_recebidas");
                }
            } else {
                error_log("❌ Compra não tem chave_nfe para buscar XML");
            }

            if (empty($xmlCompleto)) {
                error_log("❌ XML da NF-e não encontrado para esta compra");
                $this->error('XML da NF-e não encontrado para esta compra. Verifique se a NF-e foi baixada corretamente.');
                return;
            }

            // Extrair itens do XML
            libxml_use_internal_errors(true);
            $xml = simplexml_load_string($xmlCompleto);

            if ($xml === false) {
                $errors = libxml_get_errors();
                $errorMsg = 'Erro ao processar XML: ';
                foreach ($errors as $error) {
                    $errorMsg .= trim($error->message) . ' ';
                }
                libxml_clear_errors();
                throw new Exception($errorMsg);
            }

            $nfeData = $this->extrairDadosNFe($xml);
            $itensXml = $nfeData['itens'] ?? [];

            if (empty($itensXml)) {
                $this->error('Nenhum item encontrado no XML');
                return;
            }

            // Buscar produtos do sistema para relacionamento
            $produtos = [];
            try {
                // Verificar qual tabela usar
                $stmtTest = $this->db->query("SHOW TABLES LIKE 'produtos'");
                $tabelaProdutos = ($stmtTest->rowCount() > 0) ? 'produtos' : 'itens';

                $stmt = $this->db->prepare("
                    SELECT id, name, code, barcode, unit, price
                    FROM {$tabelaProdutos}
                    WHERE company_id = :company_id
                    ORDER BY name ASC
                ");
                $stmt->execute(['company_id' => $companyId]);
                $produtos = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao buscar produtos: " . $e->getMessage());
            }

            // Buscar fornecedor
            $fornecedor = null;
            $fornecedorId = null;
            if (!empty($compra['fornecedor_id'])) {
                $fornecedorId = (int) $compra['fornecedor_id'];
                $stmt = $this->db->prepare("SELECT id, name, document FROM pessoas WHERE id = :id LIMIT 1");
                $stmt->execute(['id' => $fornecedorId]);
                $fornecedor = $stmt->fetch();
            }

            // Buscar relacionamentos existentes para auto-seleção
            $relacionamentosExistentes = [];
            if ($fornecedorId) {
                $this->criarTabelaProdutoFornecedorCodigos();

                // Verificar qual tabela usar (produtos ou itens)
                $stmtTest = $this->db->query("SHOW TABLES LIKE 'produtos'");
                $tabelaProdutos = ($stmtTest->rowCount() > 0) ? 'produtos' : 'itens';
                $campoProdutoId = ($tabelaProdutos === 'produtos') ? 'produto_id' : 'item_id';

                foreach ($itensXml as $index => $itemXml) {
                    $codigoFornecedor = $itemXml['codigo_produto'] ?? '';
                    $eanFornecedor = ($itemXml['ean'] && $itemXml['ean'] !== 'SEM GTIN') ? $itemXml['ean'] : '';

                    if (!empty($codigoFornecedor) || !empty($eanFornecedor)) {
                        // Buscar por código ou EAN
                        $sql = "
                            SELECT COALESCE(produto_id, item_id) as produto_id
                            FROM produto_fornecedor_codigos
                            WHERE company_id = :company_id
                            AND fornecedor_id = :fornecedor_id
                            AND (
                                codigo_fornecedor = :codigo_fornecedor
                                " . (!empty($eanFornecedor) ? "OR ean_fornecedor = :ean_fornecedor" : "") . "
                            )
                            LIMIT 1
                        ";

                        $params = [
                            'company_id' => $companyId,
                            'fornecedor_id' => $fornecedorId,
                            'codigo_fornecedor' => $codigoFornecedor
                        ];

                        if (!empty($eanFornecedor)) {
                            $params['ean_fornecedor'] = $eanFornecedor;
                        }

                        $stmt = $this->db->prepare($sql);
                        $stmt->execute($params);
                        $relacionamento = $stmt->fetch();

                        if ($relacionamento && !empty($relacionamento['produto_id'])) {
                            $relacionamentosExistentes[$index] = (int) $relacionamento['produto_id'];
                        }
                    }
                }
            }

            // Verificar se todos os itens já têm relacionamento
            $totalItens = count($itensXml);
            $totalRelacionados = count($relacionamentosExistentes);

            error_log("🔍 Verificação de relacionamentos: {$totalRelacionados}/{$totalItens} itens já relacionados");

            // Se todos os itens já têm relacionamento, processar automaticamente
            if ($totalItens > 0 && $totalRelacionados === $totalItens) {
                error_log("✅ Todos os produtos já têm relacionamento. Processando automaticamente...");

                // Simular POST para salvar relacionamento
                // Criar array de relacionamentos no formato esperado pelo método salvarRelacionamentoProdutos
                $relacionamentosArray = [];
                foreach ($relacionamentosExistentes as $index => $produtoId) {
                    $relacionamentosArray[$index] = $produtoId;
                }

                // Processar relacionamento automaticamente sem mostrar tela
                // Usar $_POST temporariamente para simular o POST
                $postOriginal = $_POST;

                // Verificar se é requisição GET (redirect) ou POST (AJAX)
                $isGet = $_SERVER['REQUEST_METHOD'] === 'GET';

                if ($isGet) {
                    // Se for GET, fazer redirect para uma URL que processa via POST interno
                    // Usar um parâmetro especial para indicar processamento automático
                    $redirectUrl = url('/compras/salvar-relacionamento-produtos') . '?auto_processar=1&compra_id=' . $compraId;

                    // Codificar relacionamentos na URL ou usar sessão temporária
                    // Melhor: fazer redirect para uma página que processa e redireciona
                    error_log("🔄 Redirecionando para processamento automático: {$redirectUrl}");

                    // Por enquanto, vamos fazer o processamento direto aqui mesmo
                    // Modificar temporariamente $_POST para simular POST
                    $postOriginal = $_POST;
                    $_POST['compra_id'] = $compraId;
                    $_POST['relacionamentos'] = $relacionamentosArray;

                    try {
                        // Processar usando a mesma lógica mas sem retornar JSON
                        $this->processarRelacionamentoInterno($compraId, $relacionamentosArray, $companyId);

                        // Restaurar POST
                        $_POST = $postOriginal;

                        // Redirect para compra
                        header('Location: ' . url('/compras/editar?id=' . $compraId) . '&msg=processado_automaticamente');
                        exit;
                    } catch (Exception $e) {
                        error_log("❌ Erro ao processar relacionamento automático: " . $e->getMessage());
                        $_POST = $postOriginal;
                        // Continuar e mostrar tela normalmente em caso de erro
                    }
                } else {
                    // Se for POST/AJAX, processar normalmente
                    $postOriginal = $_POST;
                    $_POST['compra_id'] = $compraId;
                    $_POST['relacionamentos'] = $relacionamentosArray;

                    try {
                        $this->salvarRelacionamentoProdutos();
                        $_POST = $postOriginal;
                        return;
                    } catch (Exception $e) {
                        error_log("Erro ao processar relacionamento automático: " . $e->getMessage());
                        $_POST = $postOriginal ?? [];
                    }
                }
            }

            // Se não todos estão relacionados, mostrar tela normal
            $this->view('compras/relacionar-produtos-xml', [
                'compra' => $compra,
                'fornecedor' => $fornecedor,
                'itens_xml' => $itensXml,
                'produtos' => $produtos,
                'relacionamentos_existentes' => $relacionamentosExistentes
            ]);
        } catch (Exception $e) {
            error_log("Erro ao carregar tela de relacionamento: " . $e->getMessage());
            $this->error('Erro ao carregar tela de relacionamento: ' . $e->getMessage());
        }
    }

    /**
     * Processa relacionamento internamente sem retornar JSON (usado para processamento automático)
     * Reutiliza a mesma lógica do salvarRelacionamentoProdutos mas sem chamar success()
     */
    private function processarRelacionamentoInterno(int $compraId, array $relacionamentos, int $companyId): void
    {
        // Usar a mesma lógica do método salvarRelacionamentoProdutos
        // Mas chamar diretamente a parte de processamento sem passar pelo método público
        // que retorna JSON

        // Buscar compra
        $stmt = $this->db->prepare("SELECT * FROM compras WHERE id = :id AND company_id = :company_id LIMIT 1");
        $stmt->execute(['id' => $compraId, 'company_id' => $companyId]);
        $compra = $stmt->fetch();

        if (!$compra) {
            throw new Exception('Compra não encontrada');
        }

        // Buscar XML
        $xmlCompleto = null;
        if (isset($compra['xml_completo']) && !empty($compra['xml_completo'])) {
            $xmlCompleto = $compra['xml_completo'];
        } elseif (isset($compra['chave_nfe']) && !empty($compra['chave_nfe'])) {
            $stmt = $this->db->prepare("SELECT xml_completo FROM nfe_recebidas WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
            $stmt->execute(['chave_nfe' => $compra['chave_nfe'], 'company_id' => $companyId]);
            $nfe = $stmt->fetch();
            if ($nfe && !empty($nfe['xml_completo'])) {
                $xmlCompleto = $nfe['xml_completo'];
            }
        }

        if (empty($xmlCompleto)) {
            throw new Exception('XML da NF-e não encontrado');
        }

        // Extrair itens do XML
        libxml_use_internal_errors(true);
        $xml = simplexml_load_string($xmlCompleto);
        if ($xml === false) {
            throw new Exception('Erro ao processar XML');
        }

        // Usar flag global para evitar que success() retorne JSON
        $GLOBALS['__skip_success_response'] = true;

        try {
            // Chamar método de salvamento - ele já faz beginTransaction, processamento e commit
            // Mas não vai retornar JSON devido ao flag
            $this->salvarRelacionamentoProdutos();

            // Se chegou aqui, o processamento foi feito com sucesso
        } finally {
            // Limpar flag
            unset($GLOBALS['__skip_success_response']);
        }
    }

    /**
     * Salva relacionamento de produtos e insere itens na compra
     */
    public function salvarRelacionamentoProdutos(): void
    {
        try {
            $compraId = (int) $this->request->post('compra_id');
            $relacionamentos = $this->request->post('relacionamentos', []);
            $companyId = $this->getCompanyId();

            if (empty($compraId)) {
                $this->error('ID da compra não informado');
                return;
            }

            if (empty($relacionamentos)) {
                $this->error('Nenhum relacionamento informado');
                return;
            }

            // Verificar compra
            $stmt = $this->db->prepare("SELECT * FROM compras WHERE id = :id AND company_id = :company_id LIMIT 1");
            $stmt->execute(['id' => $compraId, 'company_id' => $companyId]);
            $compra = $stmt->fetch();

            if (!$compra) {
                $this->error('Compra não encontrada');
                return;
            }

            // Buscar XML para extrair dados completos dos itens
            $xmlCompleto = null;
            if (isset($compra['xml_completo']) && !empty($compra['xml_completo'])) {
                $xmlCompleto = $compra['xml_completo'];
            } elseif (isset($compra['chave_nfe']) && !empty($compra['chave_nfe'])) {
                $stmt = $this->db->prepare("SELECT xml_completo FROM nfe_recebidas WHERE chave_nfe = :chave_nfe AND company_id = :company_id LIMIT 1");
                $stmt->execute(['chave_nfe' => $compra['chave_nfe'], 'company_id' => $companyId]);
                $nfe = $stmt->fetch();
                if ($nfe && !empty($nfe['xml_completo'])) {
                    $xmlCompleto = $nfe['xml_completo'];
                }
            }

            if (empty($xmlCompleto)) {
                $this->error('XML da NF-e não encontrado');
                return;
            }

            // Extrair itens do XML
            libxml_use_internal_errors(true);
            $xml = simplexml_load_string($xmlCompleto);
            if ($xml === false) {
                throw new Exception('Erro ao processar XML');
            }

            $nfeData = $this->extrairDadosNFe($xml);
            $itensXml = $nfeData['itens'] ?? [];

            $this->db->beginTransaction();

            // Criar tabela de relacionamento se não existir
            $this->criarTabelaProdutoFornecedorCodigos();

            // Verificar qual tabela usar (produtos ou itens)
            $stmtTest = $this->db->query("SHOW TABLES LIKE 'produtos'");
            $tabelaProdutos = ($stmtTest->rowCount() > 0) ? 'produtos' : 'itens';
            $campoProdutoId = ($tabelaProdutos === 'produtos') ? 'produto_id' : 'item_id';
            $campoOposto = ($tabelaProdutos === 'produtos') ? 'item_id' : 'produto_id';

            $fornecedorId = !empty($compra['fornecedor_id']) ? (int) $compra['fornecedor_id'] : null;

            $itensInseridos = 0;
            $totalCompra = 0;

            // Buscar todos os elementos <det> do XML para extrair dados fiscais
            $nfeNs = 'http://www.portalfiscal.inf.br/nfe';
            $xml->registerXPathNamespace('nfe', $nfeNs);
            $dets = $xml->xpath('//det') ?: $xml->xpath('//nfe:det') ?: [];

            foreach ($relacionamentos as $indexXml => $produtoId) {
                if (empty($produtoId) || $produtoId === 'null' || $produtoId === '0') {
                    continue; // Pular itens sem relacionamento
                }

                if (!isset($itensXml[$indexXml])) {
                    continue;
                }

                $itemXml = $itensXml[$indexXml];
                $produtoId = (int) $produtoId;

                // Obter o elemento <det> correspondente para extrair dados fiscais
                $det = isset($dets[$indexXml]) ? $dets[$indexXml] : null;

                // Se não encontrou pelo índice, tentar buscar pelo número do item
                if (!$det && isset($itemXml['numero_item'])) {
                    foreach ($dets as $d) {
                        $nItem = (string) ($d->attributes()->nItem ?? '');
                        if ($nItem == $itemXml['numero_item']) {
                            $det = $d;
                            break;
                        }
                    }
                }

                // Salvar relacionamento na tabela auxiliar
                if ($fornecedorId && (!empty($itemXml['codigo_produto']) || !empty($itemXml['ean']))) {
                    $codigoFornecedor = $itemXml['codigo_produto'] ?? '';
                    $eanFornecedor = ($itemXml['ean'] && $itemXml['ean'] !== 'SEM GTIN') ? $itemXml['ean'] : null;

                    if (!empty($codigoFornecedor)) {
                        // Verificar se já existe relacionamento
                        $sqlCheck = "
                            SELECT id FROM produto_fornecedor_codigos
                            WHERE company_id = :company_id
                            AND {$campoProdutoId} = :produto_id
                            AND {$campoOposto} IS NULL
                            AND fornecedor_id = :fornecedor_id
                            AND codigo_fornecedor = :codigo_fornecedor
                            LIMIT 1
                        ";

                        $stmtCheck = $this->db->prepare($sqlCheck);
                        $stmtCheck->execute([
                            'company_id' => $companyId,
                            'produto_id' => $produtoId,
                            'fornecedor_id' => $fornecedorId,
                            'codigo_fornecedor' => $codigoFornecedor
                        ]);

                        $existe = $stmtCheck->fetch();

                        if (!$existe) {
                            // Inserir relacionamento
                            $sqlInsert = "
                                INSERT INTO produto_fornecedor_codigos
                                (company_id, {$campoProdutoId}, {$campoOposto}, fornecedor_id, codigo_fornecedor, ean_fornecedor, created_at, updated_at)
                                VALUES
                                (:company_id, :produto_id, NULL, :fornecedor_id, :codigo_fornecedor, :ean_fornecedor, NOW(), NOW())
                            ";

                            $stmtInsert = $this->db->prepare($sqlInsert);
                            $stmtInsert->execute([
                                'company_id' => $companyId,
                                'produto_id' => $produtoId,
                                'fornecedor_id' => $fornecedorId,
                                'codigo_fornecedor' => $codigoFornecedor,
                                'ean_fornecedor' => $eanFornecedor
                            ]);

                            error_log("✅ Relacionamento salvo: Produto ID {$produtoId} <-> Fornecedor ID {$fornecedorId} (Código: {$codigoFornecedor})");
                        } else {
                            // Atualizar EAN se necessário
                            if (!empty($eanFornecedor)) {
                                $sqlUpdate = "
                                    UPDATE produto_fornecedor_codigos
                                    SET ean_fornecedor = :ean_fornecedor, updated_at = NOW()
                                    WHERE id = :id
                                ";
                                $stmtUpdate = $this->db->prepare($sqlUpdate);
                                $stmtUpdate->execute([
                                    'ean_fornecedor' => $eanFornecedor,
                                    'id' => $existe['id']
                                ]);
                            }
                        }
                    }
                }

                // Buscar dados do produto para preencher item_name e item_code
                // Verificar estrutura da tabela para saber qual coluna usar
                $stmtCheckProd = $this->db->query("SHOW COLUMNS FROM {$tabelaProdutos}");
                $columnsProd = $stmtCheckProd->fetchAll();
                $columnNamesProd = array_column($columnsProd, 'Field');

                $codeColumn = 'sku';
                if (in_array('code', $columnNamesProd)) {
                    $codeColumn = 'code';
                } elseif (in_array('sku', $columnNamesProd)) {
                    $codeColumn = 'sku';
                }

                $stmtProduto = $this->db->prepare("SELECT name, {$codeColumn} as code FROM {$tabelaProdutos} WHERE id = :id AND company_id = :company_id LIMIT 1");
                $stmtProduto->execute(['id' => $produtoId, 'company_id' => $companyId]);
                $produto = $stmtProduto->fetch();

                // Extrair dados fiscais do XML (impostos)
                $imposto = $det->imposto ?? $det->children($nfeNs)->imposto ?? null;
                $icms = null;
                $pis = null;
                $cofins = null;
                $ipi = null;

                if ($imposto) {
                    $icms = $imposto->ICMS ?? $imposto->children($nfeNs)->ICMS ?? null;
                    if ($icms) {
                        $icmsGrupo = $icms->ICMS00 ?? $icms->ICMS10 ?? $icms->ICMS20 ?? $icms->ICMS30 ??
                            $icms->ICMS40 ?? $icms->ICMS51 ?? $icms->ICMS60 ?? $icms->ICMS70 ??
                            $icms->ICMS90 ?? $icms->children($nfeNs)->ICMS00 ?? null;
                        if ($icmsGrupo) {
                            $itemXml['cst_icms'] = (string) ($icmsGrupo->CST ?? $icmsGrupo->CSOSN ?? '');
                            $itemXml['aliquota_icms'] = (float) ($icmsGrupo->pICMS ?? 0);
                            $itemXml['valor_icms'] = (float) ($icmsGrupo->vICMS ?? 0);
                        }
                    }

                    $pis = $imposto->PIS ?? $imposto->children($nfeNs)->PIS ?? null;
                    if ($pis) {
                        $pisGrupo = $pis->PISAliq ?? $pis->PISQtde ?? $pis->PISNT ?? $pis->PISOutr ??
                            $pis->children($nfeNs)->PISAliq ?? null;
                        if ($pisGrupo) {
                            $itemXml['cst_pis'] = (string) ($pisGrupo->CST ?? '');
                            $itemXml['aliquota_pis'] = (float) ($pisGrupo->pPIS ?? 0);
                            $itemXml['valor_pis'] = (float) ($pisGrupo->vPIS ?? 0);
                        }
                    }

                    $cofins = $imposto->COFINS ?? $imposto->children($nfeNs)->COFINS ?? null;
                    if ($cofins) {
                        $cofinsGrupo = $cofins->COFINSAliq ?? $cofins->COFINSQtde ?? $cofins->COFINSNT ?? $cofins->COFINSOutr ??
                            $cofins->children($nfeNs)->COFINSAliq ?? null;
                        if ($cofinsGrupo) {
                            $itemXml['cst_cofins'] = (string) ($cofinsGrupo->CST ?? '');
                            $itemXml['aliquota_cofins'] = (float) ($cofinsGrupo->pCOFINS ?? 0);
                            $itemXml['valor_cofins'] = (float) ($cofinsGrupo->vCOFINS ?? 0);
                        }
                    }

                    $ipi = $imposto->IPI ?? $imposto->children($nfeNs)->IPI ?? null;
                    if ($ipi) {
                        $ipiGrupo = $ipi->IPITrib ?? $ipi->IPINT ?? $ipi->children($nfeNs)->IPITrib ?? null;
                        if ($ipiGrupo) {
                            $itemXml['cst_ipi'] = (string) ($ipiGrupo->CST ?? '');
                            $itemXml['aliquota_ipi'] = (float) ($ipiGrupo->pIPI ?? 0);
                            $itemXml['valor_ipi'] = (float) ($ipiGrupo->vIPI ?? 0);
                        }
                    }
                }

                // Verificar estrutura da tabela compra_itens
                $stmtCheck = $this->db->query("SHOW COLUMNS FROM compra_itens");
                $columns = $stmtCheck->fetchAll();
                $columnNames = array_column($columns, 'Field');

                // Campos obrigatórios
                $campos = ['compra_id', 'company_id', 'quantity', 'unit_price', 'total', 'created_at'];
                $valores = [':compra_id', ':company_id', ':quantity', ':unit_price', ':total', 'NOW()'];
                $dados = [
                    'compra_id' => $compraId,
                    'company_id' => $companyId,
                    'quantity' => $itemXml['quantidade'] ?? 0,
                    'unit_price' => $itemXml['valor_unitario'] ?? 0,
                    'total' => $itemXml['valor_total'] ?? 0
                ];

                // Verificar se usa item_id ou product_id
                if (in_array('product_id', $columnNames)) {
                    $campos[] = 'product_id';
                    $valores[] = ':product_id';
                    $dados['product_id'] = $produtoId;
                } elseif (in_array('item_id', $columnNames)) {
                    $campos[] = 'item_id';
                    $valores[] = ':item_id';
                    $dados['item_id'] = $produtoId;
                }

                // Campos do produto
                if (in_array('item_name', $columnNames)) {
                    $campos[] = 'item_name';
                    $valores[] = ':item_name';
                    $dados['item_name'] = $produto['name'] ?? $itemXml['nome'] ?? '';
                }

                if (in_array('item_code', $columnNames)) {
                    $campos[] = 'item_code';
                    $valores[] = ':item_code';
                    $dados['item_code'] = $produto['sku'] ?? $produto['code'] ?? $itemXml['codigo_produto'] ?? '';
                }

                if (in_array('unit', $columnNames)) {
                    $campos[] = 'unit';
                    $valores[] = ':unit';
                    $dados['unit'] = $itemXml['unidade'] ?? 'UN';
                }

                if (in_array('discount', $columnNames)) {
                    $campos[] = 'discount';
                    $valores[] = ':discount';
                    $dados['discount'] = 0;
                }

                if (in_array('discount_type', $columnNames)) {
                    $campos[] = 'discount_type';
                    $valores[] = ':discount_type';
                    $dados['discount_type'] = 'percent';
                }

                // Campos fiscais
                if (in_array('ncm', $columnNames)) {
                    $campos[] = 'ncm';
                    $valores[] = ':ncm';
                    $dados['ncm'] = $itemXml['ncm'] ?? '';
                }

                if (in_array('cest', $columnNames)) {
                    $campos[] = 'cest';
                    $valores[] = ':cest';
                    $dados['cest'] = '';
                }

                if (in_array('cfop', $columnNames)) {
                    $campos[] = 'cfop';
                    $valores[] = ':cfop';
                    $dados['cfop'] = $itemXml['cfop'] ?? '';
                }

                if (in_array('origem', $columnNames)) {
                    $campos[] = 'origem';
                    $valores[] = ':origem';
                    $dados['origem'] = '';
                }

                if (in_array('cst_icms', $columnNames)) {
                    $campos[] = 'cst_icms';
                    $valores[] = ':cst_icms';
                    $dados['cst_icms'] = $itemXml['cst_icms'] ?? '';
                }

                if (in_array('aliquota_icms', $columnNames)) {
                    $campos[] = 'aliquota_icms';
                    $valores[] = ':aliquota_icms';
                    $dados['aliquota_icms'] = $itemXml['aliquota_icms'] ?? 0;
                }

                if (in_array('valor_icms', $columnNames)) {
                    $campos[] = 'valor_icms';
                    $valores[] = ':valor_icms';
                    $dados['valor_icms'] = $itemXml['valor_icms'] ?? 0;
                }

                if (in_array('cst_pis', $columnNames)) {
                    $campos[] = 'cst_pis';
                    $valores[] = ':cst_pis';
                    $dados['cst_pis'] = $itemXml['cst_pis'] ?? '';
                }

                if (in_array('aliquota_pis', $columnNames)) {
                    $campos[] = 'aliquota_pis';
                    $valores[] = ':aliquota_pis';
                    $dados['aliquota_pis'] = $itemXml['aliquota_pis'] ?? 0;
                }

                if (in_array('valor_pis', $columnNames)) {
                    $campos[] = 'valor_pis';
                    $valores[] = ':valor_pis';
                    $dados['valor_pis'] = $itemXml['valor_pis'] ?? 0;
                }

                if (in_array('cst_cofins', $columnNames)) {
                    $campos[] = 'cst_cofins';
                    $valores[] = ':cst_cofins';
                    $dados['cst_cofins'] = $itemXml['cst_cofins'] ?? '';
                }

                if (in_array('aliquota_cofins', $columnNames)) {
                    $campos[] = 'aliquota_cofins';
                    $valores[] = ':aliquota_cofins';
                    $dados['aliquota_cofins'] = $itemXml['aliquota_cofins'] ?? 0;
                }

                if (in_array('valor_cofins', $columnNames)) {
                    $campos[] = 'valor_cofins';
                    $valores[] = ':valor_cofins';
                    $dados['valor_cofins'] = $itemXml['valor_cofins'] ?? 0;
                }

                if (in_array('cst_ipi', $columnNames)) {
                    $campos[] = 'cst_ipi';
                    $valores[] = ':cst_ipi';
                    $dados['cst_ipi'] = $itemXml['cst_ipi'] ?? '';
                }

                if (in_array('aliquota_ipi', $columnNames)) {
                    $campos[] = 'aliquota_ipi';
                    $valores[] = ':aliquota_ipi';
                    $dados['aliquota_ipi'] = $itemXml['aliquota_ipi'] ?? 0;
                }

                if (in_array('valor_ipi', $columnNames)) {
                    $campos[] = 'valor_ipi';
                    $valores[] = ':valor_ipi';
                    $dados['valor_ipi'] = $itemXml['valor_ipi'] ?? 0;
                }

                if (in_array('notes', $columnNames)) {
                    $campos[] = 'notes';
                    $valores[] = ':notes';
                    $dados['notes'] = '';
                }

                // Campos de lote
                if (in_array('lote', $columnNames) && !empty($itemXml['lotes'])) {
                    $campos[] = 'lote';
                    $valores[] = ':lote';
                    $dados['lote'] = $itemXml['lotes'][0]['numero'] ?? '';
                }

                if (in_array('data_fabricacao', $columnNames) && !empty($itemXml['lotes'])) {
                    $dataFab = $itemXml['lotes'][0]['data_fabricacao'] ?? '';
                    if (!empty($dataFab)) {
                        $campos[] = 'data_fabricacao';
                        $valores[] = ':data_fabricacao';
                        $dados['data_fabricacao'] = date('Y-m-d', strtotime($dataFab));
                    }
                }

                if (in_array('data_validade', $columnNames) && !empty($itemXml['lotes'])) {
                    $dataVal = $itemXml['lotes'][0]['data_validade'] ?? '';
                    if (!empty($dataVal)) {
                        $campos[] = 'data_validade';
                        $valores[] = ':data_validade';
                        $dados['data_validade'] = date('Y-m-d', strtotime($dataVal));
                    }
                }

                // Construir SQL de forma segura
                $camposFinais = [];
                $valoresFinais = [];
                $dadosFinais = [];

                for ($i = 0; $i < count($campos); $i++) {
                    $campo = $campos[$i];
                    $valor = $valores[$i];

                    if (strpos($valor, ':') === 0) {
                        $placeholder = substr($valor, 1);
                        if (array_key_exists($placeholder, $dados)) {
                            $camposFinais[] = $campo;
                            $valoresFinais[] = $valor;
                            $dadosFinais[$placeholder] = $dados[$placeholder];
                        }
                    } else {
                        $camposFinais[] = $campo;
                        $valoresFinais[] = $valor;
                    }
                }

                $sql = "INSERT INTO compra_itens (" . implode(', ', $camposFinais) . ") VALUES (" . implode(', ', $valoresFinais) . ")";
                $stmt = $this->db->prepare($sql);
                $stmt->execute($dadosFinais);
                $itensInseridos++;
                $totalCompra += $itemXml['valor_total'] ?? 0;
            }

            // Atualizar total da compra
            $stmt = $this->db->prepare("UPDATE compras SET total = :total WHERE id = :id AND company_id = :company_id");
            $stmt->execute([
                'total' => $totalCompra,
                'id' => $compraId,
                'company_id' => $companyId
            ]);

            $this->db->commit();

            $this->success("{$itensInseridos} item(ns) adicionado(s) à compra com sucesso!", [
                'compra_id' => $compraId,
                'itens_inseridos' => $itensInseridos
            ]);
        } catch (Exception $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }
            error_log("Erro ao salvar relacionamento: " . $e->getMessage());
            $this->error('Erro ao salvar relacionamento: ' . $e->getMessage());
        }
    }

    /**
     * Insere itens da compra
     */
    private function inserirItensCompra(int $compraId, array $produtosMap, int $companyId): void
    {
        error_log("5. Inserindo itens da compra #{$compraId}...");
        error_log("   Total de itens a inserir: " . count($produtosMap));

        if (empty($produtosMap)) {
            error_log("   ⚠️ AVISO: Array de produtos vazio!");
            return;
        }

        // Verificar se a tabela compra_itens existe
        try {
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM compra_itens");
            $columns = $stmtCheck->fetchAll();
            $columnNames = array_column($columns, 'Field');
            error_log("   ✅ Tabela compra_itens encontrada");
            error_log("   Colunas disponíveis: " . implode(', ', $columnNames));
        } catch (Exception $e) {
            error_log("   ❌ ERRO: Tabela compra_itens não existe: " . $e->getMessage());
            throw new Exception("Tabela compra_itens não existe no banco de dados");
        }

        $itensInseridos = 0;
        foreach ($produtosMap as $index => $map) {
            $produtoId = $map['produto_id'];
            $item = $map['item'];

            error_log("   Inserindo item " . ($index + 1) . ": Produto ID {$produtoId}, Qtd: {$item['quantidade']}, Valor: {$item['valor_total']}");

            $campos = ['compra_id', 'company_id', 'product_id', 'quantity', 'unit_price', 'total', 'created_at'];
            $valores = [':compra_id', ':company_id', ':product_id', ':quantity', ':unit_price', ':total', 'NOW()'];

            $dados = [
                'compra_id' => $compraId,
                'company_id' => $companyId,
                'product_id' => $produtoId,
                'quantity' => $item['quantidade'],
                'unit_price' => $item['valor_unitario'],
                'total' => $item['valor_total']
            ];

            // Verificar se usa item_id ou product_id
            if (!in_array('product_id', $columnNames) && in_array('item_id', $columnNames)) {
                $campos = array_map(function ($campo) {
                    return $campo === 'product_id' ? 'item_id' : $campo;
                }, $campos);
                $valores = array_map(function ($valor) {
                    return $valor === ':product_id' ? ':item_id' : $valor;
                }, $valores);
                $dados['item_id'] = $produtoId;
                unset($dados['product_id']);
                error_log("     Usando item_id em vez de product_id");
            }

            // Lote (se usar lote)
            if (in_array('lote', $columnNames) && !empty($item['lotes'])) {
                $campos[] = 'lote';
                $valores[] = ':lote';
                $dados['lote'] = $item['lotes'][0]['numero'] ?? '';
            }

            if (in_array('data_fabricacao', $columnNames) && !empty($item['lotes'])) {
                $dataFab = $item['lotes'][0]['data_fabricacao'] ?? '';
                if (!empty($dataFab)) {
                    $campos[] = 'data_fabricacao';
                    $valores[] = ':data_fabricacao';
                    $dados['data_fabricacao'] = date('Y-m-d', strtotime($dataFab));
                }
            }

            if (in_array('data_validade', $columnNames) && !empty($item['lotes'])) {
                $dataVal = $item['lotes'][0]['data_validade'] ?? '';
                if (!empty($dataVal)) {
                    $campos[] = 'data_validade';
                    $valores[] = ':data_validade';
                    $dados['data_validade'] = date('Y-m-d', strtotime($dataVal));
                }
            }

            // Construir SQL e dados de forma segura - garantir sincronização perfeita
            $camposFinais = [];
            $valoresFinais = [];
            $dadosFinais = [];

            // Validação inicial: garantir que arrays têm o mesmo tamanho
            if (count($campos) !== count($valores)) {
                throw new Exception("Erro interno: arrays de campos e valores têm tamanhos diferentes. Campos: " . count($campos) . ", Valores: " . count($valores));
            }

            // Iterar pelos campos e valores de forma sincronizada
            for ($i = 0; $i < count($campos); $i++) {
                $campo = $campos[$i];
                $valor = $valores[$i];

                if (strpos($valor, ':') === 0) {
                    // É um placeholder
                    $placeholder = substr($valor, 1);
                    // Verificar se o placeholder existe em $dados (mesmo que seja NULL)
                    // array_key_exists permite NULL, isset() não
                    if (array_key_exists($placeholder, $dados)) {
                        $camposFinais[] = $campo;
                        $valoresFinais[] = $valor;
                        $dadosFinais[$placeholder] = $dados[$placeholder];
                    } else {
                        // Placeholder não tem valor - isso causaria HY093, então não adicionamos
                        error_log("     ⚠️ Placeholder :{$placeholder} não encontrado em \$dados, pulando campo {$campo}");
                    }
                } else {
                    // É um valor literal (como NOW())
                    $camposFinais[] = $campo;
                    $valoresFinais[] = $valor;
                }
            }

            // Validação final: garantir que todos os placeholders na SQL têm valores
            preg_match_all('/:(\w+)/', implode(' ', $valoresFinais), $matches);
            $placeholdersNaQuery = $matches[1] ?? [];

            // Verificar placeholders duplicados (pode causar HY093)
            $placeholdersCount = array_count_values($placeholdersNaQuery);
            $duplicados = array_filter($placeholdersCount, function ($count) {
                return $count > 1;
            });
            if (!empty($duplicados)) {
                $errorMsg = "Placeholders duplicados na query: " . implode(', ', array_keys($duplicados));
                error_log("     ❌ ERRO: {$errorMsg}");
                throw new Exception($errorMsg);
            }

            $placeholdersSemValor = array_diff($placeholdersNaQuery, array_keys($dadosFinais));

            if (!empty($placeholdersSemValor)) {
                $errorMsg = "Placeholders na query sem valores: " . implode(', ', $placeholdersSemValor);
                error_log("     ❌ ERRO: {$errorMsg}");
                error_log("     Campos finais: " . implode(', ', $camposFinais));
                error_log("     Valores finais: " . implode(', ', $valoresFinais));
                error_log("     Dados disponíveis: " . implode(', ', array_keys($dados)));
                throw new Exception($errorMsg);
            }

            // Validação extra: garantir que não há dados sem placeholders
            $dadosSemPlaceholder = array_diff(array_keys($dadosFinais), $placeholdersNaQuery);
            if (!empty($dadosSemPlaceholder)) {
                error_log("     ⚠️ AVISO: Dados sem placeholders na query (serão ignorados): " . implode(', ', $dadosSemPlaceholder));
            }

            $sql = "INSERT INTO compra_itens (" . implode(', ', $camposFinais) . ") VALUES (" . implode(', ', $valoresFinais) . ")";

            // Preparar dados para execute() - garantir que chaves não tenham ':' e valores são válidos
            $dadosParaExecute = [];
            foreach ($dadosFinais as $key => $value) {
                // Remover ':' se existir no início da chave (PDO não aceita ':' nas chaves)
                $cleanKey = (strpos($key, ':') === 0) ? substr($key, 1) : $key;
                // PDO aceita NULL, então manter NULL se for o valor
                $dadosParaExecute[$cleanKey] = $value;
            }

            // Validação crítica: contar placeholders na SQL vs parâmetros
            $countPlaceholders = count($placeholdersNaQuery);
            $countParams = count($dadosParaExecute);
            if ($countPlaceholders !== $countParams) {
                $errorMsg = "CRÍTICO: Contagem não corresponde! Placeholders: {$countPlaceholders}, Parâmetros: {$countParams}";
                error_log("     ❌ {$errorMsg}");
                error_log("     Placeholders: " . implode(', ', $placeholdersNaQuery));
                error_log("     Parâmetros: " . implode(', ', array_keys($dadosParaExecute)));
                throw new Exception($errorMsg);
            }

            $logMsg = "     SQL: {$sql}\n     Dados (original): " . json_encode($dadosFinais) . "\n     Dados para execute: " . json_encode($dadosParaExecute) . "\n     Placeholders: " . implode(', ', $placeholdersNaQuery);
            error_log($logMsg);
            $this->logToFile($logMsg, 'compras-importacao-nfe.log');

            try {
                $stmt = $this->db->prepare($sql);
                $stmt->execute($dadosParaExecute);
                $itensInseridos++;
                error_log("     ✅ Item inserido com sucesso");
            } catch (Exception $e) {
                $errorMsg = $e->getMessage();
                $errorInfo = $this->db->errorInfo();

                $logDetails = [
                    "     ❌ ERRO ao inserir item: {$errorMsg}",
                    "     SQL Error Code: " . ($errorInfo[0] ?? 'N/A'),
                    "     SQL Error Message: " . ($errorInfo[2] ?? 'N/A'),
                    "     SQL: {$sql}",
                    "     Dados enviados: " . json_encode($dadosFinais),
                    "     Contagem placeholders na SQL: " . substr_count($sql, ':'),
                    "     Contagem dados: " . count($dadosFinais)
                ];

                // Verificar se é o erro de parâmetro inválido
                if (strpos($errorMsg, 'Invalid parameter number') !== false || strpos($errorMsg, 'HY093') !== false) {
                    preg_match_all('/:(\w+)/', $sql, $matches);
                    $logDetails[] = "     ⚠️ ERRO CONFIRMADO: Invalid parameter number (HY093)";
                    $logDetails[] = "     Placeholders na SQL: " . (isset($matches[1]) ? implode(', ', $matches[1]) : 'nenhum');
                    $logDetails[] = "     Chaves nos dados: " . implode(', ', array_keys($dadosFinais));
                }

                $logMessage = implode("\n", $logDetails);
                error_log($logMessage);
                $this->logToFile($logMessage, 'compras-importacao-nfe.log');

                throw $e;
            }
        }

        error_log("✅ Total de itens inseridos: {$itensInseridos} de " . count($produtosMap));
    }

    /**
     * Busca todas as empresas disponíveis para o seletor do monitor
     * Retorna apenas as empresas vinculadas ao usuário logado através da tabela empresas_users
     */
    private function getTodasEmpresasParaMonitor(): array
    {
        try {
            $userId = $this->getUserId();

            if (!$userId) {
                error_log("Monitor NF-e: Usuário não logado");
                return [];
            }

            // Verificar se a tabela empresas existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'empresas'");
            if ($stmt->rowCount() === 0) {
                error_log("Monitor NF-e: Tabela 'empresas' não existe");
                return [];
            }

            // Verificar se a tabela empresas_users existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'empresas_users'");
            $temTabelaEmpresasUsers = $stmt->rowCount() > 0;

            // Verificar se existe coluna 'ativo' ou 'status' na tabela empresas
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'ativo'");
            $temColunaAtivo = $stmtCheck->rowCount() > 0;

            $stmtCheck = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'status'");
            $temColunaStatus = $stmtCheck->rowCount() > 0;

            if ($temTabelaEmpresasUsers) {
                // Primeiro, tentar buscar empresas vinculadas ao usuário através de empresas_users
                $query = "
                    SELECT DISTINCT e.id, e.razao_social, e.nome_fantasia, e.cnpj
                    FROM empresas e
                    INNER JOIN empresas_users eu ON e.id = eu.empresa_id
                    WHERE eu.user_id = :user_id
                    ORDER BY e.razao_social ASC
                ";

                error_log("Monitor NF-e: Query empresas (com empresas_users): " . $query);
                error_log("Monitor NF-e: User ID: " . $userId);

                $stmt = $this->db->prepare($query);
                $stmt->execute(['user_id' => $userId]);
                $empresas = $stmt->fetchAll();

                // Se não encontrou empresas vinculadas, buscar todas as empresas (sem filtro de ativo/status)
                if (empty($empresas)) {
                    error_log("Monitor NF-e: Nenhuma empresa vinculada ao usuário, buscando todas as empresas");
                    $query = "
                        SELECT id, razao_social, nome_fantasia, cnpj
                        FROM empresas
                        ORDER BY razao_social ASC
                    ";

                    error_log("Monitor NF-e: Query empresas (fallback - todas): " . $query);
                    $stmt = $this->db->prepare($query);
                    $stmt->execute();
                    $empresas = $stmt->fetchAll();
                }
            } else {
                // Se não existe tabela empresas_users, buscar todas as empresas (comportamento antigo)
                error_log("Monitor NF-e: Tabela 'empresas_users' não existe, buscando todas as empresas");

                $query = "
                    SELECT id, razao_social, nome_fantasia, cnpj
                    FROM empresas
                    ORDER BY razao_social ASC
                ";

                error_log("Monitor NF-e: Query empresas (sem empresas_users): " . $query);
                $stmt = $this->db->prepare($query);
                $stmt->execute();
                $empresas = $stmt->fetchAll();
            }

            error_log("Monitor NF-e: Total de empresas encontradas: " . count($empresas));
            if (count($empresas) > 0) {
                error_log("Monitor NF-e: Primeira empresa: " . json_encode($empresas[0]));
            }

            return $empresas;
        } catch (Exception $e) {
            error_log("Erro ao buscar empresas para monitor: " . $e->getMessage());
            error_log("Stack trace: " . $e->getTraceAsString());
            return [];
        }
    }

    /**
     * Busca empresas vinculadas ao usuário logado
     * Retorna apenas as empresas vinculadas através da tabela empresas_users
     */
    private function getEmpresasVinculadasUsuario(): array
    {
        try {
            $userId = $this->getUserId();

            if (!$userId) {
                error_log("Compras: Usuário não logado");
                return [];
            }

            // Verificar se a tabela empresas existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'empresas'");
            if ($stmt->rowCount() === 0) {
                error_log("Compras: Tabela 'empresas' não existe");
                return [];
            }

            // Verificar se a tabela empresas_users existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'empresas_users'");
            $temTabelaEmpresasUsers = $stmt->rowCount() > 0;

            // Verificar se existe coluna 'ativo' ou 'status' na tabela empresas
            $stmtCheck = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'ativo'");
            $temColunaAtivo = $stmtCheck->rowCount() > 0;

            $stmtCheck = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'status'");
            $temColunaStatus = $stmtCheck->rowCount() > 0;

            if ($temTabelaEmpresasUsers) {
                // Buscar empresas vinculadas ao usuário através de empresas_users
                $query = "
                    SELECT DISTINCT e.id, e.razao_social, e.nome_fantasia, e.cnpj
                    FROM empresas e
                    INNER JOIN empresas_users eu ON e.id = eu.empresa_id
                    WHERE eu.user_id = :user_id
                ";

                // Adicionar filtro de ativo se existir
                if ($temColunaAtivo) {
                    $query .= " AND (e.ativo = 'Sim' OR e.ativo = 1 OR e.ativo = '1')";
                } elseif ($temColunaStatus) {
                    $query .= " AND (e.status = 'ativo' OR e.status = 1 OR e.status = '1')";
                }

                $query .= " ORDER BY e.razao_social ASC";

                $stmt = $this->db->prepare($query);
                $stmt->execute(['user_id' => $userId]);
                return $stmt->fetchAll();
            } else {
                // Se não existe tabela empresas_users, buscar todas as empresas (comportamento antigo)
                $query = "
                    SELECT id, razao_social, nome_fantasia, cnpj
                    FROM empresas
                ";

                // Adicionar filtro se existir coluna ativo ou status
                if ($temColunaAtivo) {
                    $query .= " WHERE ativo = 'Sim' OR ativo = 1 OR ativo = '1'";
                } elseif ($temColunaStatus) {
                    $query .= " WHERE status = 'ativo' OR status = 1 OR status = '1'";
                }

                $query .= " ORDER BY razao_social ASC";

                $stmt = $this->db->prepare($query);
                $stmt->execute();
                return $stmt->fetchAll();
            }
        } catch (Exception $e) {
            error_log("Erro ao buscar empresas vinculadas ao usuário: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Busca todas as empresas para o seletor
     */
    private function getTodasEmpresas(): array
    {
        try {
            // Verificar se a tabela empresas existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'empresas'");
            if ($stmt->rowCount() === 0) {
                return [];
            }

            $stmt = $this->db->prepare("
                SELECT id, razao_social, nome_fantasia, cnpj
                FROM empresas
                ORDER BY razao_social ASC
            ");
            $stmt->execute();
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar empresas: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Processa ações baseadas no status da compra
     */
    private function processarAcoesStatus(int $compraId, string $status, array $data, array $itens = [], ?string $statusAnterior = null): void
    {
        try {
            // Garantir que itens é um array
            $itens = is_array($itens) ? $itens : [];

            error_log("Compra #{$compraId}: Processando status '{$status}' com " . count($itens) . " itens");

            switch ($status) {
                case 'faturado':
                    $this->processarStatusFaturado($compraId, $data);
                    break;

                case 'aguardando_entrega':
                    error_log("Compra #{$compraId}: Chamando processarStatusAguardandoEntrega com " . count($itens) . " itens");
                    $this->processarStatusAguardandoEntrega($compraId, $itens);
                    break;

                case 'recebido':
                    error_log("Compra #{$compraId}: Chamando processarStatusRecebido com " . count($itens) . " itens");
                    $this->processarStatusRecebido($compraId, $itens);
                    break;

                case 'cancelado':
                    $this->processarStatusCancelado($compraId);
                    break;

                default:
                    // Orçamento - não faz nada
                    break;
            }
        } catch (Exception $e) {
            error_log("Compra #{$compraId}: Erro ao processar ações do status '{$status}': " . $e->getMessage());
            // Não relançar a exceção para não quebrar o fluxo principal
            // throw $e;
        }
    }

    /**
     * Processa status Faturado: Gera contas a Pagar
     */
    private function processarStatusFaturado(int $compraId, array $data): void
    {
        try {
            // Verificar se já existem contas geradas
            $stmt = $this->db->query("SHOW TABLES LIKE 'contas_pagar'");
            if ($stmt->rowCount() == 0) {
                error_log("Compra #{$compraId}: Tabela contas_pagar não existe");
                return;
            }

            $stmt = $this->db->prepare("
                SELECT COUNT(*) as total
                FROM contas_pagar
                WHERE compra_id = :compra_id
            ");
            $stmt->execute(['compra_id' => $compraId]);
            $contasExistentes = $stmt->fetch()['total'];

            if ($contasExistentes == 0 && $data['total'] > 0) {
                error_log("Compra #{$compraId}: Gerando contas a pagar (status: Faturado)");
                $this->gerarContasPagar($compraId, $data);
            } else {
                error_log("Compra #{$compraId}: Contas já existem ou total é zero - não gera");
            }
        } catch (Exception $e) {
            error_log("Compra #{$compraId}: Erro ao processar status Faturado: " . $e->getMessage());
            // Não relançar para não quebrar o fluxo principal
        }
    }

    /**
     * Processa status Aguardando Entrega: Popula estoque_movimentos.previsao com a quantidade do item
     */
    private function processarStatusAguardandoEntrega(int $compraId, array $itens): void
    {
        try {
            error_log("Compra #{$compraId}: INÍCIO processarStatusAguardandoEntrega - Total de itens: " . count($itens));
            $companyId = $this->getCompanyId();

            // Verificar se a tabela estoque_movimentos existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'estoque_movimentos'");
            if ($stmt->rowCount() == 0) {
                error_log("Compra #{$compraId}: Tabela estoque_movimentos não existe");
                return;
            }

            // Verificar se a coluna previsao existe
            $stmt = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'previsao'");
            $temPrevisao = $stmt->rowCount() > 0;

            if (!$temPrevisao) {
                error_log("Compra #{$compraId}: Coluna previsao não existe em estoque_movimentos");
                return;
            }

            if (empty($itens)) {
                error_log("Compra #{$compraId}: Nenhum item fornecido para processar");
                return;
            }

            foreach ($itens as $index => $item) {
                $itemId = $item['item_id'] ?? null;
                $quantity = (float) ($item['quantity'] ?? 0);

                error_log("Compra #{$compraId}: Processando item #{$index} - item_id: {$itemId}, quantity: {$quantity}");

                if (empty($itemId) || $quantity <= 0) {
                    error_log("Compra #{$compraId}: Item #{$index} ignorado - item_id vazio ou quantity <= 0");
                    continue;
                }

                // Verificar se já existe movimentação para este item e compra (usando product_id)
                $stmt = $this->db->prepare("
                    SELECT id FROM estoque_movimentos
                    WHERE company_id = :company_id
                      AND product_id = :product_id
                      AND reference_id = :reference_id
                      AND reference_type = 'compra'
                    LIMIT 1
                ");
                $stmt->execute([
                    'company_id' => $companyId,
                    'product_id' => $itemId,
                    'reference_id' => $compraId
                ]);
                $movimento = $stmt->fetch();

                if ($movimento) {
                    // Atualizar previsao existente
                    $stmt = $this->db->prepare("
                        UPDATE estoque_movimentos
                        SET previsao = :previsao
                        WHERE id = :id
                    ");
                    $stmt->execute([
                        'previsao' => $quantity,
                        'id' => $movimento['id']
                    ]);
                } else {
                    // Criar nova movimentação com previsao
                    error_log("Compra #{$compraId}: Criando NOVO registro de movimentação para item_id: {$itemId}, quantity: {$quantity}");
                    $stmtCols = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'created_by'");
                    $temCreatedBy = $stmtCols->rowCount() > 0;
                    $userId = $this->session->get('user_id');

                    // Criar nova movimentação com previsao usando product_id (estrutura correta)
                    error_log("Compra #{$compraId}: Criando NOVO registro de movimentação com previsão para product_id: {$itemId}, quantity: {$quantity}");

                    $stmt = $this->db->prepare("
                        INSERT INTO estoque_movimentos (
                            company_id, product_id, type, previsao,
                            reference_type, reference_id, created_at
                        ) VALUES (
                            :company_id, :product_id, 'entrada', :previsao,
                            'compra', :reference_id, NOW()
                        )
                    ");
                    $stmt->execute([
                        'company_id' => $companyId,
                        'product_id' => $itemId,
                        'previsao' => $quantity,
                        'reference_id' => $compraId
                    ]);
                    error_log("Compra #{$compraId}: ✅ Registro criado com sucesso - product_id: {$itemId}, previsão: {$quantity}");
                }

                error_log("Compra #{$compraId}: Item {$itemId} - Previsão atualizada: {$quantity}");
            }
        } catch (Exception $e) {
            error_log("Compra #{$compraId}: Erro ao processar status Aguardando Entrega: " . $e->getMessage());
            // Não relançar para não quebrar o fluxo principal
        }
    }

    /**
     * Processa status Recebido: Altera estoque_movimentos.previsao para 0 e popula estoque_movimentos.quantity com a quantidade do item
     */
    private function processarStatusRecebido(int $compraId, array $itens): void
    {
        try {
            error_log("Compra #{$compraId}: INÍCIO processarStatusRecebido - Total de itens: " . count($itens));
            $companyId = $this->getCompanyId();

            // Verificar se a tabela estoque_movimentos existe
            $stmt = $this->db->query("SHOW TABLES LIKE 'estoque_movimentos'");
            if ($stmt->rowCount() == 0) {
                error_log("Compra #{$compraId}: Tabela estoque_movimentos não existe");
                return;
            }

            // Verificar se as colunas existem
            $stmt = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'previsao'");
            $temPrevisao = $stmt->rowCount() > 0;
            $stmt = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'quantity'");
            $temQuantity = $stmt->rowCount() > 0;

            if (!$temPrevisao || !$temQuantity) {
                error_log("Compra #{$compraId}: Colunas previsao ou quantity não existem em estoque_movimentos");
                return;
            }

            if (empty($itens)) {
                error_log("Compra #{$compraId}: Nenhum item fornecido para processar");
                return;
            }

            foreach ($itens as $index => $item) {
                $itemId = $item['item_id'] ?? null;
                $quantity = (float) ($item['quantity'] ?? 0);

                error_log("Compra #{$compraId}: Processando item #{$index} - item_id: {$itemId}, quantity: {$quantity}");

                if (empty($itemId) || $quantity <= 0) {
                    error_log("Compra #{$compraId}: Item #{$index} ignorado - item_id vazio ou quantity <= 0");
                    continue;
                }

                // Buscar movimentação existente (usando product_id, não item_id)
                $stmt = $this->db->prepare("
                    SELECT id FROM estoque_movimentos
                    WHERE company_id = :company_id
                      AND product_id = :product_id
                      AND reference_id = :reference_id
                      AND reference_type = 'compra'
                    LIMIT 1
                ");
                $stmt->execute([
                    'company_id' => $companyId,
                    'product_id' => $itemId,
                    'reference_id' => $compraId
                ]);
                $movimento = $stmt->fetch();

                if ($movimento) {
                    // Atualizar: previsao = 0, quantity = quantidade do item
                    $stmt = $this->db->prepare("
                        UPDATE estoque_movimentos
                        SET previsao = 0, quantity = :quantity
                        WHERE id = :id
                    ");
                    $stmt->execute([
                        'quantity' => $quantity,
                        'id' => $movimento['id']
                    ]);

                    // Atualizar estoque do produto
                    $stmtUpdate = $this->db->prepare("
                        UPDATE produtos SET stock_quantity = stock_quantity + :quantity
                        WHERE id = :id AND company_id = :company_id
                    ");
                    $stmtUpdate->execute([
                        'quantity' => $quantity,
                        'id' => $itemId,
                        'company_id' => $companyId
                    ]);

                    error_log("Compra #{$compraId}: Item {$itemId} - Previsão zerada, quantity atualizado: {$quantity}, estoque atualizado");
                } else {
                    // Criar novo registro se não existir
                    error_log("Compra #{$compraId}: Movimentação não encontrada para item {$itemId}, criando NOVO registro de entrada no estoque");

                    // Usar product_id (estrutura correta da tabela)
                    $stmt = $this->db->prepare("
                        INSERT INTO estoque_movimentos (
                            company_id, product_id, type, previsao, quantity,
                            reference_type, reference_id, created_at
                        ) VALUES (
                            :company_id, :product_id, 'entrada', 0, :quantity,
                            'compra', :reference_id, NOW()
                        )
                    ");
                    $stmt->execute([
                        'company_id' => $companyId,
                        'product_id' => $itemId,
                        'quantity' => $quantity,
                        'reference_id' => $compraId
                    ]);
                    error_log("Compra #{$compraId}: ✅ Novo registro de movimentação criado - product_id: {$itemId}, quantity: {$quantity}");

                    // Atualizar estoque do produto
                    $stmtUpdate = $this->db->prepare("
                        UPDATE produtos SET stock_quantity = stock_quantity + :quantity
                        WHERE id = :id AND company_id = :company_id
                    ");
                    $stmtUpdate->execute([
                        'quantity' => $quantity,
                        'id' => $itemId,
                        'company_id' => $companyId
                    ]);

                    error_log("Compra #{$compraId}: Item {$itemId} - Novo registro criado com quantity: {$quantity}, estoque atualizado");
                }
            }
        } catch (Exception $e) {
            error_log("Compra #{$compraId}: Erro ao processar status Recebido: " . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Processa status Cancelado: Deleta o registro de estoque onde estoque_movimentos.reference_id = compras.id
     * e faz update em contas_pagar.status para cancelado
     */
    private function processarStatusCancelado(int $compraId): void
    {
        try {
            $companyId = $this->getCompanyId();

            // 1. Deletar registros de estoque_movimentos
            $stmt = $this->db->query("SHOW TABLES LIKE 'estoque_movimentos'");
            if ($stmt->rowCount() > 0) {
                // Verificar quais colunas existem
                $stmt = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'reference_id'");
                $temReferenceId = $stmt->rowCount() > 0;
                $stmt = $this->db->query("SHOW COLUMNS FROM estoque_movimentos LIKE 'documento_id'");
                $temDocumentoId = $stmt->rowCount() > 0;

                if ($temReferenceId) {
                    // Buscar movimentações para reverter estoque antes de deletar
                    $stmt = $this->db->prepare("
                        SELECT id, item_id, product_id, quantity, type
                        FROM estoque_movimentos
                        WHERE company_id = :company_id
                          AND reference_id = :reference_id
                          AND (reference_type = 'compra' OR documento = 'compra')
                    ");
                    $stmt->execute([
                        'company_id' => $companyId,
                        'reference_id' => $compraId
                    ]);
                    $movimentos = $stmt->fetchAll();

                    // Reverter estoque antes de deletar
                    foreach ($movimentos as $mov) {
                        $itemId = $mov['item_id'] ?? $mov['product_id'] ?? null;
                        $quantity = (float) ($mov['quantity'] ?? 0);
                        $type = $mov['type'] ?? 'entrada';

                        if ($itemId && $quantity > 0 && $type === 'entrada') {
                            // Reverter entrada (diminuir estoque)
                            $stmtUpdate = $this->db->prepare("
                                UPDATE produtos SET stock_quantity = stock_quantity - :quantity
                                WHERE id = :id AND company_id = :company_id
                            ");
                            $stmtUpdate->execute([
                                'quantity' => $quantity,
                                'id' => $itemId,
                                'company_id' => $companyId
                            ]);
                        }
                    }

                    // Deletar movimentações
                    $stmt = $this->db->prepare("
                        DELETE FROM estoque_movimentos
                        WHERE company_id = :company_id
                          AND reference_id = :reference_id
                          AND (reference_type = 'compra' OR documento = 'compra')
                    ");
                    $stmt->execute([
                        'company_id' => $companyId,
                        'reference_id' => $compraId
                    ]);
                    error_log("Compra #{$compraId}: Movimentações de estoque deletadas");
                } elseif ($temDocumentoId) {
                    $stmt = $this->db->prepare("
                        DELETE FROM estoque_movimentos
                        WHERE company_id = :company_id
                          AND documento_id = :documento_id
                          AND documento = 'compra'
                    ");
                    $stmt->execute([
                        'company_id' => $companyId,
                        'documento_id' => $compraId
                    ]);
                    error_log("Compra #{$compraId}: Movimentações de estoque deletadas");
                }
            }

            // 2. Atualizar contas_pagar.status para cancelado
            $stmt = $this->db->query("SHOW TABLES LIKE 'contas_pagar'");
            if ($stmt->rowCount() > 0) {
                $stmt = $this->db->prepare("
                    UPDATE contas_pagar
                    SET status = 'cancelado'
                    WHERE compra_id = :compra_id
                      AND company_id = :company_id
                ");
                $stmt->execute([
                    'compra_id' => $compraId,
                    'company_id' => $companyId
                ]);
                $linhasAfetadas = $stmt->rowCount();
                error_log("Compra #{$compraId}: {$linhasAfetadas} conta(s) a pagar cancelada(s)");
            }
        } catch (Exception $e) {
            error_log("Compra #{$compraId}: Erro ao processar status Cancelado: " . $e->getMessage());
            throw $e;
        }
    }

}