import { Router } from "express"; import { type AuthenticatedRequest, authenticate, requireAdmin, } from "../middleware/auth"; import { asyncHandler } from "../middleware/errorHandler"; import { prisma } from "../utils/prisma"; const router = Router(); router.get( "/", authenticate, asyncHandler(async (req: AuthenticatedRequest, res) => { const { page = "1", limit = "20", type } = req.query; const pageNum = parseInt(page as string); const limitNum = Math.min(parseInt(limit as string), 100); const skip = (pageNum - 1) * limitNum; const where: any = { userId: req.user!.id }; if (type) where.type = type; const [transactions, total] = await Promise.all([ prisma.transaction.findMany({ where, orderBy: { createdAt: "desc" }, skip, take: limitNum, include: { watchEvent: { select: { duration: true, percentComplete: true } }, request: { select: { mediaType: true, status: true } }, }, }), prisma.transaction.count({ where }), ]); res.json({ transactions, pagination: { page: pageNum, limit: limitNum, total, totalPages: Math.ceil(total / limitNum), }, }); }), ); router.get( "/stats", authenticate, asyncHandler(async (req: AuthenticatedRequest, res) => { const thirtyDaysAgo = new Date(); thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30); const [totalStats, recentStats, byType] = await Promise.all([ prisma.transaction.groupBy({ by: ["type"], where: { userId: req.user!.id }, _sum: { amount: true }, _count: { id: true }, }), prisma.transaction.groupBy({ by: ["type"], where: { userId: req.user!.id, createdAt: { gte: thirtyDaysAgo } }, _sum: { amount: true }, _count: { id: true }, }), prisma.transaction.findMany({ where: { userId: req.user!.id }, select: { type: true, amount: true, createdAt: true }, orderBy: { createdAt: "desc" }, take: 100, }), ]); const dailyEarnings = await prisma.$queryRaw`SELECT DATE(created_at) as date, SUM(CASE WHEN type = 'EARN' THEN amount ELSE 0 END) as earned, SUM(CASE WHEN type = 'SPEND' THEN amount ELSE 0 END) as spent FROM transactions WHERE user_id = ${req.user!.id} AND created_at >= ${thirtyDaysAgo} GROUP BY DATE(created_at) ORDER BY date DESC`; res.json({ total: totalStats, recent: recentStats, dailyEarnings, recentTransactions: byType.slice(0, 10), }); }), ); router.get( "/admin/all", authenticate, requireAdmin, asyncHandler(async (req: AuthenticatedRequest, res) => { const { page = "1", limit = "50", userId, type } = req.query; const pageNum = parseInt(page as string); const limitNum = Math.min(parseInt(limit as string), 100); const skip = (pageNum - 1) * limitNum; const where: any = {}; if (userId) where.userId = userId; if (type) where.type = type; const [transactions, total] = await Promise.all([ prisma.transaction.findMany({ where, orderBy: { createdAt: "desc" }, skip, take: limitNum, include: { user: { select: { plexUsername: true } } }, }), prisma.transaction.count({ where }), ]); res.json({ transactions, pagination: { page: pageNum, limit: limitNum, total, totalPages: Math.ceil(total / limitNum), }, }); }), ); router.get( "/admin/stats", authenticate, requireAdmin, asyncHandler(async (_req: AuthenticatedRequest, res) => { const [total, recent] = await Promise.all([ prisma.transaction.groupBy({ by: ["type"], _sum: { amount: true }, _count: { id: true }, }), prisma.transaction.groupBy({ by: ["type"], where: { createdAt: { gte: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000) }, }, _sum: { amount: true }, _count: { id: true }, }), ]); res.json({ total, recent }); }), ); router.get( "/recent", authenticate, asyncHandler(async (_req: AuthenticatedRequest, res) => { const transactions = await prisma.transaction.findMany({ orderBy: { createdAt: "desc" }, take: 10, include: { user: { select: { plexUsername: true } } }, }); res.json({ transactions }); }), ); export { router as transactionsRouter };