<?php
namespace Modules\Financeiro\Controllers;

use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Audit\AuditLogger;
use Gestoreasy\Core\Auth\UserContext;
use Gestoreasy\Core\Mail\Mailer;
use Gestoreasy\Core\Config\Config;
use Modules\Financeiro\Services\BankIntegrationStub;
use PDO;
use Exception;

class ContasPagarController {
    private PDO $db;
    

    public function __construct() {
        $this->db = ConnectionManager::forTenant();
    }

    public function list(Request $request): Response {
        try {
            $page = max(1, (int)$request->getQueryParam('page', 1));
            $perPage = min(100, max(10, (int)$request->getQueryParam('per_page', 20)));
            $status = $request->getQueryParam('status', '');
            $search = $request->getQueryParam('q', '');
            $approvalLevel = (int)($request->getQueryParam('approval_level', 0));
            $approvalStatus = (string)$request->getQueryParam('approval_status', '');
            
            $offset = ($page - 1) * $perPage;
            
            // Base query
            $whereConditions = ['1=1'];
            $params = [];
            
            if ($status && in_array($status, ['pendente', 'pago', 'vencido'])) {
                $whereConditions[] = 'status = :status';
                $params['status'] = $status;
            }
            
            if ($search) {
                $whereConditions[] = '(descricao LIKE :search OR fornecedor LIKE :search OR documento LIKE :search)';
                $params['search'] = '%' . $search . '%';
            }

            // Filtro por aprovação (status/nível)
            if ($approvalLevel > 0 && in_array($approvalStatus, ['pendente','aprovado','rejeitado'], true)) {
                $apprTableExists = $this->db->query("SHOW TABLES LIKE 'contas_pagar_aprovacoes'")->rowCount() > 0;
                $threshold = 5000.0;
                try { $threshold = (float)Config::get('FINANCE_APPROVAL_THRESHOLD_BRL', 5000.0); } catch (\Throwable $e) {}
                if ($apprTableExists) {
                    if ($approvalStatus === 'aprovado' || $approvalStatus === 'rejeitado') {
                        $whereConditions[] = 'EXISTS (SELECT 1 FROM contas_pagar_aprovacoes a WHERE a.conta_id = contas_pagar.id AND a.level = :appr_level AND a.status = :appr_status)';
                        $params['appr_level'] = $approvalLevel;
                        $params['appr_status'] = $approvalStatus;
                    } else { // pendente
                        $whereConditions[] = 'NOT EXISTS (SELECT 1 FROM contas_pagar_aprovacoes a WHERE a.conta_id = contas_pagar.id AND a.level = :appr_level AND a.status IN ("aprovado","rejeitado"))';
                        $params['appr_level'] = $approvalLevel;
                        // Garantir que o nível seja requerido conforme a regra de valor
                        if ($approvalLevel >= 2) {
                            $whereConditions[] = 'valor >= :appr_threshold';
                            $params['appr_threshold'] = $threshold;
                        }
                    }
                } else {
                    // Sem tabela de aprovações: comportamento aproximado
                    if ($approvalStatus === 'pendente') {
                        if ($approvalLevel >= 2) {
                            $whereConditions[] = 'valor >= :appr_threshold';
                            $params['appr_threshold'] = $threshold;
                        }
                    } else {
                        // aprovado/rejeitado não são possíveis sem tabela -> nenhum resultado
                        $whereConditions[] = '0=1';
                    }
                }
            }
            
            $whereClause = implode(' AND ', $whereConditions);
            
            // Check if table exists
            $tableExists = $this->db->query("SHOW TABLES LIKE 'contas_pagar'")->rowCount() > 0;
            
            if (!$tableExists) {
                return Response::json([
                    'data' => [],
                    'pagination' => [
                        'page' => $page,
                        'per_page' => $perPage,
                        'total' => 0,
                        'total_pages' => 0
                    ],
                    'message' => 'Tabela contas_pagar não encontrada. Execute as migrações.'
                ]);
            }
            
            // Count total
            $countQuery = "SELECT COUNT(*) FROM contas_pagar WHERE $whereClause";
            $countStmt = $this->db->prepare($countQuery);
            $countStmt->execute($params);
            $total = $countStmt->fetchColumn();
            
            // Get data
            $query = "SELECT * FROM contas_pagar WHERE $whereClause ORDER BY data_vencimento ASC LIMIT :limit OFFSET :offset";
            $stmt = $this->db->prepare($query);
            
            foreach ($params as $key => $value) {
                $stmt->bindValue(":$key", $value);
            }
            $stmt->bindValue(':limit', $perPage, PDO::PARAM_INT);
            $stmt->bindValue(':offset', $offset, PDO::PARAM_INT);
            
            $stmt->execute();
            $contas = $stmt->fetchAll(PDO::FETCH_ASSOC);

            // Enriquecer com resumo de aprovações (aprovadas/rejeitadas) e níveis requeridos
            foreach ($contas as &$c) {
                try {
                    $required = $this->requiredApprovalLevels((float)($c['valor'] ?? 0));
                } catch (\Throwable $e) { $required = 1; }
                $approved = 0; $rejected = 0;
                $levels = [];
                try {
                    // Resumo por status
                    $st = $this->db->prepare('SELECT status, COUNT(*) as cnt FROM contas_pagar_aprovacoes WHERE conta_id = ? GROUP BY status');
                    $st->execute([(int)($c['id'] ?? 0)]);
                    $rows = $st->fetchAll(PDO::FETCH_ASSOC);
                    foreach ($rows as $r) {
                        if (($r['status'] ?? '') === 'aprovado') { $approved = (int)($r['cnt'] ?? 0); }
                        if (($r['status'] ?? '') === 'rejeitado') { $rejected = (int)($r['cnt'] ?? 0); }
                    }
                    // Estados por nível
                    $st2 = $this->db->prepare('SELECT level, status FROM contas_pagar_aprovacoes WHERE conta_id = ?');
                    $st2->execute([(int)($c['id'] ?? 0)]);
                    $rows2 = $st2->fetchAll(PDO::FETCH_ASSOC);
                    $map = [];
                    foreach ($rows2 as $r2) { $lvl = (int)($r2['level'] ?? 0); if ($lvl > 0) { $map[$lvl] = (string)($r2['status'] ?? 'pendente'); } }
                    for ($i = 1; $i <= (int)$required; $i++) {
                        $levels[] = [ 'level' => $i, 'status' => ($map[$i] ?? 'pendente') ];
                    }
                } catch (\Throwable $e) { /* noop */ }
                $c['approval_required_levels'] = (int)$required;
                $c['approval_approved_levels'] = (int)$approved;
                $c['approval_rejected_levels'] = (int)$rejected;
                $c['approval_levels'] = $levels;
            }
            
            // Log audit (read)
            AuditLogger::logRead('contas_pagar', null, [
                'filters' => compact('status', 'search'),
                'pagination' => compact('page', 'perPage')
            ]);
            
            return Response::json([
                'data' => $contas,
                'pagination' => [
                    'page' => $page,
                    'per_page' => $perPage,
                    'total' => (int)$total,
                    'total_pages' => ceil($total / $perPage)
                ]
            ]);
            
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao listar contas a pagar: ' . $e->getMessage()], 500);
        }
    }

    public function getById(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? $params[0] : null;
            
            $stmt = $this->db->prepare("SELECT * FROM contas_pagar WHERE id = :id");
            $stmt->execute(['id' => $id]);
            $conta = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$conta) {
                return Response::json(['error' => 'Conta não encontrada'], 404);
            }
            
            return Response::json(['data' => $conta]);
            
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao buscar conta: ' . $e->getMessage()], 500);
        }
    }

    public function create(Request $request): Response {
        try {
            $data = is_array($request->body) ? $request->body : [];
            
            // Validação básica
            $required = ['descricao', 'valor', 'data_vencimento', 'fornecedor'];
            foreach ($required as $field) {
                if (empty($data[$field])) {
                    return Response::json(['error' => "Campo '$field' é obrigatório"], 400);
                }
            }
            
            $stmt = $this->db->prepare("
                INSERT INTO contas_pagar (descricao, valor, data_vencimento, fornecedor, documento, observacoes, status, created_at)
                VALUES (:descricao, :valor, :data_vencimento, :fornecedor, :documento, :observacoes, 'pendente', NOW())
            ");
            
            $stmt->execute([
                'descricao' => $data['descricao'],
                'valor' => $data['valor'],
                'data_vencimento' => $data['data_vencimento'],
                'fornecedor' => $data['fornecedor'],
                'documento' => $data['documento'] ?? null,
                'observacoes' => $data['observacoes'] ?? null
            ]);
            
            $id = $this->db->lastInsertId();
            
            AuditLogger::logCreate('contas_pagar', (int)$id, $data);
            
            return Response::json(['message' => 'Conta criada com sucesso', 'id' => $id], 201);
            
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao criar conta: ' . $e->getMessage()], 500);
        }
    }

    public function update(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? $params[0] : null;
            $data = is_array($request->body) ? $request->body : [];
            
            // Check if exists
            $stmt = $this->db->prepare("SELECT * FROM contas_pagar WHERE id = :id");
            $stmt->execute(['id' => $id]);
            $existing = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$existing) {
                return Response::json(['error' => 'Conta não encontrada'], 404);
            }
            
            $stmt = $this->db->prepare("
                UPDATE contas_pagar 
                SET descricao = :descricao, valor = :valor, data_vencimento = :data_vencimento, 
                    fornecedor = :fornecedor, documento = :documento, observacoes = :observacoes, updated_at = NOW()
                WHERE id = :id
            ");
            
            $stmt->execute([
                'id' => $id,
                'descricao' => $data['descricao'],
                'valor' => $data['valor'],
                'data_vencimento' => $data['data_vencimento'],
                'fornecedor' => $data['fornecedor'],
                'documento' => $data['documento'] ?? null,
                'observacoes' => $data['observacoes'] ?? null
            ]);
            
            AuditLogger::logUpdate('contas_pagar', (int)$id, $existing, $data);
            
            return Response::json(['message' => 'Conta atualizada com sucesso']);
            
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao atualizar conta: ' . $e->getMessage()], 500);
        }
    }

    public function delete(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? $params[0] : null;
            
            // Check if exists
            $stmt = $this->db->prepare("SELECT * FROM contas_pagar WHERE id = :id");
            $stmt->execute(['id' => $id]);
            $conta = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$conta) {
                return Response::json(['error' => 'Conta não encontrada'], 404);
            }
            
            if ($conta['status'] === 'pago') {
                return Response::json(['error' => 'Não é possível excluir conta já paga'], 400);
            }
            
            $stmt = $this->db->prepare("DELETE FROM contas_pagar WHERE id = :id");
            $stmt->execute(['id' => $id]);
            
            AuditLogger::logDelete('contas_pagar', (int)$id, $conta);
            
            return Response::json(['message' => 'Conta excluída com sucesso']);
            
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao excluir conta: ' . $e->getMessage()], 500);
        }
    }

    public function pay(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? $params[0] : null;
            $data = is_array($request->body) ? $request->body : [];
            
            // Check if exists
            $stmt = $this->db->prepare("SELECT * FROM contas_pagar WHERE id = :id");
            $stmt->execute(['id' => $id]);
            $conta = $stmt->fetch(PDO::FETCH_ASSOC);
            
            if (!$conta) {
                return Response::json(['error' => 'Conta não encontrada'], 404);
            }
            
            if ($conta['status'] === 'pago') {
                return Response::json(['error' => 'Conta já está paga'], 400);
            }
            // Verificar aprovações necessárias antes do pagamento
            $required = $this->requiredApprovalLevels((float)($conta['valor'] ?? 0));
            if ($required > 0) {
                $aprovadas = 0;
                try {
                    $st = $this->db->prepare('SELECT COUNT(*) FROM contas_pagar_aprovacoes WHERE conta_id = ? AND status = "aprovado"');
                    $st->execute([(int)$id]);
                    $aprovadas = (int)$st->fetchColumn();
                } catch (\Throwable $e) { $aprovadas = 0; }
                if ($aprovadas < $required) {
                    return Response::json(['error' => 'Pagamento bloqueado: aprovações pendentes', 'required_levels' => $required, 'approved_levels' => $aprovadas], 403);
                }
            }

            $data_pagamento = $data['data_pagamento'] ?? date('Y-m-d');
            $valor_pago = isset($data['valor_pago']) ? (float)$data['valor_pago'] : (float)$conta['valor'];
            $forma = $data['forma_pagamento'] ?? 'dinheiro';
            // Aceitar tanto 'observacoes' quanto 'observacoes_pagamento' vindos da UI
            $obs = $data['observacoes'] ?? ($data['observacoes_pagamento'] ?? null);
            // Conta bancária (opcional) para refletir movimentação
            $contaBancariaId = isset($data['conta_bancaria_id']) ? (int)$data['conta_bancaria_id'] : 0;
            if ($contaBancariaId <= 0) {
                try {
                    $q = $this->db->query("SELECT id FROM bank_accounts WHERE status = 'ativa' ORDER BY id ASC LIMIT 1");
                    $fallbackAcc = $q->fetch(PDO::FETCH_ASSOC);
                    if ($fallbackAcc && isset($fallbackAcc['id'])) $contaBancariaId = (int)$fallbackAcc['id'];
                } catch (\Throwable $e) { /* ignore */ }
            }

            // Inserir histórico de pagamento
            try {
                $ins = $this->db->prepare("INSERT INTO contas_pagar_pagamentos (conta_id, data_pagamento, valor_pago, forma_pagamento, observacoes) VALUES (?,?,?,?,?)");
                $ins->execute([(int)$id, $data_pagamento, $valor_pago, $forma, $obs]);
            } catch (\Throwable $e) {
                // Continua mesmo sem histórico, mas registra auditoria do erro
                AuditLogger::log('error', 'contas_pagar_pagamentos', (int)$id, null, ['message' => 'Falha ao registrar histórico', 'error' => $e->getMessage()]);
            }

            // Atualizar conta como paga
            $stmt = $this->db->prepare("
                UPDATE contas_pagar 
                SET status = 'pago', data_pagamento = :data_pagamento, valor_pago = :valor_pago, 
                    forma_pagamento = :forma_pagamento, observacoes_pagamento = :observacoes, updated_at = NOW()
                WHERE id = :id
            ");
            $stmt->execute([
                'id' => $id,
                'data_pagamento' => $data_pagamento,
                'valor_pago' => $valor_pago,
                'forma_pagamento' => $forma,
                'observacoes' => $obs
            ]);

            // Se uma conta bancária foi informada, registrar saída em Bancos
            if ($contaBancariaId > 0 && $valor_pago > 0) {
                try {
                    // Buscar saldo atual
                    $stAcc = $this->db->prepare('SELECT * FROM bank_accounts WHERE id = ?');
                    $stAcc->execute([$contaBancariaId]);
                    $acc = $stAcc->fetch(PDO::FETCH_ASSOC);
                    if ($acc) {
                        $saldoAtual = (float)($acc['saldo'] ?? 0);
                        $novoSaldo = $saldoAtual - $valor_pago;
                        $descricao = sprintf('Pagamento CP #%d - %s %s', (int)$id, (string)($conta['fornecedor'] ?? ''), (string)($conta['documento'] ?? $conta['descricao'] ?? ''));
                        // Inserir movimentação com origem
                        $insMov = $this->db->prepare('INSERT INTO bank_transactions (conta_id, data, descricao, tipo, valor, saldo, source_type, source_id, created_at) VALUES (?,?,?,?,?,?,?,?, NOW())');
                        $insMov->execute([$contaBancariaId, $data_pagamento, $descricao, 'saida', $valor_pago, $novoSaldo, 'contas_pagar', (int)$id]);
                        // Atualizar saldo
                        $updAcc = $this->db->prepare('UPDATE bank_accounts SET saldo = ?, updated_at = NOW() WHERE id = ?');
                        $updAcc->execute([$novoSaldo, $contaBancariaId]);
                        // Auditoria
                        AuditLogger::logCreate('bank_transactions', (int)$this->db->lastInsertId(), [
                            'conta_id' => $contaBancariaId,
                            'data' => $data_pagamento,
                            'descricao' => $descricao,
                            'tipo' => 'saida',
                            'valor' => $valor_pago,
                            'saldo' => $novoSaldo,
                            'source_type' => 'contas_pagar',
                            'source_id' => (int)$id
                        ], ['hook' => 'contas_pagar.pay']);
                    }
                } catch (\Throwable $e) {
                    AuditLogger::log('error', 'bank_transactions', (int)$id, null, ['message' => 'Falha ao registrar saída bancária', 'error' => $e->getMessage()]);
                }
            }

            AuditLogger::log('pay', 'contas_pagar', (int)$id, $conta, $data);
            return Response::json(['message' => 'Conta paga com sucesso']);
            
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao pagar conta: ' . $e->getMessage()], 500);
        }
    }

    public function exportCsv(Request $request): Response {
        try {
            $sep = (string)$request->getQueryParam('sep', ';');
            if (!in_array($sep, [';', ',', '\t'], true)) { $sep = ';'; }
            if ($sep === '\t') { $sep = "\t"; }

            $status = (string)$request->getQueryParam('status', '');
            $search = (string)$request->getQueryParam('q', '');
            $start = (string)$request->getQueryParam('start', '');
            $end = (string)$request->getQueryParam('end', '');
            $approvalLevel = (int)($request->getQueryParam('approval_level', 0));
            $approvalStatus = (string)$request->getQueryParam('approval_status', '');

            $where = ['1=1'];
            $params = [];
            if ($status && in_array($status, ['pendente', 'pago', 'vencido'], true)) {
                $where[] = 'status = :status';
                $params['status'] = $status;
            }
            if ($search) {
                $where[] = '(descricao LIKE :search OR fornecedor LIKE :search OR documento LIKE :search)';
                $params['search'] = '%' . $search . '%';
            }
            if ($start) { $where[] = 'data_vencimento >= :start'; $params['start'] = $start; }
            if ($end) { $where[] = 'data_vencimento <= :end'; $params['end'] = $end; }

            if ($approvalLevel > 0 && in_array($approvalStatus, ['pendente','aprovado','rejeitado'], true)) {
                $apprTableExists = $this->db->query("SHOW TABLES LIKE 'contas_pagar_aprovacoes'")->rowCount() > 0;
                $threshold = 5000.0;
                try { $threshold = (float)Config::get('FINANCE_APPROVAL_THRESHOLD_BRL', 5000.0); } catch (\Throwable $e) {}
                if ($apprTableExists) {
                    if ($approvalStatus === 'aprovado' || $approvalStatus === 'rejeitado') {
                        $where[] = 'EXISTS (SELECT 1 FROM contas_pagar_aprovacoes a WHERE a.conta_id = contas_pagar.id AND a.level = :appr_level AND a.status = :appr_status)';
                        $params['appr_level'] = $approvalLevel;
                        $params['appr_status'] = $approvalStatus;
                    } else { // pendente
                        $where[] = 'NOT EXISTS (SELECT 1 FROM contas_pagar_aprovacoes a WHERE a.conta_id = contas_pagar.id AND a.level = :appr_level AND a.status IN ("aprovado","rejeitado"))';
                        $params['appr_level'] = $approvalLevel;
                        if ($approvalLevel >= 2) {
                            $where[] = 'valor >= :appr_threshold';
                            $params['appr_threshold'] = $threshold;
                        }
                    }
                } else {
                    if ($approvalStatus === 'pendente') {
                        if ($approvalLevel >= 2) {
                            $where[] = 'valor >= :appr_threshold';
                            $params['appr_threshold'] = $threshold;
                        }
                    } else {
                        $where[] = '0=1';
                    }
                }
            }
            $whereClause = implode(' AND ', $where);

            $tableExists = $this->db->query("SHOW TABLES LIKE 'contas_pagar'")->rowCount() > 0;
            if (!$tableExists) {
                return new Response(404, 'Tabela contas_pagar não encontrada');
            }

            $sql = "SELECT id, descricao, fornecedor, valor, data_vencimento, status, documento, data_pagamento, valor_pago, forma_pagamento, observacoes, created_at, updated_at FROM contas_pagar WHERE $whereClause ORDER BY data_vencimento ASC";
            $stmt = $this->db->prepare($sql);
            foreach ($params as $k => $v) { $stmt->bindValue(":$k", $v); }
            $stmt->execute();
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
            $out = fopen('php://temp', 'r+');
            fputs($out, $bom);
            $headers = [
                'ID','Descrição','Fornecedor','Valor','Vencimento','Status','Documento','Data Pagamento','Valor Pago','Forma Pagamento','Observações','Criado em','Atualizado em'
            ];
            fputcsv($out, $headers, $sep);
            $fmtDate = function (?string $s): ?string {
                if (!$s) { return null; }
                $t = strtotime($s);
                return $t ? date('d-m-Y', $t) : $s;
            };
            $fmtDateTime = function (?string $s): ?string {
                if (!$s) { return null; }
                $t = strtotime($s);
                return $t ? date('d-m-Y H:i:s', $t) : $s;
            };
            $fmtMoney = function ($n): ?string {
                if ($n === null || $n === '') { return null; }
                $f = is_numeric($n) ? (float)$n : (float)str_replace(',', '.', (string)$n);
                return number_format($f, 2, ',', '');
            };
            foreach ($rows as $r) {
                fputcsv($out, [
                    $r['id'] ?? null,
                    $r['descricao'] ?? null,
                    $r['fornecedor'] ?? null,
                    isset($r['valor']) ? $fmtMoney($r['valor']) : null,
                    isset($r['data_vencimento']) ? $fmtDate($r['data_vencimento']) : null,
                    $r['status'] ?? null,
                    $r['documento'] ?? null,
                    isset($r['data_pagamento']) ? $fmtDate($r['data_pagamento']) : null,
                    isset($r['valor_pago']) ? $fmtMoney($r['valor_pago']) : null,
                    $r['forma_pagamento'] ?? null,
                    $r['observacoes'] ?? null,
                    isset($r['created_at']) ? $fmtDateTime($r['created_at']) : null,
                    isset($r['updated_at']) ? $fmtDateTime($r['updated_at']) : null
                ], $sep);
            }
            rewind($out);
            $csv = stream_get_contents($out);
            fclose($out);
            return new Response(200, $csv, [
                'Content-Type' => 'text/csv; charset=utf-8',
                'Content-Disposition' => 'attachment; filename="contas_pagar.csv"'
            ]);
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao exportar CSV: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Histórico de pagamentos de uma conta
     */
    public function history(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? (int)$params[0] : 0;
            $stmt = $this->db->prepare('SELECT id, data_pagamento, valor_pago, forma_pagamento, observacoes, created_at FROM contas_pagar_pagamentos WHERE conta_id = ? ORDER BY data_pagamento DESC, id DESC');
            $stmt->execute([$id]);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            AuditLogger::logRead('contas_pagar_pagamentos', $id, ['count' => count($rows)]);
            return Response::json(['data' => $rows]);
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao obter histórico: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Histórico de aprovações (multi-nível) de uma conta
     */
    public function approvalHistory(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? (int)$params[0] : 0;
            $sql = 'SELECT a.id, a.level, a.status, a.approved_by, u.name AS approved_by_name, a.approved_at, a.notes, a.created_at, a.updated_at '
                 . 'FROM contas_pagar_aprovacoes a '
                 . 'LEFT JOIN users u ON u.id = a.approved_by '
                 . 'WHERE a.conta_id = ? ORDER BY a.level ASC, a.id ASC';
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$id]);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            AuditLogger::logRead('contas_pagar_aprovacoes', $id, ['count' => count($rows)]);
            return Response::json(['data' => $rows]);
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao obter aprovações: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Aprovação de conta (multi-nível)
     */
    public function approve(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? (int)$params[0] : 0;
            $body = is_array($request->body) ? $request->body : [];
            $level = max(1, (int)($body['level'] ?? 1));
            $status = (string)($body['status'] ?? 'aprovado');
            if (!in_array($status, ['aprovado','rejeitado'], true)) {
                return Response::json(['error' => 'status inválido'], 422);
            }
            $user = UserContext::get($request) ?? [];
            $userId = (int)($user['sub'] ?? ($user['id'] ?? 0));
            $notes = (string)($body['notes'] ?? '');

            // Verificar existência da conta
            $chk = $this->db->prepare('SELECT id, valor FROM contas_pagar WHERE id = ?');
            $chk->execute([$id]);
            $conta = $chk->fetch(PDO::FETCH_ASSOC);
            if (!$conta) { return Response::json(['error' => 'Conta não encontrada'], 404); }

            // Upsert aprovação
            $sel = $this->db->prepare('SELECT id FROM contas_pagar_aprovacoes WHERE conta_id = ? AND level = ?');
            $sel->execute([$id, $level]);
            $row = $sel->fetch(PDO::FETCH_ASSOC);
            if ($row && isset($row['id'])) {
                $upd = $this->db->prepare('UPDATE contas_pagar_aprovacoes SET status = ?, approved_by = ?, approved_at = NOW(), notes = ? WHERE id = ?');
                $upd->execute([$status, $userId ?: null, $notes ?: null, (int)$row['id']]);
                $apprId = (int)$row['id'];
            } else {
                $ins = $this->db->prepare('INSERT INTO contas_pagar_aprovacoes (conta_id, level, status, approved_by, approved_at, notes) VALUES (?,?,?,?,NOW(),?)');
                $ins->execute([$id, $level, $status, $userId ?: null, $notes ?: null]);
                $apprId = (int)$this->db->lastInsertId();
            }

            AuditLogger::logUpdate('contas_pagar_aprovacoes', $apprId, [], ['conta_id' => $id, 'level' => $level, 'status' => $status]);
            return Response::json(['message' => 'Ação de aprovação registrada', 'approval_id' => $apprId]);
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao aprovar: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Conciliação bancária de uma conta
     */
    public function reconcile(Request $request): Response {
        try {
        $params = $request->get('params', []);
        $id = isset($params[0]) ? (int)$params[0] : 0;
            $body = is_array($request->body) ? $request->body : [];
            $reference = trim((string)($body['reference'] ?? ''));
            if ($reference === '') { return Response::json(['error' => 'reference requerido'], 422); }

            // Verificar conta
            $stmt = $this->db->prepare('SELECT id, status FROM contas_pagar WHERE id = ?');
            $stmt->execute([$id]);
            $conta = $stmt->fetch(PDO::FETCH_ASSOC);
            if (!$conta) return Response::json(['error' => 'Conta não encontrada'], 404);
            if (($conta['status'] ?? '') !== 'pago') return Response::json(['error' => 'Conciliação permitida apenas para contas pagas'], 409);

            // Stub de integração bancária: confirma liquidação usando referência
            $bankRes = [];
            try {
                $bankRes = BankIntegrationStub::confirmSettlement($reference);
            } catch (\Throwable $e) {
                $bankRes = ['status' => 'unknown', 'error' => $e->getMessage()];
            }

            $upd = $this->db->prepare('UPDATE contas_pagar SET reconciled_at = NOW(), reconciliation_reference = ? WHERE id = ?');
            $upd->execute([$reference, $id]);
            AuditLogger::logUpdate('contas_pagar', $id, $conta, ['reconciled_at' => date('c'), 'reconciliation_reference' => $reference, 'bank' => ($bankRes['bank'] ?? null), 'bank_status' => ($bankRes['status'] ?? null)]);
            return Response::json(['message' => 'Conta conciliada', 'reference' => $reference, 'bank' => ($bankRes['bank'] ?? null), 'bank_status' => ($bankRes['status'] ?? null)]);
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao conciliar: ' . $e->getMessage()], 500);
        }
    }

    /**
     * Notificações de vencimentos próximos
     */
    public function notifyDue(Request $request): Response {
        try {
            $days = max(1, (int)($request->getQueryParam('days', 5)));
            $stmt = $this->db->prepare("SELECT id, descricao, fornecedor, valor, data_vencimento FROM contas_pagar WHERE status = 'pendente' AND data_vencimento <= DATE_ADD(CURDATE(), INTERVAL :days DAY)");
            $stmt->bindValue(':days', $days, PDO::PARAM_INT);
            $stmt->execute();
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
            $admin = Config::get('DEFAULT_ADMIN_EMAIL', 'admin@local');
            $count = 0;
            foreach ($rows as $r) {
                $subject = '[GestorEasy] Conta a vencer: ' . ($r['descricao'] ?? ('#' . $r['id']));
                $body = "Fornecedor: " . ($r['fornecedor'] ?? '-') . "\n" .
                        "Valor: R$ " . number_format((float)($r['valor'] ?? 0), 2, ',', '.') . "\n" .
                        "Vencimento: " . ($r['data_vencimento'] ?? '-') . "\n" .
                        "Link: " . (Config::get('APP_URL', 'http://localhost:8000') . '/financeiro/pagar');
                Mailer::send($admin, $subject, $body);
                $count++;
            }
            AuditLogger::log('notify', 'contas_pagar', null, null, ['count' => $count, 'days' => $days]);
            return Response::json(['message' => 'Notificações disparadas', 'count' => $count]);
        } catch (Exception $e) {
            return Response::json(['error' => 'Erro ao notificar: ' . $e->getMessage()], 500);
        }
    }

    private function requiredApprovalLevels(float $valor): int {
        // Regra simples: >= 5000 exige 2 níveis; caso contrário, 1 nível
        try {
            $threshold = (float)Config::get('FINANCE_APPROVAL_THRESHOLD_BRL', 5000);
        } catch (\Throwable $e) { $threshold = 5000.0; }
        return $valor >= $threshold ? 2 : 1;
    }
}