<?php
namespace Modules\Dashboard;

use Gestoreasy\Core\Module\ModuleInterface;
use Gestoreasy\Core\Routing\Router;
use Gestoreasy\Core\Http\Request;
use Gestoreasy\Core\Http\Response;
use Gestoreasy\Core\View\View;
use Gestoreasy\Core\Auth\AuthMiddleware;
use Gestoreasy\Core\Auth\Rbac;
use Gestoreasy\Core\Tenant\ConnectionManager;
use Gestoreasy\Core\Audit\AuditLogger;

class Module implements ModuleInterface {
    public function register(Router $router): void {
        $render = function(Request $r) {
            return View::renderWithLayout('dashboard/index', [
                'title' => 'Dashboard'
            ]);
        };
        $router->get('/', $render, [AuthMiddleware::requireAuthHtml()]);
        $router->get('/dashboard', $render, [AuthMiddleware::requireAuthHtml()]);

        // ==== Relatórios (HTML stubs) ====
        $router->get('/relatorios/vendas', function(Request $r){
            return View::renderWithLayout('relatorios/vendas', ['title' => 'Relatórios de Vendas']);
        }, [AuthMiddleware::requireAuthHtml()]);
        $router->get('/relatorios/compras', function(Request $r){
            return View::renderWithLayout('relatorios/compras', ['title' => 'Relatórios de Compras']);
        }, [AuthMiddleware::requireAuthHtml()]);
        $router->get('/relatorios/estoque', function(Request $r){
            return View::renderWithLayout('relatorios/estoque', ['title' => 'Relatórios de Estoque']);
        }, [AuthMiddleware::requireAuthHtml()]);
        // Redireciona a página legada para o módulo moderno
        $router->get('/relatorios/financeiro', function(Request $r){
            return Response::redirect('/financeiro/relatorios', 302);
        }, [AuthMiddleware::requireAuthHtml()]);
        $router->get('/relatorios/clientes', function(Request $r){
            return View::renderWithLayout('relatorios/clientes', ['title' => 'Relatórios de Clientes']);
        }, [AuthMiddleware::requireAuthHtml()]);
        $router->get('/relatorios/produtos-criticos', function(Request $r){
            return View::renderWithLayout('relatorios/produtos_criticos', ['title' => 'Relatórios de Produtos Críticos']);
        }, [AuthMiddleware::requireAuthHtml()]);
        $router->get('/relatorios/titulos-a-vencer', function(Request $r){
            return View::renderWithLayout('relatorios/titulos_a_vencer', ['title' => 'Relatórios de Títulos a Vencer']);
        }, [AuthMiddleware::requireAuthHtml()]);

        // ==== API agregadora para o Dashboard: Finance ====
        // Contas a pagar (resumo para dashboard)
        $router->get('/api/finance/payables', function(Request $r) {
            try {
                $db = ConnectionManager::forTenant();
                // Verifica tabela
                $exists = $db->query("SHOW TABLES LIKE 'contas_pagar'")->rowCount() > 0;
                if (!$exists) return Response::json(['data' => [], 'message' => 'Tabela contas_pagar ausente']);

                $start = $r->getQueryParam('start', null);
                $end = $r->getQueryParam('end', null);
                $perPage = min(100, max(1, (int)$r->getQueryParam('per_page', 50)));
                $where = ['1=1'];
                $params = [];
                // Apenas títulos em aberto para o dashboard
                $where[] = "status IN ('pendente','vencido')";
                if ($start) { $where[] = 'data_vencimento >= :start'; $params['start'] = $start; }
                if ($end) { $where[] = 'data_vencimento <= :end'; $params['end'] = $end; }
                $sql = 'SELECT id, descricao, fornecedor, status, valor, data_vencimento FROM contas_pagar WHERE ' . implode(' AND ', $where) . ' ORDER BY data_vencimento ASC LIMIT :limit';
                $st = $db->prepare($sql);
                foreach ($params as $k=>$v) { $st->bindValue(':' . $k, $v); }
                $st->bindValue(':limit', $perPage, \PDO::PARAM_INT);
                $st->execute();
                $rows = $st->fetchAll(\PDO::FETCH_ASSOC) ?: [];
                // Mapeia para o formato esperado pelo front
                $data = array_map(function($c){
                    return [
                        'id' => (int)$c['id'],
                        'due_at' => $c['data_vencimento'],
                        'description' => $c['descricao'],
                        'supplier_name' => $c['fornecedor'] ?? null,
                        'category' => 'fornecedores',
                        'status' => $c['status'],
                        'amount' => (float)$c['valor']
                    ];
                }, $rows);
                AuditLogger::logRead('dashboard_finance_payables', null, ['count' => count($data), 'filters' => ['start'=>$start,'end'=>$end]]);
                return Response::json(['data' => $data]);
            } catch (\Throwable $e) {
                return new Response(500, ['error' => 'Falha ao carregar contas a pagar: ' . $e->getMessage()]);
            }
        }, [AuthMiddleware::requireAuth(), Rbac::requirePermissions(['financeiro.read'])]);

        // Contas a receber (resumo para dashboard)
        $router->get('/api/finance/receivables', function(Request $r) {
            try {
                $db = ConnectionManager::forTenant();
                // Verifica tabela
                $exists = $db->query("SHOW TABLES LIKE 'contas_receber'")->rowCount() > 0;
                if (!$exists) return Response::json(['data' => [], 'message' => 'Tabela contas_receber ausente']);

                $start = $r->getQueryParam('start', null);
                $end = $r->getQueryParam('end', null);
                $perPage = min(100, max(1, (int)$r->getQueryParam('per_page', 50)));
                $where = ['1=1'];
                $params = [];
                // Apenas títulos não recebidos para o dashboard
                $where[] = "status IN ('pendente','vencido')";
                if ($start) { $where[] = 'data_vencimento >= :start'; $params['start'] = $start; }
                if ($end) { $where[] = 'data_vencimento <= :end'; $params['end'] = $end; }
                $sql = 'SELECT id, descricao, cliente, status, valor, data_vencimento, data_recebimento, valor_recebido FROM contas_receber WHERE ' . implode(' AND ', $where) . ' ORDER BY data_vencimento ASC LIMIT :limit';
                $st = $db->prepare($sql);
                foreach ($params as $k=>$v) { $st->bindValue(':' . $k, $v); }
                $st->bindValue(':limit', $perPage, \PDO::PARAM_INT);
                $st->execute();
                $rows = $st->fetchAll(\PDO::FETCH_ASSOC) ?: [];
                // Mapeia para o formato esperado pelo front
                $data = array_map(function($c){
                    return [
                        'id' => (int)$c['id'],
                        'due_at' => $c['data_vencimento'],
                        'receive_at' => $c['data_recebimento'] ?? null,
                        'description' => $c['descricao'],
                        'customer_name' => $c['cliente'] ?? null,
                        'category' => 'vendas',
                        'status' => $c['status'],
                        'amount' => (float)$c['valor'],
                        'amount_received' => isset($c['valor_recebido']) ? (float)$c['valor_recebido'] : null
                    ];
                }, $rows);
                AuditLogger::logRead('dashboard_finance_receivables', null, ['count' => count($data), 'filters' => ['start'=>$start,'end'=>$end]]);
                return Response::json(['data' => $data]);
            } catch (\Throwable $e) {
                return new Response(500, ['error' => 'Falha ao carregar contas a receber: ' . $e->getMessage()]);
            }
        }, [AuthMiddleware::requireAuth(), Rbac::requirePermissions(['financeiro.read'])]);

        // Agenda/Calendário — eventos simples para o dashboard
        $router->get('/api/calendar/events', function(Request $r) {
            try {
                $db = ConnectionManager::forTenant();
                // Garante tabela de eventos
                $db->exec("CREATE TABLE IF NOT EXISTS calendar_events (
                    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    date DATE NOT NULL,
                    type ENUM('despesa','receita') NOT NULL,
                    description VARCHAR(255) NULL,
                    value DECIMAL(12,2) NOT NULL DEFAULT 0,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_date (date),
                    INDEX idx_type (type)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $start = $r->getQueryParam('start', null);
                $end = $r->getQueryParam('end', null);
                if (!$start || !$end) {
                    $today = new \DateTime('today');
                    $first = (clone $today)->modify('first day of this month')->format('Y-m-d');
                    $nextFirst = (clone $today)->modify('first day of next month')->format('Y-m-d');
                    $start = $start ?: $first; $end = $end ?: $nextFirst;
                }
                $st = $db->prepare('SELECT id, date, type, description, value FROM calendar_events WHERE date >= :start AND date < :end ORDER BY date ASC, id ASC');
                $st->execute(['start' => $start, 'end' => $end]);
                $rows = $st->fetchAll(\PDO::FETCH_ASSOC) ?: [];
                AuditLogger::logRead('calendar_events', null, ['count' => count($rows), 'filters' => ['start' => $start, 'end' => $end]]);
                return Response::json(['data' => array_map(function($ev){
                    return [
                        'id' => (int)$ev['id'],
                        'date' => $ev['date'],
                        'type' => $ev['type'],
                        'description' => $ev['description'] ?? null,
                        'value' => (float)$ev['value']
                    ];
                }, $rows)]);
            } catch (\Throwable $e) {
                return new Response(500, ['error' => 'Falha ao carregar agenda: ' . $e->getMessage()]);
            }
        }, [AuthMiddleware::requireAuth()]);

        $router->post('/api/calendar/events', function(Request $r) {
            try {
                $db = ConnectionManager::forTenant();
                $db->exec("CREATE TABLE IF NOT EXISTS calendar_events (
                    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    date DATE NOT NULL,
                    type ENUM('despesa','receita') NOT NULL,
                    description VARCHAR(255) NULL,
                    value DECIMAL(12,2) NOT NULL DEFAULT 0,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_date (date),
                    INDEX idx_type (type)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $date = (string)($r->body['date'] ?? '');
                $type = (string)($r->body['type'] ?? 'despesa');
                $desc = trim((string)($r->body['description'] ?? ''));
                $value = (float)($r->body['value'] ?? 0);
                if ($date === '' || ($type !== 'despesa' && $type !== 'receita')) {
                    return Response::json(['error' => 'Campos obrigatórios ausentes'], 422);
                }
                if (!is_numeric($r->body['value'] ?? null) || $value <= 0) {
                    return Response::json(['error' => 'Valor deve ser positivo'], 422);
                }
                $st = $db->prepare('INSERT INTO calendar_events (date, type, description, value) VALUES (?, ?, ?, ?)');
                $st->execute([$date, $type, $desc !== '' ? $desc : null, $value]);
                $id = (int)$db->lastInsertId();
                AuditLogger::logCreate('calendar_events', $id, ['date' => $date, 'type' => $type, 'value' => $value]);

                // Integração com financeiro básica (sem dependência de módulos externos)
                $db->exec("CREATE TABLE IF NOT EXISTS contas_pagar (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    descricao VARCHAR(255) NOT NULL,
                    valor DECIMAL(10,2) NOT NULL,
                    data_vencimento DATE NOT NULL,
                    fornecedor VARCHAR(255) NOT NULL,
                    documento VARCHAR(100) NULL,
                    observacoes TEXT NULL,
                    status ENUM('pendente', 'pago', 'vencido') DEFAULT 'pendente',
                    data_pagamento DATE NULL,
                    valor_pago DECIMAL(10,2) NULL,
                    forma_pagamento VARCHAR(50) NULL,
                    observacoes_pagamento TEXT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP NULL,
                    INDEX idx_data_vencimento (data_vencimento),
                    INDEX idx_status (status),
                    INDEX idx_fornecedor (fornecedor),
                    INDEX idx_documento (documento)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $db->exec("CREATE TABLE IF NOT EXISTS contas_receber (
                    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
                    descricao VARCHAR(255) NOT NULL,
                    cliente VARCHAR(255) NOT NULL,
                    documento VARCHAR(100) NULL,
                    valor DECIMAL(12,2) NOT NULL,
                    status ENUM('pendente','recebido','vencido') NOT NULL DEFAULT 'pendente',
                    data_vencimento DATE NOT NULL,
                    data_recebimento DATE NULL,
                    valor_recebido DECIMAL(12,2) NULL,
                    forma_recebimento VARCHAR(50) NULL,
                    observacoes TEXT NULL,
                    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    updated_at DATETIME NULL DEFAULT NULL,
                    PRIMARY KEY (id),
                    KEY idx_status (status),
                    KEY idx_data_vencimento (data_vencimento),
                    KEY idx_cliente (cliente),
                    KEY idx_documento (documento)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $financeId = null; $financeType = null;
                if ($type === 'despesa') {
                    $st2 = $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())");
                    $st2->execute([
                        ':descricao' => ($desc !== '' ? $desc : 'Agenda: Despesa'),
                        ':valor' => $value,
                        ':data_vencimento' => $date,
                        ':fornecedor' => 'Agenda',
                        ':documento' => null,
                        ':observacoes' => null,
                    ]);
                    $financeId = (int)$db->lastInsertId();
                    $financeType = 'contas_pagar';
                    AuditLogger::logCreate('contas_pagar', $financeId, ['calendar_event_id' => $id]);
                } else {
                    $st3 = $db->prepare("INSERT INTO contas_receber (descricao, valor, data_vencimento, cliente, documento, observacoes, status, created_at) VALUES (:descricao, :valor, :data_vencimento, :cliente, :documento, :observacoes, 'pendente', NOW())");
                    $st3->execute([
                        ':descricao' => ($desc !== '' ? $desc : 'Agenda: Receita'),
                        ':valor' => $value,
                        ':data_vencimento' => $date,
                        ':cliente' => 'Agenda',
                        ':documento' => null,
                        ':observacoes' => null,
                    ]);
                    $financeId = (int)$db->lastInsertId();
                    $financeType = 'contas_receber';
                    AuditLogger::logCreate('contas_receber', $financeId, ['calendar_event_id' => $id]);
                }

                return Response::json(['id' => $id, 'finance_type' => $financeType, 'finance_id' => $financeId], 201);
            } catch (\Throwable $e) {
                return new Response(500, ['error' => 'Falha ao salvar na agenda: ' . $e->getMessage()]);
            }
        }, [AuthMiddleware::requireAuth()]);

        // Lançamento rápido: cria evento e integra com Financeiro (contas pagar/receber)
        $router->post('/api/calendar/quick-transactions', function(Request $r) {
            try {
                $db = ConnectionManager::forTenant();
                // Garantir tabela de eventos
                $db->exec("CREATE TABLE IF NOT EXISTS calendar_events (
                    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    date DATE NOT NULL,
                    type ENUM('despesa','receita') NOT NULL,
                    description VARCHAR(255) NULL,
                    value DECIMAL(12,2) NOT NULL DEFAULT 0,
                    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
                    INDEX idx_date (date),
                    INDEX idx_type (type)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $date = (string)($r->body['date'] ?? '');
                $type = (string)($r->body['type'] ?? 'despesa');
                $desc = trim((string)($r->body['description'] ?? ''));
                $value = (float)($r->body['value'] ?? 0);
                if ($date === '' || ($type !== 'despesa' && $type !== 'receita')) {
                    return Response::json(['error' => 'Campos obrigatórios ausentes'], 422);
                }
                if (!is_numeric($r->body['value'] ?? null) || $value <= 0) {
                    return Response::json(['error' => 'Valor deve ser positivo'], 422);
                }

                // Criar evento de agenda
                $stEv = $db->prepare('INSERT INTO calendar_events (date, type, description, value) VALUES (?, ?, ?, ?)');
                $stEv->execute([$date, $type, $desc !== '' ? $desc : null, $value]);
                $eventId = (int)$db->lastInsertId();
                // Corrigir ordem/parâmetros do logger: usar helper específico para criação
                AuditLogger::logCreate('calendar_events', $eventId, [
                    'date' => $date,
                    'type' => $type,
                    'value' => $value
                ]);

                // Garantir tabelas financeiro básicas (best-effort)
                $db->exec("CREATE TABLE IF NOT EXISTS contas_pagar (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    descricao VARCHAR(255) NOT NULL,
                    valor DECIMAL(10,2) NOT NULL,
                    data_vencimento DATE NOT NULL,
                    fornecedor VARCHAR(255) NOT NULL,
                    documento VARCHAR(100) NULL,
                    observacoes TEXT NULL,
                    status ENUM('pendente', 'pago', 'vencido') DEFAULT 'pendente',
                    data_pagamento DATE NULL,
                    valor_pago DECIMAL(10,2) NULL,
                    forma_pagamento VARCHAR(50) NULL,
                    observacoes_pagamento TEXT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP NULL,
                    INDEX idx_data_vencimento (data_vencimento),
                    INDEX idx_status (status),
                    INDEX idx_fornecedor (fornecedor),
                    INDEX idx_documento (documento)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $db->exec("CREATE TABLE IF NOT EXISTS contas_receber (
                    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
                    descricao VARCHAR(255) NOT NULL,
                    cliente VARCHAR(255) NOT NULL,
                    documento VARCHAR(100) NULL,
                    valor DECIMAL(12,2) NOT NULL,
                    status ENUM('pendente','recebido','vencido') NOT NULL DEFAULT 'pendente',
                    data_vencimento DATE NOT NULL,
                    data_recebimento DATE NULL,
                    valor_recebido DECIMAL(12,2) NULL,
                    forma_recebimento VARCHAR(50) NULL,
                    observacoes TEXT NULL,
                    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
                    updated_at DATETIME NULL DEFAULT NULL,
                    PRIMARY KEY (id),
                    KEY idx_status (status),
                    KEY idx_data_vencimento (data_vencimento),
                    KEY idx_cliente (cliente),
                    KEY idx_documento (documento)
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci");

                $financeId = null; $financeType = null;
                if ($type === 'despesa') {
                    // Inserir em contas a pagar
                    $st = $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())");
                    $st->execute([
                        ':descricao' => ($desc !== '' ? $desc : 'Lançamento rápido (Agenda)'),
                        ':valor' => $value,
                        ':data_vencimento' => $date,
                        ':fornecedor' => 'Agenda',
                        ':documento' => null,
                        ':observacoes' => null,
                    ]);
                    $financeId = (int)$db->lastInsertId();
                    $financeType = 'contas_pagar';
                    AuditLogger::logCreate('contas_pagar', $financeId, ['origem' => 'agenda', 'calendar_event_id' => $eventId]);
                } else {
                    // Inserir em contas a receber
                    $st = $db->prepare("INSERT INTO contas_receber (descricao, valor, data_vencimento, cliente, documento, observacoes, status, created_at) VALUES (:descricao, :valor, :data_vencimento, :cliente, :documento, :observacoes, 'pendente', NOW())");
                    $st->execute([
                        ':descricao' => ($desc !== '' ? $desc : 'Lançamento rápido (Agenda)'),
                        ':valor' => $value,
                        ':data_vencimento' => $date,
                        ':cliente' => 'Agenda',
                        ':documento' => null,
                        ':observacoes' => null,
                    ]);
                    $financeId = (int)$db->lastInsertId();
                    $financeType = 'contas_receber';
                    AuditLogger::logCreate('contas_receber', $financeId, ['origem' => 'agenda', 'calendar_event_id' => $eventId]);
                }

                return Response::json(['id' => $eventId, 'finance_type' => $financeType, 'finance_id' => $financeId], 201);
            } catch (\Throwable $e) {
                return new Response(500, ['error' => 'Falha no lançamento rápido: ' . $e->getMessage()]);
            }
        }, [AuthMiddleware::requireAuth(), Rbac::requirePermissions(['financeiro.create'])]);

        // Métricas agregadas de finanças (KPIs rápidos)
        $router->get('/api/finance/metrics', function(Request $r) {
            try {
                $db = ConnectionManager::forTenant();
                $hasPay = $db->query("SHOW TABLES LIKE 'contas_pagar'")->rowCount() > 0;
                $hasRec = $db->query("SHOW TABLES LIKE 'contas_receber'")->rowCount() > 0;
                $start = $r->getQueryParam('start', null);
                $end = $r->getQueryParam('end', null);
                $today = (new \DateTime('today'))->format('Y-m-d');
                $next7 = (new \DateTime('+7 days'))->format('Y-m-d');

                $payables = [
                    'total_pending' => 0.0,
                    'overdue_count' => 0,
                    'due_today_count' => 0,
                    'next_7d_count' => 0,
                    'next_dates' => [],
                    'next_dates_detail' => []
                ];
                $receivables = [
                    'total_pending' => 0.0,
                    'due_today_count' => 0,
                    'next_7d_count' => 0,
                    'next_dates' => [],
                    'next_dates_detail' => []
                ];

                if ($hasPay) {
                    // filtros por período (somente datas)
                    $dateWhere = []; $dateParams = [];
                    if ($start) { $dateWhere[] = 'data_vencimento >= :p_start'; $dateParams['p_start'] = $start; }
                    if ($end) { $dateWhere[] = 'data_vencimento <= :p_end'; $dateParams['p_end'] = $end; }
                    $dateClause = $dateWhere ? (' AND ' . implode(' AND ', $dateWhere)) : '';

                    // total pendente (inclui vencido)
                    $st = $db->prepare("SELECT COALESCE(SUM(valor),0) AS total FROM contas_pagar WHERE status IN ('pendente','vencido')" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->execute(); $payables['total_pending'] = (float)($st->fetch()['total'] ?? 0);
                    // vencidos
                    $st = $db->prepare("SELECT COUNT(*) AS c FROM contas_pagar WHERE status='vencido'" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); } $st->execute();
                    $payables['overdue_count'] = (int)$st->fetch()['c'];
                    // hoje
                    $st = $db->prepare("SELECT COUNT(*) AS c FROM contas_pagar WHERE status IN ('pendente','vencido') AND data_vencimento = :p_today" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':p_today', $today);
                    $st->execute(); $payables['due_today_count'] = (int)$st->fetch()['c'];
                    // próximos 7 dias
                    $st = $db->prepare("SELECT COUNT(*) AS c FROM contas_pagar WHERE status = 'pendente' AND data_vencimento > :p_today AND data_vencimento <= :p_next7" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':p_today', $today);
                    $st->bindValue(':p_next7', $next7);
                    $st->execute(); $payables['next_7d_count'] = (int)$st->fetch()['c'];
                    // próximas datas (simples)
                    $st = $db->prepare("SELECT data_vencimento FROM contas_pagar WHERE status = 'pendente' AND data_vencimento >= :p_today" . $dateClause . " ORDER BY data_vencimento ASC LIMIT 5");
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':p_today', $today);
                    $st->execute();
                    $payables['next_dates'] = array_map(fn($r)=>$r['data_vencimento'], $st->fetchAll(\PDO::FETCH_ASSOC) ?: []);

                    // detalhe: count e total por próximas datas (máx 3)
                    $st = $db->prepare("SELECT data_vencimento AS dt, COUNT(*) AS cnt, COALESCE(SUM(valor),0) AS tot FROM contas_pagar WHERE status = 'pendente' AND data_vencimento >= :p_today" . $dateClause . " GROUP BY data_vencimento ORDER BY data_vencimento ASC LIMIT 5");
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':p_today', $today);
                    $st->execute();
                    $payables['next_dates_detail'] = array_map(fn($r)=>['date'=>$r['dt'],'count'=>(int)$r['cnt'],'total'=>(float)$r['tot']], $st->fetchAll(\PDO::FETCH_ASSOC) ?: []);
                }

                if ($hasRec) {
                    // filtros por período (somente datas)
                    $dateWhere = []; $dateParams = [];
                    if ($start) { $dateWhere[] = 'data_vencimento >= :r_start'; $dateParams['r_start'] = $start; }
                    if ($end) { $dateWhere[] = 'data_vencimento <= :r_end'; $dateParams['r_end'] = $end; }
                    $dateClause = $dateWhere ? (' AND ' . implode(' AND ', $dateWhere)) : '';

                    $st = $db->prepare("SELECT COALESCE(SUM(valor),0) AS total FROM contas_receber WHERE status IN ('pendente','vencido')" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->execute(); $receivables['total_pending'] = (float)($st->fetch()['total'] ?? 0);

                    $st = $db->prepare("SELECT COUNT(*) AS c FROM contas_receber WHERE status IN ('pendente','vencido') AND data_vencimento = :r_today" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':r_today', $today);
                    $st->execute(); $receivables['due_today_count'] = (int)$st->fetch()['c'];

                    $st = $db->prepare("SELECT COUNT(*) AS c FROM contas_receber WHERE status = 'pendente' AND data_vencimento > :r_today AND data_vencimento <= :r_next7" . $dateClause);
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':r_today', $today);
                    $st->bindValue(':r_next7', $next7);
                    $st->execute(); $receivables['next_7d_count'] = (int)$st->fetch()['c'];

                    // próximas datas de recebimento (pendentes)
                    $st = $db->prepare("SELECT data_vencimento FROM contas_receber WHERE status = 'pendente' AND data_vencimento >= :r_today" . $dateClause . " ORDER BY data_vencimento ASC LIMIT 5");
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':r_today', $today);
                    $st->execute();
                    $receivables['next_dates'] = array_map(fn($r)=>$r['data_vencimento'], $st->fetchAll(\PDO::FETCH_ASSOC) ?: []);

                    // detalhe: count e total por próximas datas (máx 3)
                    $st = $db->prepare("SELECT data_vencimento AS dt, COUNT(*) AS cnt, COALESCE(SUM(valor),0) AS tot FROM contas_receber WHERE status = 'pendente' AND data_vencimento >= :r_today" . $dateClause . " GROUP BY data_vencimento ORDER BY data_vencimento ASC LIMIT 5");
                    foreach ($dateParams as $k=>$v) { $st->bindValue(':'.$k, $v); }
                    $st->bindValue(':r_today', $today);
                    $st->execute();
                    $receivables['next_dates_detail'] = array_map(fn($r)=>['date'=>$r['dt'],'count'=>(int)$r['cnt'],'total'=>(float)$r['tot']], $st->fetchAll(\PDO::FETCH_ASSOC) ?: []);
                }

                AuditLogger::logRead('dashboard_finance_metrics', null, ['filters' => ['start'=>$start,'end'=>$end]]);
                return Response::json(['payables' => $payables, 'receivables' => $receivables]);
            } catch (\Throwable $e) {
                return new Response(500, ['error' => 'Falha ao carregar métricas financeiras: ' . $e->getMessage()]);
            }
        }, [AuthMiddleware::requireAuth(), Rbac::requirePermissions(['financeiro.read'])]);
    }
    public function name(): string { return 'Dashboard'; }
    public function version(): string { return '0.1.0'; }
    public function dependencies(): array { return []; }
}