<?php

declare(strict_types=1);

namespace App\Controllers;

use Exception;

/**
 * Controller de Empresas
 *
 * @author Romildo Conegundes
 * @package Systhema
 */
class EmpresasController extends BaseController
{
    /**
     * Lista todas as empresas
     */
    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('empresas')) {
            $this->response->forbidden('Você não tem permissão para visualizar empresas.');
            return;
        }

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

            $query = "SELECT * FROM empresas WHERE 1=1";
            $params = [];

            if (!empty($search)) {
                $query .= " AND (razao_social LIKE :search OR cnpj LIKE :search OR nome_fantasia LIKE :search)";
                $params['search'] = "%{$search}%";
            }

            if ($status !== '') {
                $query .= " AND ativo = :status";
                $params['status'] = $status === '1' ? 'Sim' : 'Não';
            }

            $query .= " ORDER BY razao_social ASC";

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

            $this->view('empresas/index', [
                'empresas' => $empresas,
                'search' => $search,
                'status' => $status,
                'pageTitle' => 'Empresas'
            ]);
        } catch (Exception $e) {
            error_log("Erro ao listar empresas: " . $e->getMessage());
            $this->error('Erro ao carregar empresas');
        }
    }

    /**
     * Retorna dados da empresa atual em JSON.
     * Usado pelo PDV para montar payload de NFC-e.
     */
    public function atualJson(): void
    {
        try {
            $companyId = $this->getCompanyId();

            if (!$companyId) {
                $this->error('Empresa nao encontrada');
                return;
            }

            $stmt = $this->db->prepare("SELECT * FROM empresas WHERE id = :id LIMIT 1");
            $stmt->execute(['id' => $companyId]);
            $empresa = $stmt->fetch();

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

            // Mapear campos esperados pelo serviço NFC-e
            $dados = [
                'nome' => $empresa['razao_social'] ?? $empresa['nome_fantasia'] ?? '',
                'cnpj' => $empresa['cnpj'] ?? '',
                'inscricao_estadual' => $empresa['inscricao_estadual'] ?? '',
                'estado' => $empresa['uf'] ?? $empresa['estado'] ?? '',
                'cidade' => $empresa['cidade'] ?? '',
                'endereco' => $empresa['endereco'] ?? '',
                'numero' => $empresa['numero'] ?? '',
                'bairro' => $empresa['bairro'] ?? '',
                'cep' => $empresa['cep'] ?? '',
                'csc' => $empresa['csc_nfce'] ?? $empresa['csc'] ?? '',
                'csc_id' => $empresa['id_token_nfce'] ?? $empresa['csc_id'] ?? '',
                'serie_nfce' => $empresa['serie_nfce'] ?? null,
                'numero_nfce' => $empresa['numero_nfce'] ?? null,
                'ambiente_nfce' => $empresa['ambiente_nfce'] ?? null,
            ];

            $this->success('Empresa atual', ['empresa' => $dados]);
        } catch (\Exception $e) {
            error_log('Erro ao obter empresa atual: ' . $e->getMessage());
            $this->error('Erro ao obter empresa atual');
        }
    }

    /**
     * Exibe formulário de criação
     */
    public function create(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('empresas')) {
            $this->response->forbidden('Você não tem permissão para criar empresas.');
            return;
        }

        $this->view('empresas/form', [
            'pageTitle' => 'Nova Empresa'
        ]);
    }

    /**
     * Salva nova empresa
     */
    public function store(): void
    {
        error_log('========================================');
        error_log('[Empresas::store] === INÍCIO DO PROCESSAMENTO ===');
        error_log('[Empresas::store] Timestamp: ' . date('Y-m-d H:i:s'));
        error_log('[Empresas::store] REQUEST_METHOD: ' . $_SERVER['REQUEST_METHOD']);
        error_log('[Empresas::store] Content-Type: ' . ($_SERVER['CONTENT_TYPE'] ?? 'N/A'));

        // Verificar permissão de criação
        if (!$this->canCreate('empresas')) {
            error_log('[Empresas::store] ❌ Permissão negada');
            $this->response->forbidden('Você não tem permissão para criar empresas.');
            return;
        }
        error_log('[Empresas::store] ✅ Permissão verificada');

        $companyId = $this->getCompanyId();
        error_log('[Empresas::store] Company ID: ' . ($companyId ?? 'NULL'));

        // Log de todos os dados POST recebidos
        error_log('[Empresas::store] Dados POST recebidos:');
        error_log('[Empresas::store] REQUEST_METHOD: ' . ($_SERVER['REQUEST_METHOD'] ?? 'N/A'));
        error_log('[Empresas::store] CONTENT_TYPE: ' . ($_SERVER['CONTENT_TYPE'] ?? 'N/A'));
        error_log('[Empresas::store] $_POST está vazio? ' . (empty($_POST) ? 'SIM' : 'NÃO'));
        error_log('[Empresas::store] $_POST keys: ' . json_encode(array_keys($_POST ?? [])));
        error_log('[Empresas::store] $_POST values (primeiros 2000 chars): ' . substr(json_encode($_POST ?? []), 0, 2000));
        error_log('[Empresas::store] FILES keys: ' . json_encode(array_keys($_FILES ?? [])));

        // Se $_POST está vazio mas é POST, tentar ler do php://input
        if (empty($_POST) && ($_SERVER['REQUEST_METHOD'] ?? '') === 'POST') {
            error_log('[Empresas::store] ⚠️ $_POST está vazio! Tentando ler de php://input...');
            $input = file_get_contents('php://input');
            error_log('[Empresas::store] php://input length: ' . strlen($input));
            error_log('[Empresas::store] php://input preview: ' . substr($input, 0, 500));

            // Se for multipart/form-data, os dados devem estar em $_POST
            // Se não estiver, pode ser um problema de configuração do PHP
            if (strpos($_SERVER['CONTENT_TYPE'] ?? '', 'multipart/form-data') !== false && empty($_POST)) {
                error_log('[Empresas::store] ❌ ERRO CRÍTICO: multipart/form-data mas $_POST está vazio!');
                error_log('[Empresas::store] Isso pode indicar problema com upload_max_filesize ou post_max_size');
            }
        }

        // Remove formatação do CNPJ antes de salvar
        $documento = $this->request->post('document') ?? '';
        $cnpjLimpo = preg_replace('/[^0-9]/', '', $documento);
        error_log('[Empresas::store] Documento original: ' . $documento);
        error_log('[Empresas::store] CNPJ limpo: ' . $cnpjLimpo);

        // Verificar se os dados estão chegando
        $nameValue = $this->request->post('name');
        $tradeNameValue = $this->request->post('trade_name');
        error_log('[Empresas::store] name (razao_social): ' . ($nameValue ?? 'NULL'));
        error_log('[Empresas::store] trade_name: ' . ($tradeNameValue ?? 'NULL'));

        // Se name está vazio, verificar se está em $_POST diretamente
        if (empty($nameValue) && isset($_POST['name'])) {
            $nameValue = $_POST['name'];
            error_log('[Empresas::store] name encontrado em $_POST diretamente: ' . $nameValue);
        }

        $data = [
            'company_id' => $companyId,
            'razao_social' => $nameValue,
            'nome_fantasia' => $tradeNameValue,
            'website' => $this->request->post('website'),
            'cnpj' => $cnpjLimpo,
            'email' => $this->request->post('email'),
            'telefone' => $this->request->post('phone'),
            'inscricao_estadual' => $this->request->post('state_registration'),
            'inscricao_municipal' => $this->request->post('municipal_registration'),
            'endereco' => $this->request->post('address'),
            'numero' => $this->request->post('numero'),
            'complemento' => $this->request->post('complemento'),
            'bairro' => $this->request->post('bairro'),
            'cidade' => $this->request->post('city'),
            'uf' => $this->request->post('state'),
            'cep' => $this->request->post('zip_code'),
            'certificado_path' => null,
            'senha_certificado' => $this->request->post('senha_certificado'),
            'serie_nfe' => $this->request->post('serie_nfe', '1'),
            'numero_nfe' => $this->request->post('numero_nfe', 0),
            'ambiente_nfe' => $this->request->post('ambiente_nfe', 'homologacao'),
            'serie_nfce' => $this->request->post('serie_nfce', '1'),
            'numero_nfce' => $this->request->post('numero_nfce', 0),
            'ambiente_nfce' => $this->request->post('ambiente_nfce', 'homologacao'),
            'csc_nfce' => $this->request->post('csc_nfce'),
            'id_token_nfce' => $this->request->post('id_token_nfce'),
            'serie_nfse' => $this->request->post('serie_nfse', '1'),
            'numero_nfse' => $this->request->post('numero_nfse', 0),
            'nfse_codigo_servico' => $this->request->post('nfse_codigo_servico'),
            'nfse_codigo_tributacao' => $this->request->post('nfse_codigo_tributacao'),
            'nfse_aliquota_iss' => $this->request->post('nfse_aliquota_iss') !== null ? (float) $this->request->post('nfse_aliquota_iss') : null,
            'nfse_natureza_operacao' => $this->request->post('nfse_natureza_operacao', '1'),
            'nfse_regime_tributacao' => $this->request->post('nfse_regime_tributacao'),
            'nfse_optante_simples' => $this->request->post('nfse_optante_simples', '2'),
            'nfse_iss_retido_padrao' => $this->request->post('nfse_iss_retido_padrao', '2'),
            'serie_mdfe' => $this->request->post('serie_mdfe', '1'),
            'numero_mdfe' => $this->request->post('numero_mdfe', 0),
            'serie_cte' => $this->request->post('serie_cte', '1'),
            'numero_cte' => $this->request->post('numero_cte', 0),
            'shipay_enabled' => $this->request->post('shipay_enabled') ? 1 : 0,
            'shipay_environment' => $this->request->post('shipay_environment', 'sandbox'),
            'shipay_access_key' => $this->request->post('shipay_access_key'),
            'shipay_secret_key' => $this->request->post('shipay_secret_key'),
            'shipay_client_id' => $this->request->post('shipay_client_id'),
            'shipay_store_id' => $this->request->post('shipay_store_id'),
            'shipay_cashier_id' => $this->request->post('shipay_cashier_id'),
            'shipay_webhook_url' => $this->request->post('shipay_webhook_url'),
            'shipay_webhook_secret' => $this->request->post('shipay_webhook_secret'),
            'nfse_nacional_ativo' => $this->request->post('nfse_nacional_ativo') ? 1 : 0,
            'nfse_nacional_client_id' => $this->request->post('nfse_nacional_client_id'),
            'nfse_nacional_client_secret' => $this->request->post('nfse_nacional_client_secret'),
            // SEMPRE produção (emissão real) - homologação desabilitada
            'nfse_nacional_homologacao' => 0,
            'ativo' => $this->request->post('is_active') ? 'Sim' : 'Não',
        ];

        // Adicionar formula_custo apenas se a coluna existir
        if ($this->formulaCustoColumnExists()) {
            $data['formula_custo'] = $this->request->post('formula_custo');
        }

        // Verifica se as colunas do contador existem antes de adicionar aos dados
        $hasContadorColumns = $this->contadorColumnsExist();

        if ($hasContadorColumns) {
            // Adiciona dados do Contador apenas se as colunas existirem
            $data['contador_nome'] = $this->request->post('contador_nome');
            $data['contador_cpf'] = $this->request->post('contador_cpf');
            $data['contador_crc'] = $this->request->post('contador_crc');
            $data['contador_cnpj'] = $this->request->post('contador_cnpj');
            $data['contador_razao_social'] = $this->request->post('contador_razao_social');
            $data['contador_email'] = $this->request->post('contador_email');
            $data['contador_telefone'] = $this->request->post('contador_telefone');
            $data['contador_cep'] = $this->request->post('contador_cep');
            $data['contador_logradouro'] = $this->request->post('contador_logradouro');
            $data['contador_numero'] = $this->request->post('contador_numero');
            $data['contador_complemento'] = $this->request->post('contador_complemento');
            $data['contador_bairro'] = $this->request->post('contador_bairro');
            $data['contador_uf'] = $this->request->post('contador_uf');
            $data['contador_municipio'] = $this->request->post('contador_municipio');
        }

        // Verificar se o campo name existe antes de validar
        $nameValue = $this->request->post('name');
        error_log('[Empresas::store] Campo name recebido: ' . ($nameValue ?? 'NULL'));
        error_log('[Empresas::store] Tamanho do name: ' . (strlen($nameValue ?? '') ?? 0));

        // Validação manual mais detalhada
        $errors = [];
        if (empty($nameValue) || trim($nameValue) === '') {
            $errors['name'] = ['O campo Razão Social é obrigatório'];
            error_log('[Empresas::store] ❌ ERRO: Campo name está vazio!');
        } elseif (strlen(trim($nameValue)) < 3) {
            $errors['name'] = ['O campo Razão Social deve ter pelo menos 3 caracteres'];
            error_log('[Empresas::store] ❌ ERRO: Campo name tem menos de 3 caracteres!');
        }

        // Usar validação do sistema também
        $validationErrors = $this->validate([
            'name' => 'required|min:3',
        ]);

        if (!empty($validationErrors)) {
            $errors = array_merge($errors, $validationErrors);
        }

        if (!empty($errors)) {
            error_log('[Empresas::store] ❌ Validação falhou: ' . json_encode($errors));
            error_log('[Empresas::store] POST keys: ' . json_encode(array_keys($_POST ?? [])));
            error_log('[Empresas::store] POST completo: ' . json_encode($_POST ?? []));
            error_log('[Empresas::store] Dados preparados: ' . json_encode($data));
            $this->error('Dados inválidos', $errors);
            return;
        }

        error_log('[Empresas::store] ✅ Validação passou');
        error_log('[Empresas::store] Dados preparados para salvamento:');
        error_log('[Empresas::store] Total de campos: ' . count($data));
        error_log('[Empresas::store] Dados (primeiros 2000 chars): ' . substr(json_encode($data), 0, 2000));

        try {
            error_log('[Empresas::store] Iniciando processo de salvamento...');
            // Upload do logo se fornecido
            if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
                $data['logo'] = $this->uploadLogo($_FILES['logo']);
            }

            // Upload do certificado se fornecido
            if (isset($_FILES['certificado']) && $_FILES['certificado']['error'] === UPLOAD_ERR_OK) {
                $data['certificado_path'] = $this->uploadCertificado($_FILES['certificado'], $data['cnpj']);
            }

            // Construir colunas e valores dinamicamente baseado nos dados que realmente existem
            $columns = [];
            $values = [];
            $params = [];

            // Campos obrigatórios sempre presentes
            $camposBase = [
                'company_id',
                'razao_social',
                'nome_fantasia',
                'cnpj',
                'email',
                'telefone',
                'website',
                'inscricao_estadual',
                'inscricao_municipal',
                'endereco',
                'numero',
                'complemento',
                'bairro',
                'cidade',
                'uf',
                'cep',
                'certificado_path',
                'senha_certificado',
                'serie_nfe',
                'numero_nfe',
                'ambiente_nfe',
                'serie_nfce',
                'numero_nfce',
                'ambiente_nfce',
                'csc_nfce',
                'id_token_nfce',
                'serie_nfse',
                'numero_nfse',
                'nfse_codigo_servico',
                'nfse_codigo_tributacao',
                'nfse_aliquota_iss',
                'nfse_natureza_operacao',
                'nfse_regime_tributacao',
                'nfse_optante_simples',
                'nfse_iss_retido_padrao',
                'serie_mdfe',
                'numero_mdfe',
                'serie_cte',
                'numero_cte',
                'shipay_enabled',
                'shipay_environment',
                'shipay_access_key',
                'shipay_secret_key',
                'shipay_client_id',
                'shipay_store_id',
                'shipay_cashier_id',
                'shipay_webhook_url',
                'shipay_webhook_secret',
                'nfse_nacional_ativo',
                'nfse_nacional_client_id',
                'nfse_nacional_client_secret',
                'nfse_nacional_homologacao',
                'ativo'
            ];

            // Adicionar logo se existir
            if (isset($data['logo'])) {
                $camposBase[] = 'logo';
            }

            // Adicionar campos base
            foreach ($camposBase as $campo) {
                if (array_key_exists($campo, $data)) {
                    $columns[] = $campo;
                    $values[] = ":$campo";
                    $params[$campo] = $data[$campo];
                }
            }

            // Adicionar formula_custo apenas se a coluna existir e o valor estiver definido
            if ($this->formulaCustoColumnExists() && isset($data['formula_custo'])) {
                $columns[] = 'formula_custo';
                $values[] = ':formula_custo';
                $params['formula_custo'] = $data['formula_custo'];
            }

            // Adicionar campos do contador se existirem
            if ($hasContadorColumns) {
                $camposContador = [
                    'contador_nome',
                    'contador_cpf',
                    'contador_crc',
                    'contador_cnpj',
                    'contador_razao_social',
                    'contador_email',
                    'contador_telefone',
                    'contador_cep',
                    'contador_logradouro',
                    'contador_numero',
                    'contador_complemento',
                    'contador_bairro',
                    'contador_uf',
                    'contador_municipio'
                ];
                foreach ($camposContador as $campo) {
                    if (array_key_exists($campo, $data)) {
                        $columns[] = $campo;
                        $values[] = ":$campo";
                        $params[$campo] = $data[$campo];
                    }
                }
            }

            // Construir strings finais
            $columnsStr = implode(', ', $columns);
            $valuesStr = implode(', ', $values);

            error_log('[Empresas::store] Preparando query INSERT...');
            error_log('[Empresas::store] Total de colunas: ' . count($columns));
            error_log('[Empresas::store] Total de valores: ' . count($values));
            error_log('[Empresas::store] Total de parâmetros: ' . count($params));
            error_log('[Empresas::store] Colunas: ' . $columnsStr);
            error_log('[Empresas::store] Valores: ' . $valuesStr);
            error_log('[Empresas::store] Parâmetros (keys): ' . json_encode(array_keys($params)));

            $stmt = $this->db->prepare("
                INSERT INTO empresas ($columnsStr) VALUES ($valuesStr)
            ");

            error_log('[Empresas::store] Query preparada com sucesso');
            error_log('[Empresas::store] Executando INSERT no banco de dados...');

            $stmt->execute($params);
            $empresaId = $this->db->lastInsertId();

            error_log('[Empresas::store] ✅ INSERT executado com sucesso!');
            error_log('[Empresas::store] ID da empresa criada: ' . $empresaId);

            $this->logActivity('create', 'companies', (int) $empresaId, $data);

            error_log('[Empresas::store] === FIM (Sucesso) ===');
            error_log('========================================');

            $this->success('Empresa cadastrada com sucesso', [
                'id' => $empresaId
            ]);
        } catch (Exception $e) {
            error_log('[Empresas::store] ❌ ERRO ao criar empresa!');
            error_log('[Empresas::store] Mensagem: ' . $e->getMessage());
            error_log('[Empresas::store] Arquivo: ' . $e->getFile() . ':' . $e->getLine());
            error_log('[Empresas::store] Stack trace: ' . $e->getTraceAsString());

            // Log de informações adicionais do erro
            if (isset($stmt) && $stmt instanceof \PDOStatement) {
                $errorInfo = $stmt->errorInfo();
                error_log('[Empresas::store] PDO Error Info: ' . json_encode($errorInfo));
            }

            error_log('[Empresas::store] === FIM (Erro) ===');
            error_log('========================================');
            $this->error('Erro ao cadastrar empresa: ' . $e->getMessage());
        }
    }

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

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

            if (!$id) {
                $this->redirect('/empresas');
                return;
            }

            $stmt = $this->db->prepare("SELECT * FROM empresas WHERE id = :id LIMIT 1");
            $stmt->execute(['id' => $id]);
            $empresaRaw = $stmt->fetch();

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

            // Mapear campos do banco (português) para o formato esperado pela view (inglês)
            $empresa = [
                'id' => $empresaRaw['id'],
                'name' => $empresaRaw['razao_social'] ?? '',
                'trade_name' => $empresaRaw['nome_fantasia'] ?? '',
                'website' => $empresaRaw['website'] ?? '',
                'document' => $empresaRaw['cnpj'] ?? '',
                'email' => $empresaRaw['email'] ?? '',
                'phone' => $empresaRaw['telefone'] ?? '',
                'state_registration' => $empresaRaw['inscricao_estadual'] ?? '',
                'municipal_registration' => $empresaRaw['inscricao_municipal'] ?? '',
                'address' => $empresaRaw['endereco'] ?? '',
                'numero' => $empresaRaw['numero'] ?? '',
                'complemento' => $empresaRaw['complemento'] ?? '',
                'bairro' => $empresaRaw['bairro'] ?? '',
                'city' => $empresaRaw['cidade'] ?? '',
                'state' => $empresaRaw['uf'] ?? '',
                'zip_code' => $empresaRaw['cep'] ?? '',
                'logo' => $empresaRaw['logo'] ?? '',
                'certificado_path' => $empresaRaw['certificado_path'] ?? '',
                'senha_certificado' => $empresaRaw['senha_certificado'] ?? '',
                'serie_nfe' => $empresaRaw['serie_nfe'] ?? '1',
                'numero_nfe' => $empresaRaw['numero_nfe'] ?? 0,
                'ambiente_nfe' => $empresaRaw['ambiente_nfe'] ?? 'homologacao',
                'serie_nfce' => $empresaRaw['serie_nfce'] ?? '1',
                'numero_nfce' => $empresaRaw['numero_nfce'] ?? 0,
                'ambiente_nfce' => $empresaRaw['ambiente_nfce'] ?? 'homologacao',
                'csc_nfce' => $empresaRaw['csc_nfce'] ?? '',
                'id_token_nfce' => $empresaRaw['id_token_nfce'] ?? '',
                'serie_nfse' => $empresaRaw['serie_nfse'] ?? '1',
                'numero_nfse' => $empresaRaw['numero_nfse'] ?? 0,
                'nfse_codigo_servico' => $empresaRaw['nfse_codigo_servico'] ?? '',
                'nfse_codigo_tributacao' => $empresaRaw['nfse_codigo_tributacao'] ?? '',
                'nfse_aliquota_iss' => $empresaRaw['nfse_aliquota_iss'] ?? null,
                'nfse_natureza_operacao' => $empresaRaw['nfse_natureza_operacao'] ?? '1',
                'nfse_regime_tributacao' => $empresaRaw['nfse_regime_tributacao'] ?? '',
                'nfse_optante_simples' => $empresaRaw['nfse_optante_simples'] ?? '2',
                'nfse_iss_retido_padrao' => $empresaRaw['nfse_iss_retido_padrao'] ?? '2',
                'serie_mdfe' => $empresaRaw['serie_mdfe'] ?? '1',
                'numero_mdfe' => $empresaRaw['numero_mdfe'] ?? 0,
                'serie_cte' => $empresaRaw['serie_cte'] ?? '1',
                'numero_cte' => $empresaRaw['numero_cte'] ?? 0,
                'shipay_enabled' => (int) ($empresaRaw['shipay_enabled'] ?? 0),
                'shipay_environment' => $empresaRaw['shipay_environment'] ?? 'sandbox',
                'shipay_access_key' => $empresaRaw['shipay_access_key'] ?? '',
                'shipay_secret_key' => $empresaRaw['shipay_secret_key'] ?? '',
                'shipay_client_id' => $empresaRaw['shipay_client_id'] ?? '',
                'shipay_store_id' => $empresaRaw['shipay_store_id'] ?? '',
                'shipay_cashier_id' => $empresaRaw['shipay_cashier_id'] ?? '',
                'shipay_webhook_url' => $empresaRaw['shipay_webhook_url'] ?? '',
                'shipay_webhook_secret' => $empresaRaw['shipay_webhook_secret'] ?? '',
                'nfse_nacional_ativo' => (int) ($empresaRaw['nfse_nacional_ativo'] ?? 0),
                'nfse_nacional_client_id' => $empresaRaw['nfse_nacional_client_id'] ?? '',
                'nfse_nacional_client_secret' => $empresaRaw['nfse_nacional_client_secret'] ?? '',
                'nfse_nacional_homologacao' => (int) ($empresaRaw['nfse_nacional_homologacao'] ?? 0),
                'formula_custo' => $empresaRaw['formula_custo'] ?? '',
                'is_active' => ($empresaRaw['ativo'] ?? 'Não') === 'Sim' ? 1 : 0,
                // Dados do Contador
                'contador_nome' => $empresaRaw['contador_nome'] ?? '',
                'contador_cpf' => $empresaRaw['contador_cpf'] ?? '',
                'contador_crc' => $empresaRaw['contador_crc'] ?? '',
                'contador_cnpj' => $empresaRaw['contador_cnpj'] ?? '',
                'contador_razao_social' => $empresaRaw['contador_razao_social'] ?? '',
                'contador_email' => $empresaRaw['contador_email'] ?? '',
                'contador_telefone' => $empresaRaw['contador_telefone'] ?? '',
                'contador_cep' => $empresaRaw['contador_cep'] ?? '',
                'contador_logradouro' => $empresaRaw['contador_logradouro'] ?? '',
                'contador_numero' => $empresaRaw['contador_numero'] ?? '',
                'contador_complemento' => $empresaRaw['contador_complemento'] ?? '',
                'contador_bairro' => $empresaRaw['contador_bairro'] ?? '',
                'contador_uf' => $empresaRaw['contador_uf'] ?? '',
                'contador_municipio' => $empresaRaw['contador_municipio'] ?? '',
                'created_at' => $empresaRaw['created_at'] ?? '',
                'updated_at' => $empresaRaw['updated_at'] ?? '',
            ];

            // Carregar fórmulas de custo personalizadas
            $formulasCusto = [];
            try {
                $this->garantirTabelaFormulasCusto();
                $stmt = $this->db->prepare("
                    SELECT * FROM empresas_formulas_custo
                    WHERE empresa_id = :empresa_id
                    ORDER BY ordem ASC, id ASC
                ");
                $stmt->execute(['empresa_id' => $id]);
                $formulasCusto = $stmt->fetchAll();
            } catch (Exception $e) {
                error_log("Erro ao carregar fórmulas de custo: " . $e->getMessage());
            }

            $this->view('empresas/form', [
                'empresa' => $empresa,
                'formulasCusto' => $formulasCusto,
                'pageTitle' => 'Editar Empresa'
            ]);
        } catch (Exception $e) {
            error_log("Erro ao exibir formulário: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

    /**
     * Verifica se as colunas do contador existem na tabela empresas
     */
    private function contadorColumnsExist(): bool
    {
        try {
            $stmt = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'contador_%'");
            $columns = $stmt->fetchAll();
            return count($columns) >= 14; // Deve ter pelo menos 14 colunas do contador
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Verifica se a coluna formula_custo existe na tabela empresas
     */
    private function formulaCustoColumnExists(): bool
    {
        try {
            $stmt = $this->db->query("SHOW COLUMNS FROM empresas LIKE 'formula_custo'");
            return $stmt->rowCount() > 0;
        } catch (Exception $e) {
            return false;
        }
    }

    /**
     * Atualiza uma empresa
     */
    public function update(): void
    {
        error_log('[Empresas::update] === MÉTODO CHAMADO ===');
        error_log('[Empresas::update] $_POST: ' . json_encode($_POST));
        error_log('[Empresas::update] $_FILES: ' . json_encode(array_keys($_FILES)));

        // Verificar permissão de edição
        if (!$this->canEdit('empresas')) {
            error_log('[Empresas::update] ❌ SEM PERMISSÃO');
            $this->response->forbidden('Você não tem permissão para editar empresas.');
            return;
        }

        $id = $this->request->post('id');
        error_log('[Empresas::update] ID recebido: ' . var_export($id, true));

        if (empty($id)) {
            error_log('[Empresas::update] ❌ ID VAZIO');
            $this->error('ID da empresa não informado');
            return;
        }

        // Remove formatação do CNPJ antes de atualizar
        $documento = $this->request->post('document') ?? '';
        $cnpjLimpo = preg_replace('/[^0-9]/', '', $documento);

        $data = [
            'razao_social' => $this->request->post('name'),
            'nome_fantasia' => $this->request->post('trade_name'),
            'cnpj' => $cnpjLimpo,
            'email' => $this->request->post('email'),
            'telefone' => $this->request->post('phone'),
            'inscricao_estadual' => $this->request->post('state_registration'),
            'inscricao_municipal' => $this->request->post('municipal_registration'),
            'endereco' => $this->request->post('address'),
            'numero' => $this->request->post('numero'),
            'complemento' => $this->request->post('complemento'),
            'bairro' => $this->request->post('bairro'),
            'cidade' => $this->request->post('city'),
            'uf' => $this->request->post('state'),
            'cep' => $this->request->post('zip_code'),
            'website' => $this->request->post('website'),
            'senha_certificado' => $this->request->post('senha_certificado'),
            'serie_nfe' => $this->request->post('serie_nfe', '1'),
            'numero_nfe' => $this->request->post('numero_nfe', 0),
            'ambiente_nfe' => $this->request->post('ambiente_nfe', 'homologacao'),
            'serie_nfce' => $this->request->post('serie_nfce', '1'),
            'numero_nfce' => $this->request->post('numero_nfce', 0),
            'ambiente_nfce' => $this->request->post('ambiente_nfce', 'homologacao'),
            'csc_nfce' => $this->request->post('csc_nfce'),
            'id_token_nfce' => $this->request->post('id_token_nfce'),
            'serie_nfse' => $this->request->post('serie_nfse', '1'),
            'numero_nfse' => $this->request->post('numero_nfse', 0),
            'nfse_codigo_servico' => $this->request->post('nfse_codigo_servico'),
            'nfse_codigo_tributacao' => $this->request->post('nfse_codigo_tributacao'),
            'nfse_aliquota_iss' => $this->request->post('nfse_aliquota_iss') !== null ? (float) $this->request->post('nfse_aliquota_iss') : null,
            'nfse_natureza_operacao' => $this->request->post('nfse_natureza_operacao', '1'),
            'nfse_regime_tributacao' => $this->request->post('nfse_regime_tributacao'),
            'nfse_optante_simples' => $this->request->post('nfse_optante_simples', '2'),
            'nfse_iss_retido_padrao' => $this->request->post('nfse_iss_retido_padrao', '2'),
            'serie_mdfe' => $this->request->post('serie_mdfe', '1'),
            'numero_mdfe' => $this->request->post('numero_mdfe', 0),
            'serie_cte' => $this->request->post('serie_cte', '1'),
            'numero_cte' => $this->request->post('numero_cte', 0),
            'shipay_enabled' => $this->request->post('shipay_enabled') ? 1 : 0,
            'shipay_environment' => $this->request->post('shipay_environment', 'sandbox'),
            'shipay_access_key' => $this->request->post('shipay_access_key'),
            'shipay_secret_key' => $this->request->post('shipay_secret_key'),
            'shipay_client_id' => $this->request->post('shipay_client_id'),
            'shipay_store_id' => $this->request->post('shipay_store_id'),
            'shipay_cashier_id' => $this->request->post('shipay_cashier_id'),
            'shipay_webhook_url' => $this->request->post('shipay_webhook_url'),
            'shipay_webhook_secret' => $this->request->post('shipay_webhook_secret'),
            'nfse_nacional_ativo' => $this->request->post('nfse_nacional_ativo') ? 1 : 0,
            'nfse_nacional_client_id' => $this->request->post('nfse_nacional_client_id'),
            'nfse_nacional_client_secret' => $this->request->post('nfse_nacional_client_secret'),
            // SEMPRE produção (emissão real) - homologação desabilitada
            'nfse_nacional_homologacao' => 0,
            'ativo' => $this->request->post('is_active') ? 'Sim' : 'Não'
        ];

        error_log('[Empresas::update] Array $data montado com ' . count($data) . ' campos');

        try {
            // Verifica se as colunas do contador existem antes de adicionar aos dados
            $hasContadorColumns = $this->contadorColumnsExist();
            error_log('[Empresas::update] Colunas do contador existem: ' . ($hasContadorColumns ? 'SIM' : 'NÃO'));

            if ($hasContadorColumns) {
                // Adiciona dados do Contador apenas se as colunas existirem
                $data['contador_nome'] = $this->request->post('contador_nome');
                $data['contador_cpf'] = $this->request->post('contador_cpf');
                $data['contador_crc'] = $this->request->post('contador_crc');
                $data['contador_cnpj'] = $this->request->post('contador_cnpj');
                $data['contador_razao_social'] = $this->request->post('contador_razao_social');
                $data['contador_email'] = $this->request->post('contador_email');
                $data['contador_telefone'] = $this->request->post('contador_telefone');
                $data['contador_cep'] = $this->request->post('contador_cep');
                $data['contador_logradouro'] = $this->request->post('contador_logradouro');
                $data['contador_numero'] = $this->request->post('contador_numero');
                $data['contador_complemento'] = $this->request->post('contador_complemento');
                $data['contador_bairro'] = $this->request->post('contador_bairro');
                $data['contador_uf'] = $this->request->post('contador_uf');
                $data['contador_municipio'] = $this->request->post('contador_municipio');
            }

            // Adicionar formula_custo apenas se a coluna existir
            $formulaCustoExists = $this->formulaCustoColumnExists();
            error_log('[Empresas::update] Coluna formula_custo existe: ' . ($formulaCustoExists ? 'SIM' : 'NÃO'));
            if ($formulaCustoExists) {
                $data['formula_custo'] = $this->request->post('formula_custo');
            }
            error_log('[Empresas::update] === INÍCIO DO PROCESSAMENTO ===');
            error_log('[Empresas::update] ID da empresa: ' . $id);
            error_log('[Empresas::update] Total de campos em $data: ' . count($data));

            // Upload do logo se fornecido
            if (isset($_FILES['logo']) && $_FILES['logo']['error'] === UPLOAD_ERR_OK) {
                $data['logo'] = $this->uploadLogo($_FILES['logo']);
                error_log('[Empresas::update] Logo adicionado: ' . $data['logo']);
            }

            // Upload do certificado se fornecido
            if (isset($_FILES['certificado']) && $_FILES['certificado']['error'] === UPLOAD_ERR_OK) {
                $data['certificado_path'] = $this->uploadCertificado($_FILES['certificado'], $data['cnpj']);
                error_log('[Empresas::update] Certificado adicionado: ' . $data['certificado_path']);
            }

            // Construir query UPDATE dinamicamente
            $sets = [];
            $params = [];

            // Campos obrigatórios sempre presentes
            $camposBase = [
                'razao_social',
                'nome_fantasia',
                'cnpj',
                'email',
                'telefone',
                'inscricao_estadual',
                'inscricao_municipal',
                'endereco',
                'numero',
                'complemento',
                'bairro',
                'cidade',
                'uf',
                'cep',
                'website',
                'senha_certificado',
                'serie_nfe',
                'numero_nfe',
                'ambiente_nfe',
                'serie_nfce',
                'numero_nfce',
                'ambiente_nfce',
                'csc_nfce',
                'id_token_nfce',
                'serie_nfse',
                'numero_nfse',
                'nfse_codigo_servico',
                'nfse_codigo_tributacao',
                'nfse_aliquota_iss',
                'nfse_natureza_operacao',
                'nfse_regime_tributacao',
                'nfse_optante_simples',
                'nfse_iss_retido_padrao',
                'serie_mdfe',
                'numero_mdfe',
                'serie_cte',
                'numero_cte',
                'shipay_enabled',
                'shipay_environment',
                'shipay_access_key',
                'shipay_secret_key',
                'shipay_client_id',
                'shipay_store_id',
                'shipay_cashier_id',
                'shipay_webhook_url',
                'shipay_webhook_secret',
                'nfse_nacional_ativo',
                'nfse_nacional_client_id',
                'nfse_nacional_client_secret',
                'nfse_nacional_homologacao',
                'ativo'
            ];

            // Adicionar campos base
            foreach ($camposBase as $campo) {
                if (array_key_exists($campo, $data)) {
                    $sets[] = "$campo = :$campo";
                    $params[$campo] = $data[$campo];
                }
            }

            // Adicionar logo se existir
            if (isset($data['logo'])) {
                $sets[] = "logo = :logo";
                $params['logo'] = $data['logo'];
            }

            // Adicionar certificado_path se existir
            if (isset($data['certificado_path'])) {
                $sets[] = "certificado_path = :certificado_path";
                $params['certificado_path'] = $data['certificado_path'];
            }

            // Adicionar formula_custo apenas se a coluna existir e o valor estiver definido
            if ($formulaCustoExists && isset($data['formula_custo'])) {
                $sets[] = "formula_custo = :formula_custo";
                $params['formula_custo'] = $data['formula_custo'];
            }

            // Adicionar campos do contador se existirem
            if ($hasContadorColumns) {
                $camposContador = [
                    'contador_nome',
                    'contador_cpf',
                    'contador_crc',
                    'contador_cnpj',
                    'contador_razao_social',
                    'contador_email',
                    'contador_telefone',
                    'contador_cep',
                    'contador_logradouro',
                    'contador_numero',
                    'contador_complemento',
                    'contador_bairro',
                    'contador_uf',
                    'contador_municipio'
                ];
                foreach ($camposContador as $campo) {
                    if (array_key_exists($campo, $data)) {
                        $sets[] = "$campo = :$campo";
                        $params[$campo] = $data[$campo];
                    }
                }
            }

            // Adicionar ID para o WHERE
            $params['id'] = $id;

            // Construir query final
            $setsStr = implode(', ', $sets);
            $query = "UPDATE empresas SET $setsStr WHERE id = :id";

            error_log('[Empresas::update] Query preparada: ' . substr($query, 0, 500));
            error_log('[Empresas::update] Total de SETs: ' . count($sets));
            error_log('[Empresas::update] Total de parâmetros: ' . count($params));
            error_log('[Empresas::update] Parâmetros (keys): ' . json_encode(array_keys($params)));

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

            error_log('[Empresas::update] ✅ UPDATE executado com sucesso!');
            error_log('[Empresas::update] === FIM (Sucesso) ===');

            $this->logActivity('update', 'companies', (int) $id, $data);

            $this->success('Empresa atualizada com sucesso');
        } catch (Exception $e) {
            error_log('[Empresas::update] ❌ ERRO: ' . $e->getMessage());
            error_log('[Empresas::update] Stack trace: ' . $e->getTraceAsString());
            error_log("Erro ao atualizar empresa: " . $e->getMessage());
            $this->error('Erro ao atualizar empresa: ' . $e->getMessage());
        }
    }

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

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

            // Não permite deletar empresa padrão (company_id = 1)
            $stmt = $this->db->prepare("SELECT company_id FROM empresas WHERE id = :id");
            $stmt->execute(['id' => $id]);
            $empresa = $stmt->fetch();

            if ($empresa && ($empresa['company_id'] ?? 0) == 1) {
                $this->error('Não é possível excluir a empresa padrão');
                return;
            }

            $stmt = $this->db->prepare("DELETE FROM empresas WHERE id = :id");
            $stmt->execute(['id' => $id]);

            $this->logActivity('delete', 'companies', (int) $id);

            $this->success('Empresa excluída com sucesso');
        } catch (Exception $e) {
            error_log("Erro ao deletar empresa: " . $e->getMessage());
            $this->error('Erro ao excluir empresa');
        }
    }

    /**
     * Faz upload do logo
     */
    private function uploadLogo(array $file): string
    {
        $uploadDir = \ROOT_PATH . '/storage/uploads/logos/';

        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }

        $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
        $filename = uniqid('logo_') . '.' . $extension;
        $filepath = $uploadDir . $filename;

        if (!move_uploaded_file($file['tmp_name'], $filepath)) {
            throw new Exception("Erro ao fazer upload do logo");
        }

        return '/storage/uploads/logos/' . $filename;
    }

    /**
     * Faz upload do certificado digital
     */
    private function uploadCertificado(array $file, string $cnpj): string
    {
        $cnpj = preg_replace('/\D/', '', $cnpj);
        $uploadDir = \ROOT_PATH . '/storage/certificados/' . $cnpj . '/';

        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }

        // Validar extensão do certificado
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, ['pfx', 'p12'])) {
            throw new Exception("Formato de certificado inválido. Use .pfx ou .p12");
        }

        $filename = $cnpj . '.pfx';
        $filepath = $uploadDir . $filename;

        // Fazer backup do certificado anterior se existir
        if (file_exists($filepath)) {
            $backupPath = $uploadDir . $cnpj . '_backup_' . date('Ymd_His') . '.pfx';
            rename($filepath, $backupPath);
        }

        if (!move_uploaded_file($file['tmp_name'], $filepath)) {
            throw new Exception("Erro ao fazer upload do certificado");
        }

        return '/storage/certificados/' . $cnpj . '/' . $filename;
    }

    /**
     * Testa o certificado digital e retorna informações
     */
    public function testarCertificado(): void
    {
        try {
            $id = $this->request->get('id');

            if (!$id) {
                $this->error('ID da empresa não informado');
                return;
            }

            // Busca dados da empresa
            $stmt = $this->db->prepare("SELECT id, razao_social, cnpj, certificado_path, senha_certificado FROM empresas WHERE id = :id LIMIT 1");
            $stmt->execute(['id' => $id]);
            $empresa = $stmt->fetch();

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

            $certPath = \ROOT_PATH . $empresa['certificado_path'];
            $senha = $empresa['senha_certificado'];

            // Validações
            if (empty($empresa['certificado_path'])) {
                $this->error('Certificado digital não configurado para esta empresa');
                return;
            }

            if (!file_exists($certPath)) {
                $this->error('Arquivo do certificado não encontrado: ' . $certPath);
                return;
            }

            if (!is_readable($certPath)) {
                $this->error('Certificado digital não pode ser lido. Verifique as permissões do arquivo.');
                return;
            }

            if (empty($senha)) {
                $this->error('Senha do certificado não informada');
                return;
            }

            // Usar CertificateHelper que já tem suporte para OpenSSL 3.x (resolve error:0308010C)
            // Primeiro, carrega o certificado para validar se está OK
            try {
                $certificado = \App\Core\CertificateHelper::loadPfx($certPath, $senha);
            } catch (Exception $e) {
                $errors = [];
                while (($error = openssl_error_string()) !== false) {
                    $errors[] = $error;
                }

                $errorMsg = $e->getMessage();
                if (!empty($errors)) {
                    $errorMsg .= ' | Erros OpenSSL: ' . implode('; ', $errors);
                }

                $this->error('Falha ao validar certificado. Senha incorreta ou certificado inválido. ' . $errorMsg);
                return;
            }

            // Agora extrair dados do certificado para análise usando openssl_pkcs12_read
            // Configurar OPENSSL_CONF para OpenSSL 3.x se necessário
            $certContent = file_get_contents($certPath);
            if ($certContent === false) {
                $this->error('Não foi possível ler o conteúdo do certificado');
                return;
            }

            // Detectar OpenSSL 3.x e configurar OPENSSL_CONF
            $opensslVersionString = '';
            if (defined('OPENSSL_VERSION_TEXT')) {
                $opensslVersionString = OPENSSL_VERSION_TEXT;
            } elseif (function_exists('openssl_version_text')) {
                $opensslVersionString = openssl_version_text();
            }
            $isOpenSSL3 = !empty($opensslVersionString) && strpos($opensslVersionString, 'OpenSSL 3') !== false;

            $opensslConfOriginal = getenv('OPENSSL_CONF');

            if ($isOpenSSL3) {
                // Caminho do openssl-legacy.cnf
                $basePath = \ROOT_PATH;
                $opensslConfPath = $basePath . '/src/Integrations/NFe/openssl-legacy.cnf';
                if (!file_exists($opensslConfPath)) {
                    $opensslConfPath = $basePath . '/openssl-legacy.cnf';
                }

                if (file_exists($opensslConfPath)) {
                    putenv('OPENSSL_CONF=' . $opensslConfPath);
                }
            }

            // Lê o certificado com configuração legacy se necessário
            $certData = [];
            $success = openssl_pkcs12_read($certContent, $certData, $senha);

            // Restaurar OPENSSL_CONF
            if ($opensslConfOriginal !== false) {
                putenv('OPENSSL_CONF=' . $opensslConfOriginal);
            } else {
                putenv('OPENSSL_CONF');
            }

            if (!$success) {
                $errors = [];
                while (($error = openssl_error_string()) !== false) {
                    $errors[] = $error;
                }

                $this->error('Falha ao extrair dados do certificado. ' . implode('; ', $errors));
                return;
            }

            $certPem = $certData['cert'];

            // Extrai informações do certificado
            $certDetails = openssl_x509_parse($certPem);

            // Extrai CNPJ e Razão Social do subject
            $subject = $certDetails['subject'];
            $cnpjCertificado = '';
            $razaoSocialCertificado = '';

            // Tenta extrair CNPJ do CN (Common Name)
            if (isset($subject['CN'])) {
                $cn = $subject['CN'];
                // Extrai CNPJ (número após os dois pontos ou padrão comum)
                if (preg_match('/(\d{14})/', $cn, $matches)) {
                    $cnpjCertificado = $matches[1];
                    $cnpjCertificado = substr($cnpjCertificado, 0, 2) . '.' .
                        substr($cnpjCertificado, 2, 3) . '.' .
                        substr($cnpjCertificado, 5, 3) . '/' .
                        substr($cnpjCertificado, 8, 4) . '-' .
                        substr($cnpjCertificado, 12, 2);
                }

                // Razão Social geralmente vem antes do CNPJ
                $razaoSocialCertificado = trim(preg_replace('/:.*/', '', $cn));
            }

            // Extrai outras informações
            $validadeDe = $certDetails['validFrom_time_t'] ?? 0;
            $validadeAte = $certDetails['validTo_time_t'] ?? 0;
            $serialNumber = $certDetails['serialNumber'] ?? '';

            // Verifica se está válido
            $now = time();
            $valido = ($now >= $validadeDe && $now <= $validadeAte);
            $diasRestantes = floor(($validadeAte - $now) / 86400);

            // Verifica se CNPJ do certificado corresponde ao CNPJ da empresa
            $cnpjEmpresa = preg_replace('/\D/', '', $empresa['cnpj']);
            $cnpjCertLimpo = preg_replace('/\D/', '', $cnpjCertificado);
            $cnpjCorresponde = ($cnpjEmpresa === $cnpjCertLimpo);

            // Monta resposta
            $info = [
                'sucesso' => true,
                'valido' => $valido,
                'dias_restantes' => $diasRestantes,
                'validade_de' => date('d/m/Y H:i:s', $validadeDe),
                'validade_ate' => date('d/m/Y H:i:s', $validadeAte),
                'razao_social_certificado' => $razaoSocialCertificado ?: $subject['CN'] ?? 'Não informado',
                'cnpj_certificado' => $cnpjCertificado ?: 'Não informado',
                'cnpj_empresa' => $empresa['cnpj'],
                'cnpj_corresponde' => $cnpjCorresponde,
                'serial_number' => $serialNumber,
                'emissor' => $certDetails['issuer']['CN'] ?? 'Não informado',
            ];

            $this->success('Certificado validado com sucesso', $info);
        } catch (Exception $e) {
            error_log("Erro ao testar certificado: " . $e->getMessage());
            $this->error('Erro ao testar certificado: ' . $e->getMessage());
        }
    }

    /**
     * Lista tabelas de preço da empresa
     */
    public function listarTabelasPreco(): void
    {
        try {
            $companyId = $this->request->get('company_id') ?: $this->getCompanyId();

            $stmt = $this->db->prepare("
                SELECT id, nome, descricao, tipo, ativo, ordem, created_at, updated_at
                FROM tabela_preco
                WHERE company_id = :company_id
                ORDER BY ordem ASC, nome ASC
            ");
            $stmt->execute(['company_id' => $companyId]);
            $tabelas = $stmt->fetchAll();

            $this->success('Tabelas de preço carregadas', $tabelas);
        } catch (Exception $e) {
            error_log("Erro ao listar tabelas de preço: " . $e->getMessage());
            $this->error('Erro ao carregar tabelas de preço');
        }
    }

    /**
     * Faz download do certificado digital
     */
    public function downloadCertificado(): void
    {
        try {
            // Verificar permissão de visualização
            if (!$this->canView('empresas')) {
                header('HTTP/1.1 403 Forbidden');
                echo 'Você não tem permissão para fazer download do certificado.';
                exit;
            }

            $id = $this->request->get('id');

            if (!$id) {
                header('HTTP/1.1 400 Bad Request');
                echo 'ID da empresa não informado';
                exit;
            }

            // Busca dados da empresa
            $stmt = $this->db->prepare("SELECT id, razao_social, cnpj, certificado_path FROM empresas WHERE id = :id LIMIT 1");
            $stmt->execute(['id' => $id]);
            $empresa = $stmt->fetch();

            if (!$empresa) {
                header('HTTP/1.1 404 Not Found');
                echo 'Empresa não encontrada';
                exit;
            }

            if (empty($empresa['certificado_path'])) {
                header('HTTP/1.1 404 Not Found');
                echo 'Certificado digital não configurado para esta empresa';
                exit;
            }

            $certPath = \ROOT_PATH . $empresa['certificado_path'];

            if (!file_exists($certPath)) {
                header('HTTP/1.1 404 Not Found');
                echo 'Arquivo do certificado não encontrado';
                exit;
            }

            if (!is_readable($certPath)) {
                header('HTTP/1.1 403 Forbidden');
                echo 'Certificado digital não pode ser lido. Verifique as permissões do arquivo.';
                exit;
            }

            // Nome do arquivo para download
            $cnpj = preg_replace('/\D/', '', $empresa['cnpj']);
            $filename = 'certificado_' . $cnpj . '.pfx';

            // Definir headers para download
            header('Content-Type: application/x-pkcs12');
            header('Content-Disposition: attachment; filename="' . $filename . '"');
            header('Content-Length: ' . filesize($certPath));
            header('Cache-Control: private, max-age=0, must-revalidate');
            header('Pragma: public');

            // Enviar arquivo
            readfile($certPath);
            exit;
        } catch (Exception $e) {
            error_log("Erro ao fazer download do certificado: " . $e->getMessage());
            header('HTTP/1.1 500 Internal Server Error');
            echo 'Erro ao fazer download do certificado: ' . $e->getMessage();
            exit;
        }
    }

    /**
     * Busca uma tabela de preço por ID
     */
    public function buscarTabelaPreco(): void
    {
        try {
            $id = (int) $this->request->get('id');
            $companyId = $this->getCompanyId();

            $stmt = $this->db->prepare("
                SELECT id, nome, descricao, tipo, ativo, ordem, created_at, updated_at
                FROM tabela_preco
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute(['id' => $id, 'company_id' => $companyId]);
            $tabela = $stmt->fetch();

            if ($tabela) {
                $this->success('Tabela de preço encontrada', $tabela);
            } else {
                $this->error('Tabela de preço não encontrada');
            }
        } catch (Exception $e) {
            error_log("Erro ao buscar tabela de preço: " . $e->getMessage());
            $this->error('Erro ao buscar tabela de preço');
        }
    }

    /**
     * Cria uma nova tabela de preço
     */
    public function criarTabelaPreco(): void
    {
        try {
            $companyId = $this->request->post('company_id') ?: $this->getCompanyId();

            $data = [
                'company_id' => $companyId,
                'nome' => $this->request->post('nome'),
                'descricao' => $this->request->post('descricao') ?: null,
                'tipo' => $this->request->post('tipo', 'padrao'),
                'ativo' => $this->request->post('ativo') ? 1 : 0,
                'ordem' => (int) ($this->request->post('ordem') ?: 0)
            ];

            // Validar nome obrigatório
            if (empty($data['nome'])) {
                $this->error('Nome da tabela é obrigatório');
                return;
            }

            // Verificar se já existe tabela com mesmo nome
            $stmtCheck = $this->db->prepare("
                SELECT id FROM tabela_preco
                WHERE company_id = :company_id AND nome = :nome
            ");
            $stmtCheck->execute(['company_id' => $companyId, 'nome' => $data['nome']]);
            if ($stmtCheck->fetch()) {
                $this->error('Já existe uma tabela de preço com este nome');
                return;
            }

            $stmt = $this->db->prepare("
                INSERT INTO tabela_preco (company_id, nome, descricao, tipo, ativo, ordem, created_at, updated_at)
                VALUES (:company_id, :nome, :descricao, :tipo, :ativo, :ordem, NOW(), NOW())
            ");
            $stmt->execute($data);

            $tabelaId = (int) $this->db->lastInsertId();
            $this->logActivity('create', 'tabela_preco', $tabelaId, $data);

            $this->success('Tabela de preço criada com sucesso', ['id' => $tabelaId]);
        } catch (Exception $e) {
            error_log("Erro ao criar tabela de preço: " . $e->getMessage());
            $this->error('Erro ao criar tabela de preço: ' . $e->getMessage());
        }
    }

    /**
     * Atualiza uma tabela de preço
     */
    public function atualizarTabelaPreco(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $companyId = $this->getCompanyId();

            // Verificar se a tabela existe
            $stmtCheck = $this->db->prepare("
                SELECT id FROM tabela_preco
                WHERE id = :id AND company_id = :company_id
            ");
            $stmtCheck->execute(['id' => $id, 'company_id' => $companyId]);
            if (!$stmtCheck->fetch()) {
                $this->error('Tabela de preço não encontrada');
                return;
            }

            $data = [
                'nome' => $this->request->post('nome'),
                'descricao' => $this->request->post('descricao') ?: null,
                'tipo' => $this->request->post('tipo', 'padrao'),
                'ativo' => $this->request->post('ativo') ? 1 : 0,
                'ordem' => (int) ($this->request->post('ordem') ?: 0),
                'id' => $id,
                'company_id' => $companyId
            ];

            // Validar nome obrigatório
            if (empty($data['nome'])) {
                $this->error('Nome da tabela é obrigatório');
                return;
            }

            // Verificar se já existe outra tabela com mesmo nome
            $stmtCheckNome = $this->db->prepare("
                SELECT id FROM tabela_preco
                WHERE company_id = :company_id AND nome = :nome AND id != :id
            ");
            $stmtCheckNome->execute([
                'company_id' => $companyId,
                'nome' => $data['nome'],
                'id' => $id
            ]);
            if ($stmtCheckNome->fetch()) {
                $this->error('Já existe outra tabela de preço com este nome');
                return;
            }

            $stmt = $this->db->prepare("
                UPDATE tabela_preco SET
                    nome = :nome,
                    descricao = :descricao,
                    tipo = :tipo,
                    ativo = :ativo,
                    ordem = :ordem,
                    updated_at = NOW()
                WHERE id = :id AND company_id = :company_id
            ");
            $stmt->execute($data);

            $this->logActivity('update', 'tabela_preco', $id, $data);
            $this->success('Tabela de preço atualizada com sucesso');
        } catch (Exception $e) {
            error_log("Erro ao atualizar tabela de preço: " . $e->getMessage());
            $this->error('Erro ao atualizar tabela de preço: ' . $e->getMessage());
        }
    }

    /**
     * Exclui uma tabela de preço
     */
    public function excluirTabelaPreco(): void
    {
        try {
            $id = (int) $this->request->post('id');
            $companyId = $this->getCompanyId();

            // Verificar se a tabela existe
            $stmtCheck = $this->db->prepare("
                SELECT id, nome FROM tabela_preco
                WHERE id = :id AND company_id = :company_id
            ");
            $stmtCheck->execute(['id' => $id, 'company_id' => $companyId]);
            $tabela = $stmtCheck->fetch();

            if (!$tabela) {
                $this->error('Tabela de preço não encontrada');
                return;
            }

            // Verificar se há produtos usando esta tabela
            $stmtCheckUso = $this->db->query("SHOW TABLES LIKE 'produto_preco'");
            if ($stmtCheckUso->rowCount() > 0) {
                $stmtUso = $this->db->prepare("
                    SELECT COUNT(*) as total
                    FROM produto_preco
                    WHERE descricao LIKE :nome_tabela
                ");
                $stmtUso->execute(['nome_tabela' => 'Tabela: ' . $tabela['nome'] . '%']);
                $uso = $stmtUso->fetch();

                if ($uso && $uso['total'] > 0) {
                    $this->error("Não é possível excluir esta tabela. Existem {$uso['total']} produto(s) utilizando esta tabela de preço.");
                    return;
                }
            }

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

            $this->logActivity('delete', 'tabela_preco', $id, $tabela);
            $this->success('Tabela de preço excluída com sucesso');
        } catch (Exception $e) {
            error_log("Erro ao excluir tabela de preço: " . $e->getMessage());
            $this->error('Erro ao excluir tabela de preço: ' . $e->getMessage());
        }
    }

    /**
     * Testar conexão com a Shipay
     */
    public function testarShipay(): void
    {
        try {
            $id = $this->request->get('id');

            if (!$id) {
                $this->error('ID da empresa não informado');
                return;
            }

            // Busca dados da empresa
            $stmt = $this->db->prepare("
                SELECT id, razao_social, cnpj,
                       shipay_enabled, shipay_environment, shipay_access_key,
                       shipay_secret_key, shipay_client_id
                FROM empresas
                WHERE id = :id LIMIT 1
            ");
            $stmt->execute(['id' => $id]);
            $empresa = $stmt->fetch();

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

            if (empty($empresa['shipay_enabled'])) {
                $this->error('Integração Shipay não está ativada para esta empresa');
                return;
            }

            if (empty($empresa['shipay_access_key']) || empty($empresa['shipay_secret_key']) || empty($empresa['shipay_client_id'])) {
                $this->error('Credenciais da Shipay não estão configuradas completamente');
                return;
            }

            // Preparar configuração
            $paymentConfig = require \ROOT_PATH . '/config/payment.php';
            $shipayConfig = [
                'access_key' => $empresa['shipay_access_key'],
                'secret_key' => $empresa['shipay_secret_key'],
                'client_id' => $empresa['shipay_client_id'],
                'environment' => $empresa['shipay_environment'] ?? 'sandbox',
                'base_url' => $paymentConfig['shipay']['base_url'] ?? [],
            ];

            // Testar conexão
            $shipay = new \App\Integrations\ShipayClient($shipayConfig);
            $result = $shipay->testConnection();

            if ($result['success']) {
                $this->success('Conexão com Shipay estabelecida com sucesso!', [
                    'ambiente' => $result['environment'] === 'production' ? 'Produção' : 'Sandbox (Homologação)',
                    'url_base' => $result['base_url'],
                ]);
            } else {
                $this->error('Erro ao conectar com Shipay: ' . $result['message']);
            }

        } catch (Exception $e) {
            error_log("Erro ao testar Shipay: " . $e->getMessage());
            $this->error('Erro ao testar conexão Shipay: ' . $e->getMessage());
        }
    }

    /**
     * Cria a tabela de fórmulas de custo se não existir
     */
    private function garantirTabelaFormulasCusto(): void
    {
        try {
            $stmt = $this->db->query("SHOW TABLES LIKE 'empresas_formulas_custo'");
            if ($stmt->rowCount() === 0) {
                $this->db->exec("
                    CREATE TABLE IF NOT EXISTS `empresas_formulas_custo` (
                        `id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
                        `empresa_id` INT(11) UNSIGNED NOT NULL,
                        `nome` VARCHAR(255) NOT NULL,
                        `formula` TEXT NOT NULL,
                        `ordem` INT(11) DEFAULT 0,
                        `ativo` TINYINT(1) DEFAULT 1,
                        `created_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
                        `updated_at` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
                        PRIMARY KEY (`id`),
                        KEY `idx_empresa_id` (`empresa_id`),
                        KEY `idx_ativo` (`ativo`)
                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
                ");
            }
        } catch (Exception $e) {
            error_log("Erro ao criar tabela empresas_formulas_custo: " . $e->getMessage());
        }
    }

    /**
     * Busca fórmulas de custo de uma empresa
     */
    public function buscarFormulasCusto(): void
    {
        try {
            $empresaId = (int) $this->request->get('empresa_id', 0);
            $id = $this->request->get('id', null);

            if ($empresaId <= 0) {
                $this->response->json([
                    'success' => false,
                    'message' => 'ID da empresa inválido'
                ]);
                return;
            }

            $this->garantirTabelaFormulasCusto();

            if ($id) {
                // Buscar fórmula específica
                $stmt = $this->db->prepare("
                    SELECT * FROM empresas_formulas_custo
                    WHERE id = :id AND empresa_id = :empresa_id
                    LIMIT 1
                ");
                $stmt->execute(['id' => $id, 'empresa_id' => $empresaId]);
                $formula = $stmt->fetch();

                if ($formula) {
                    $this->response->json([
                        'success' => true,
                        'data' => [$formula]
                    ]);
                } else {
                    $this->response->json([
                        'success' => false,
                        'message' => 'Fórmula não encontrada'
                    ]);
                }
            } else {
                // Buscar todas as fórmulas da empresa
                $stmt = $this->db->prepare("
                    SELECT * FROM empresas_formulas_custo
                    WHERE empresa_id = :empresa_id
                    ORDER BY ordem ASC, id ASC
                ");
                $stmt->execute(['empresa_id' => $empresaId]);
                $formulas = $stmt->fetchAll();

                $this->response->json([
                    'success' => true,
                    'data' => $formulas
                ]);
            }
        } catch (Exception $e) {
            error_log("Erro ao buscar fórmulas de custo: " . $e->getMessage());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao buscar fórmulas: ' . $e->getMessage()
            ]);
        }
    }

    /**
     * Salva uma fórmula de custo
     */
    public function salvarFormulaCusto(): void
    {
        try {
            $empresaId = (int) $this->request->post('empresa_id', 0);
            $nome = trim($this->request->post('nome', ''));
            $formula = $this->request->post('formula', '');
            $ordem = (int) $this->request->post('ordem', 0);
            $id = $this->request->post('id', null);

            if ($empresaId <= 0) {
                $this->response->json([
                    'success' => false,
                    'message' => 'ID da empresa inválido'
                ]);
                return;
            }

            if (empty($nome)) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Nome da fórmula é obrigatório'
                ]);
                return;
            }

            if (empty($formula)) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Fórmula é obrigatória'
                ]);
                return;
            }

            // Validar se é JSON válido
            $formulaArray = json_decode($formula, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                $this->response->json([
                    'success' => false,
                    'message' => 'Fórmula inválida. Erro: ' . json_last_error_msg()
                ]);
                return;
            }

            $this->garantirTabelaFormulasCusto();

            if ($id) {
                // Atualizar
                $stmt = $this->db->prepare("
                    UPDATE empresas_formulas_custo
                    SET nome = :nome, formula = :formula, ordem = :ordem, updated_at = NOW()
                    WHERE id = :id AND empresa_id = :empresa_id
                ");
                $stmt->execute([
                    'id' => $id,
                    'empresa_id' => $empresaId,
                    'nome' => $nome,
                    'formula' => $formula,
                    'ordem' => $ordem
                ]);
            } else {
                // Inserir
                $stmt = $this->db->prepare("
                    INSERT INTO empresas_formulas_custo (empresa_id, nome, formula, ordem, created_at, updated_at)
                    VALUES (:empresa_id, :nome, :formula, :ordem, NOW(), NOW())
                ");
                $stmt->execute([
                    'empresa_id' => $empresaId,
                    'nome' => $nome,
                    'formula' => $formula,
                    'ordem' => $ordem
                ]);
                $id = $this->db->lastInsertId();
            }

            $this->response->json([
                'success' => true,
                'message' => 'Fórmula salva com sucesso',
                'data' => ['id' => $id]
            ]);
        } catch (Exception $e) {
            error_log("Erro ao salvar fórmula de custo: " . $e->getMessage());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao salvar fórmula: ' . $e->getMessage()
            ]);
        }
    }

    /**
     * Remove uma fórmula de custo
     */
    public function removerFormulaCusto(): void
    {
        try {
            $id = (int) $this->request->post('id', 0);
            $empresaId = (int) $this->request->post('empresa_id', 0);

            if ($id <= 0 || $empresaId <= 0) {
                $this->response->json([
                    'success' => false,
                    'message' => 'ID inválido'
                ]);
                return;
            }

            $stmt = $this->db->prepare("
                DELETE FROM empresas_formulas_custo
                WHERE id = :id AND empresa_id = :empresa_id
            ");
            $stmt->execute([
                'id' => $id,
                'empresa_id' => $empresaId
            ]);

            $this->response->json([
                'success' => true,
                'message' => 'Fórmula removida com sucesso'
            ]);
        } catch (Exception $e) {
            error_log("Erro ao remover fórmula de custo: " . $e->getMessage());
            $this->response->json([
                'success' => false,
                'message' => 'Erro ao remover fórmula: ' . $e->getMessage()
            ]);
        }
    }
}
