import { prisma } from '../config/database.js'; export async function getDashboardMetrics() { const now = new Date(); const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); const [ totalTenants, activeTenants, trialTenants, cancelledSubs, recentSignups, connectorStatuses, payments, ] = await Promise.all([ prisma.tenant.count(), prisma.tenant.count({ where: { active: true } }), prisma.tenant.count({ where: { trialEndsAt: { gt: now } } }), prisma.subscription.count({ where: { status: 'cancelled' } }), prisma.tenant.count({ where: { createdAt: { gte: thirtyDaysAgo } } }), prisma.tenant.findMany({ where: { connectorTunnelHostname: { not: null } }, select: { id: true, nombre: true, rfc: true, connectorLastSeen: true, connectorVersion: true }, }), prisma.payment.aggregate({ where: { status: 'approved', createdAt: { gte: thirtyDaysAgo } }, _sum: { amount: true }, _count: true, }), ]); const connectors = connectorStatuses.map(t => { let status: 'connected' | 'degraded' | 'disconnected' = 'disconnected'; if (t.connectorLastSeen) { const diff = now.getTime() - t.connectorLastSeen.getTime(); if (diff < 60_000) status = 'connected'; else if (diff < 300_000) status = 'degraded'; } return { id: t.id, nombre: t.nombre, rfc: t.rfc, status, lastSeen: t.connectorLastSeen?.toISOString(), version: t.connectorVersion }; }); const connectorsDown = connectors.filter(c => c.status === 'disconnected').length; return { tenants: { total: totalTenants, active: activeTenants, trial: trialTenants, cancelled: cancelledSubs }, signupsLast30Days: recentSignups, revenue: { last30Days: Number(payments._sum.amount || 0), paymentsCount: payments._count }, connectors: { total: connectors.length, down: connectorsDown, list: connectors }, }; } export async function listAllDespachos(filters?: { vertical?: string; status?: string; search?: string }) { const where: any = {}; if (filters?.vertical) where.verticalProfile = filters.vertical; if (filters?.status === 'active') where.active = true; if (filters?.status === 'inactive') where.active = false; if (filters?.search) { where.OR = [ { nombre: { contains: filters.search, mode: 'insensitive' } }, { rfc: { contains: filters.search, mode: 'insensitive' } }, ]; } const tenants = await prisma.tenant.findMany({ where, select: { id: true, nombre: true, rfc: true, plan: true, active: true, verticalProfile: true, dbMode: true, connectorLastSeen: true, createdAt: true, trialEndsAt: true, }, orderBy: { createdAt: 'desc' }, take: 100, }); return tenants.map(t => ({ ...t, connectorLastSeen: t.connectorLastSeen?.toISOString(), createdAt: t.createdAt.toISOString(), trialEndsAt: t.trialEndsAt?.toISOString(), })); } export async function getRecentActivity(limit = 20) { const logs = await prisma.auditLog.findMany({ where: { action: { in: ['user.register', 'user.login', 'subscription.created', 'subscription.cancelled', 'subscription.upgraded', 'price.updated'] } }, orderBy: { createdAt: 'desc' }, take: limit, }); return logs; }