<?php

declare(strict_types=1);

namespace App\Controllers;

use Exception;
use App\Helpers\UrlHelper;

/**
 * Controller de Contas Bancárias
 */
class ContasController extends BaseController
{
    /**
     * Lista todas as contas bancárias
     */
    public function index(): void
    {
        // Verificar permissão de visualização
        if (!$this->canView('contas')) {
            $this->response->forbidden('Você não tem permissão para visualizar contas bancárias.');
            return;
        }

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

            // Paginação
            $perPage = 50;
            $page = max(1, (int) ($this->request->get('page') ?? 1));
            $offset = ($page - 1) * $perPage;

            // Contar total de contas
            $stmtCount = $this->db->prepare("
                SELECT COUNT(*) as total
                FROM contas_bancarias
                WHERE company_id = :company_id
            ");
            $stmtCount->execute(['company_id' => $companyId]);
            $total = (int) $stmtCount->fetch()['total'];
            $totalPages = max(1, (int) ceil($total / $perPage));

            // Buscar contas (paginado)
            $stmt = $this->db->prepare("
                SELECT * FROM contas_bancarias
                WHERE company_id = :company_id
                ORDER BY bank_name ASC
                LIMIT :limit OFFSET :offset
            ");
            $stmt->bindValue(':company_id', $companyId, \PDO::PARAM_INT);
            $stmt->bindValue(':limit', $perPage, \PDO::PARAM_INT);
            $stmt->bindValue(':offset', $offset, \PDO::PARAM_INT);
            $stmt->execute();
            $contas = $stmt->fetchAll();

            $this->view('contas/index', [
                'contas' => $contas,
                'pageTitle' => 'Contas Bancárias',
                'activeMenu' => 'contas',
                'page' => $page,
                'perPage' => $perPage,
                'total' => $total,
                'totalPages' => $totalPages
            ]);

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

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

        $bancos = $this->getBancosDisponiveis();

        $this->view('contas/create', [
            'bancos' => $bancos,
            'pageTitle' => 'Nova Conta Bancária',
            'activeMenu' => 'contas'
        ]);
    }

    /**
     * Salva nova conta bancária
     */
    public function store(): void
    {
        // Verificar permissão de criação
        if (!$this->canCreate('contas')) {
            $this->response->forbidden('Você não tem permissão para criar contas bancárias.');
            return;
        }

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

            // Processar upload de certificado e chave privada se houver
            $certificados = $this->processarUploadCertificados(null);

            $data = [
                'company_id' => $companyId,
                'bank_name' => $this->request->post('bank_name'),
                'bank_code' => $this->request->post('bank_code'),
                'agency' => $this->request->post('agency'),
                'account_number' => $this->request->post('account_number'),
                'account_type' => $this->request->post('account_type') ?: 'corrente',
                'pix_key' => $this->request->post('pix_key'),
                'pix_key_type' => $this->request->post('pix_key_type'),
                'manager_name' => $this->request->post('manager_name'),
                'manager_phone' => $this->request->post('manager_phone'),
                'credit_limit' => $this->request->post('credit_limit') ?: 0.00,
                'notes' => $this->request->post('notes'),
                'balance' => $this->request->post('balance') ?: 0.00,
                'is_active' => 1,
                // Campos específicos por banco
                'nosso_numero' => $this->request->post('nosso_numero'),
                'variacao_carteira' => $this->request->post('variacao_carteira'),
                'modalidade' => $this->request->post('modalidade'),
                'posto' => $this->request->post('posto'),
                'byte_id' => $this->request->post('byte_id'),
                'cooperativa' => $this->request->post('cooperativa'),
                'chave_api' => $this->request->post('chave_api'), // Client ID (Banco Inter/Itaú)
                'client_secret' => $this->request->post('client_secret'), // Client Secret (Banco Inter/Itaú)
                'token_webhook' => $this->request->post('token_webhook'),
                // Campos específicos Itaú
                'digito_conta_itau' => $this->request->post('digito_conta_itau'),
                'is_producao_itau' => $this->request->post('is_producao_itau', '0') === '1' ? 1 : 0,
                'certificado_path' => $certificados['certificado'],
                'chave_privada_path' => $certificados['chave_privada'],
                'certificado_senha' => $this->request->post('certificado_senha'),
            ];

            $errors = $this->validate([
                'bank_name' => 'required|min:2',
            ]);

            if (!empty($errors)) {
                $this->error('Dados inválidos', $errors);
                return;
            }

            $this->db->beginTransaction();

            // Verificar quais colunas existem na tabela
            $stmtCols = $this->db->query("SHOW COLUMNS FROM contas_bancarias");
            $colunas = $stmtCols->fetchAll(\PDO::FETCH_COLUMN, 0);

            $campos = ['company_id', 'bank_name', 'bank_code', 'agency', 'account_number',
                'account_type', 'pix_key', 'pix_key_type', 'manager_name', 'manager_phone',
                'credit_limit', 'notes', 'balance', 'is_active',
                'nosso_numero', 'variacao_carteira', 'modalidade', 'posto', 'byte_id', 'cooperativa',
                'chave_api', 'token_webhook', 'certificado_path', 'chave_privada_path', 'certificado_senha'];
            $valores = [':company_id', ':bank_name', ':bank_code', ':agency', ':account_number',
                ':account_type', ':pix_key', ':pix_key_type', ':manager_name', ':manager_phone',
                ':credit_limit', ':notes', ':balance', ':is_active',
                ':nosso_numero', ':variacao_carteira', ':modalidade', ':posto', ':byte_id', ':cooperativa',
                ':chave_api', ':token_webhook', ':certificado_path', ':chave_privada_path', ':certificado_senha'];

            // Adicionar campos do Itaú se as colunas existirem
            if (in_array('client_secret', $colunas)) {
                $campos[] = 'client_secret';
                $valores[] = ':client_secret';
            }
            if (in_array('digito_conta_itau', $colunas)) {
                $campos[] = 'digito_conta_itau';
                $valores[] = ':digito_conta_itau';
            }
            if (in_array('is_producao_itau', $colunas)) {
                $campos[] = 'is_producao_itau';
                $valores[] = ':is_producao_itau';
            }

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

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

            $stmt->execute($data);
            $contaId = (int) $this->db->lastInsertId();

            $this->logActivity('create', 'contas_bancarias', $contaId, $data);

            $this->db->commit();

            $this->success('Conta bancária criada com sucesso', [
                'id' => $contaId,
                'redirect' => UrlHelper::url('/contas')
            ]);

        } catch (Exception $e) {
            $this->db->rollBack();
            error_log("Erro ao criar conta: " . $e->getMessage());
            $this->error('Erro ao cadastrar conta bancária: ' . $e->getMessage());
        }
    }

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

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

            if (!$conta) {
                $this->response->notFound('Conta bancária não encontrada');
                return;
            }

            $bancos = $this->getBancosDisponiveis();

            $this->view('contas/edit', [
                'conta' => $conta,
                'bancos' => $bancos,
                'pageTitle' => 'Editar Conta Bancária',
                'activeMenu' => 'contas'
            ]);

        } catch (Exception $e) {
            error_log("Erro ao exibir formulário de edição: " . $e->getMessage());
            $this->error('Erro ao carregar formulário');
        }
    }

    /**
     * Atualiza uma conta bancária
     */
    public function update(): void
    {
        // Verificar permissão de edição
        if (!$this->canEdit('contas')) {
            $this->response->forbidden('Você não tem permissão para editar contas bancárias.');
            return;
        }

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

            if (!$conta) {
                $this->error('Conta bancária não encontrada');
                return;
            }

            // Processar upload de certificados (novo ou remoção)
            $certificados = $this->processarUploadCertificados($conta);

            $data = [
                'bank_name' => $this->request->post('bank_name'),
                'bank_code' => $this->request->post('bank_code'),
                'agency' => $this->request->post('agency'),
                'account_number' => $this->request->post('account_number'),
                'account_type' => $this->request->post('account_type') ?: 'corrente',
                'pix_key' => $this->request->post('pix_key'),
                'pix_key_type' => $this->request->post('pix_key_type'),
                'manager_name' => $this->request->post('manager_name'),
                'manager_phone' => $this->request->post('manager_phone'),
                'credit_limit' => $this->request->post('credit_limit') ?: 0.00,
                'notes' => $this->request->post('notes'),
                'balance' => $this->request->post('balance') ?: 0.00,
                'is_active' => $this->request->post('is_active', '0') === '1' ? 1 : 0,
                // Campos específicos por banco
                'nosso_numero' => $this->request->post('nosso_numero'),
                'variacao_carteira' => $this->request->post('variacao_carteira'),
                'modalidade' => $this->request->post('modalidade'),
                'posto' => $this->request->post('posto'),
                'byte_id' => $this->request->post('byte_id'),
                'cooperativa' => $this->request->post('cooperativa'),
                'chave_api' => $this->request->post('chave_api'), // Client ID
                'client_secret' => $this->request->post('client_secret'), // Client Secret
                'token_webhook' => $this->request->post('token_webhook'),
                // Campos específicos Itaú
                'digito_conta_itau' => $this->request->post('digito_conta_itau'),
                'is_producao_itau' => $this->request->post('is_producao_itau', '0') === '1' ? 1 : 0,
                'certificado_path' => $certificados['certificado'],
                'chave_privada_path' => $certificados['chave_privada'],
                'certificado_senha' => $this->request->post('certificado_senha'),
                'id' => $id
            ];

            $errors = $this->validate([
                'bank_name' => 'required|min:2',
            ]);

            if (!empty($errors)) {
                $this->error('Dados inválidos', $errors);
                return;
            }

            $this->db->beginTransaction();

            // Verificar quais colunas existem na tabela
            $stmtCols = $this->db->query("SHOW COLUMNS FROM contas_bancarias");
            $colunas = $stmtCols->fetchAll(\PDO::FETCH_COLUMN, 0);

            $sets = [
                'bank_name = :bank_name',
                'bank_code = :bank_code',
                'agency = :agency',
                'account_number = :account_number',
                'account_type = :account_type',
                'pix_key = :pix_key',
                'pix_key_type = :pix_key_type',
                'manager_name = :manager_name',
                'manager_phone = :manager_phone',
                'credit_limit = :credit_limit',
                'notes = :notes',
                'balance = :balance',
                'is_active = :is_active',
                'nosso_numero = :nosso_numero',
                'variacao_carteira = :variacao_carteira',
                'modalidade = :modalidade',
                'posto = :posto',
                'byte_id = :byte_id',
                'cooperativa = :cooperativa',
                'chave_api = :chave_api',
                'token_webhook = :token_webhook',
                'certificado_path = :certificado_path',
                'chave_privada_path = :chave_privada_path',
                'certificado_senha = :certificado_senha',
                'updated_at = NOW()'
            ];

            // Adicionar campos do Itaú se as colunas existirem
            if (in_array('client_secret', $colunas)) {
                $sets[] = 'client_secret = :client_secret';
            }
            if (in_array('digito_conta_itau', $colunas)) {
                $sets[] = 'digito_conta_itau = :digito_conta_itau';
            }
            if (in_array('is_producao_itau', $colunas)) {
                $sets[] = 'is_producao_itau = :is_producao_itau';
            }

            $sql = "UPDATE contas_bancarias SET " . implode(', ', $sets) . " WHERE id = :id AND company_id = :company_id";
            $stmt = $this->db->prepare($sql);

            $data['company_id'] = $this->getCompanyId();
            $stmt->execute($data);

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

            $this->db->commit();

            $this->success('Conta bancária atualizada com sucesso', [
                'redirect' => UrlHelper::url('/contas')
            ]);

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

    /**
     * Exclui uma conta bancária
     */
    public function delete(): void
    {
        // Verificar permissão de exclusão
        if (!$this->canDelete('contas')) {
            $this->response->forbidden('Você não tem permissão para excluir contas bancárias.');
            return;
        }

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

            if (!$conta) {
                $this->error('Conta bancária não encontrada');
                return;
            }

            $this->db->beginTransaction();

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

            $this->logActivity('delete', 'contas_bancarias', $id, $conta);

            $this->db->commit();

            $this->success('Conta bancária excluída com sucesso');

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

    /**
     * Busca uma conta bancária por ID
     */
    private function getConta(int $id): ?array
    {
        $stmt = $this->db->prepare("
            SELECT * FROM contas_bancarias
            WHERE id = :id AND company_id = :company_id
        ");
        $stmt->execute([
            'id' => $id,
            'company_id' => $this->getCompanyId()
        ]);

        return $stmt->fetch() ?: null;
    }

    /**
     * Busca bancos disponíveis para boleto
     */
    private function getBancosDisponiveis(): array
    {
        try {
            $stmt = $this->db->prepare("
                SELECT * FROM bancos_config
                WHERE ativo = 1
                ORDER BY nome ASC
            ");
            $stmt->execute();
            return $stmt->fetchAll();
        } catch (Exception $e) {
            error_log("Erro ao buscar bancos: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Processa upload do certificado digital (.crt) e chave privada (.key)
     *
     * @param array|null $conta Conta existente (para edição) ou null (para criação)
     * @return array Array com 'certificado' e 'chave_privada' (ou null)
     */
    private function processarUploadCertificados(?array $conta): array
    {
        $result = [
            'certificado' => null,
            'chave_privada' => null
        ];

        // Processar certificado (.crt)
        $certificadoPathAtual = $this->request->post('certificado_path_atual');
        $hasNewCertificado = isset($_FILES['certificado_file']) && $_FILES['certificado_file']['error'] === UPLOAD_ERR_OK;

        if ($hasNewCertificado) {
            $arquivo = $_FILES['certificado_file'];
            $result['certificado'] = $this->processarArquivoCertificado($arquivo, 'cert', $conta);
        } elseif ($conta && !empty($certificadoPathAtual)) {
            $result['certificado'] = $certificadoPathAtual;
        } elseif ($conta && !empty($conta['certificado_path'])) {
            // Remover arquivo antigo
            $caminhoAntigo = \ROOT_PATH . '/' . ltrim($conta['certificado_path'], '/');
            if (file_exists($caminhoAntigo)) {
                @unlink($caminhoAntigo);
            }
        }

        // Processar chave privada (.key)
        $chavePrivadaPathAtual = $this->request->post('chave_privada_path_atual');
        $hasNewChavePrivada = isset($_FILES['chave_privada_file']) && $_FILES['chave_privada_file']['error'] === UPLOAD_ERR_OK;

        if ($hasNewChavePrivada) {
            $arquivo = $_FILES['chave_privada_file'];
            $result['chave_privada'] = $this->processarArquivoCertificado($arquivo, 'key', $conta);
        } elseif ($conta && !empty($chavePrivadaPathAtual)) {
            $result['chave_privada'] = $chavePrivadaPathAtual;
        } elseif ($conta && !empty($conta['chave_privada_path'])) {
            // Remover arquivo antigo
            $caminhoAntigo = \ROOT_PATH . '/' . ltrim($conta['chave_privada_path'], '/');
            if (file_exists($caminhoAntigo)) {
                @unlink($caminhoAntigo);
            }
        }

        return $result;
    }

    /**
     * Processa um arquivo de certificado individual
     *
     * @param array $arquivo Arquivo do $_FILES
     * @param string $tipo 'cert' ou 'key'
     * @param array|null $conta Conta existente (para remover antigo)
     * @return string Caminho relativo do arquivo salvo
     */
    private function processarArquivoCertificado(array $arquivo, string $tipo, ?array $conta): string
    {
        // Validar extensão
        $extensao = strtolower(pathinfo($arquivo['name'], PATHINFO_EXTENSION));
        $extensoesPermitidas = $tipo === 'cert' ? ['crt', 'pem'] : ['key', 'pem'];

        if (!in_array($extensao, $extensoesPermitidas)) {
            throw new Exception("Formato de arquivo não permitido para {$tipo}. Use apenas: " . implode(', ', $extensoesPermitidas));
        }

        // Validar tamanho (máximo 5MB)
        $tamanhoMax = 5 * 1024 * 1024; // 5MB
        if ($arquivo['size'] > $tamanhoMax) {
            throw new Exception('Arquivo muito grande. Tamanho máximo: 5MB');
        }

        // Criar diretório se não existir
        $uploadDir = \ROOT_PATH . '/storage/certificados';
        if (!is_dir($uploadDir)) {
            if (!mkdir($uploadDir, 0755, true)) {
                throw new Exception('Erro ao criar diretório de certificados');
            }
        }

        // Gerar nome único para o arquivo
        $companyId = $this->getCompanyId();
        $prefixo = $tipo === 'cert' ? 'inter_cert_' : 'inter_key_';
        $nomeArquivo = $prefixo . $companyId . '_' . uniqid() . '_' . time() . '.' . $extensao;
        $caminhoCompleto = $uploadDir . '/' . $nomeArquivo;

        // Mover arquivo
        if (!move_uploaded_file($arquivo['tmp_name'], $caminhoCompleto)) {
            throw new Exception("Erro ao salvar arquivo de {$tipo}");
        }

        // Se estiver editando e houver arquivo antigo do mesmo tipo, remover
        if ($conta) {
            $campo = $tipo === 'cert' ? 'certificado_path' : 'chave_privada_path';
            if (!empty($conta[$campo])) {
                $caminhoAntigo = \ROOT_PATH . '/' . ltrim($conta[$campo], '/');
                if (file_exists($caminhoAntigo)) {
                    @unlink($caminhoAntigo);
                }
            }
        }

        // Retornar caminho relativo
        return 'storage/certificados/' . $nomeArquivo;
    }
}