import type { FastifyInstance } from 'fastify'; import type pg from 'pg'; import { z } from 'zod'; import { requireRole, type Authenticate } from '../../../shared/auth.js'; import { parseJson } from '../../../shared/http-input.js'; interface AdminStatsDeps { pool: pg.Pool; authenticate: Authenticate; } export async function registerAdminStatsRoutes( app: FastifyInstance, deps: AdminStatsDeps, ): Promise { app.get('/admin/stats', async (request, reply) => { const user = await deps.authenticate(request); requireRole(user, 'admin'); const pool = deps.pool; // All queries run in parallel for speed const [ ordersToday, revenueToday, ordersByState, outOfStockVariants, totalProducts, newCustomersThisMonth, ] = await Promise.all([ // Orders today pool .query<{ count: string }>( `SELECT COUNT(*)::text AS count FROM orders_orders WHERE created_at >= CURRENT_DATE`, ) .then((r) => parseInt(r.rows[0]?.count ?? '0', 10)), // Revenue today (sum of PAID, PROCESSING, SHIPPED, DELIVERED orders) pool .query<{ total: string }>( `SELECT COALESCE(SUM(total_cents), 0)::text AS total FROM orders_orders WHERE created_at >= CURRENT_DATE AND state IN ('PAID','PROCESSING','SHIPPED','DELIVERED')`, ) .then((r) => parseInt(r.rows[0]?.total ?? '0', 10)), // Orders by state pool .query<{ state: string; count: string }>( `SELECT state, COUNT(*)::text AS count FROM orders_orders GROUP BY state ORDER BY count DESC`, ) .then((r) => Object.fromEntries(r.rows.map((row) => [row.state, parseInt(row.count, 10)])), ), // Out-of-stock variants pool .query<{ count: string }>( `SELECT COUNT(*)::text AS count FROM inventory_stock s WHERE s.available <= 0`, ) .then((r) => parseInt(r.rows[0]?.count ?? '0', 10)), // Total active products pool .query<{ count: string }>( `SELECT COUNT(*)::text AS count FROM catalog_products WHERE state = 'active'`, ) .then((r) => parseInt(r.rows[0]?.count ?? '0', 10)), // New customers this month pool .query<{ count: string }>( `SELECT COUNT(*)::text AS count FROM identity_users WHERE role = 'customer' AND created_at >= DATE_TRUNC('month', CURRENT_DATE)`, ) .then((r) => parseInt(r.rows[0]?.count ?? '0', 10)), ]); return reply.send({ ordersToday, revenueTodayCents: revenueToday, revenueTodayFormatted: `€${(revenueToday / 100).toFixed(2)}`, ordersByState, outOfStockVariants, totalActiveProducts: totalProducts, newCustomersThisMonth, generatedAt: new Date().toISOString(), }); }); }