// app/api/admin/stats/route.ts import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth-options'; import { prisma } from '@/lib/prisma'; import { Prisma } from '@prisma/client'; export async function GET(req: Request) { try { const session = await getServerSession(authOptions); if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const role = (session as any)?.user?.role ?? null; if (!(role === 'admin' || role === 'superadmin')) { return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); } // Fetch all videos with aggregated stats using raw queries for better performance const videos = await prisma.video.findMany({ include: { playlist: { select: { title: true, }, }, uploader: { select: { id: true, name: true, }, }, _count: { select: { likes: true, comments: true, unlocks: true, }, }, }, orderBy: { createdAt: 'desc' }, }); // Fetch detailed stats for each video using raw queries for better performance const statsData = await prisma.$queryRaw< Array<{ videoId: string; totalViewers: number; totalSecondsWatched: bigint; avgPercentWatched: number | null; totalSegments: number; completionCount: number; }> >` SELECT p."videoId", COUNT(DISTINCT p."userId") as "totalViewers", CAST(COALESCE(SUM(p."watchedSec"), 0) AS BIGINT) as "totalSecondsWatched", ROUND(CAST(AVG(p."percent") AS NUMERIC), 2) as "avgPercentWatched", (SELECT COUNT(*) FROM "VideoWatchSegment" ws WHERE ws."videoId" = p."videoId") as "totalSegments", COUNT(CASE WHEN p."completed" = true THEN 1 END) as "completionCount" FROM "VideoProgress" p GROUP BY p."videoId" `; // Create a map for quick lookup const statsMap = new Map(statsData.map(item => [item.videoId, item])); // Combine video data with stats const videosWithStats = videos.map(video => { const stats = statsMap.get(video.id); const views = video._count.unlocks || 0; const totalViewers = stats ? Number(stats.totalViewers) : 0; const completions = stats ? Number(stats.completionCount) : 0; const engagement = (video._count.likes || 0) + (video._count.comments || 0); const avgWatched = stats?.avgPercentWatched ? Number(stats.avgPercentWatched) : 0; return { id: video.id, title: video.title, playlistTitle: video.playlist.title, uploaderName: video.uploader?.name || 'Unknown', views, totalViewers, completions, completionRate: totalViewers > 0 ? ((completions / totalViewers) * 100).toFixed(2) : '0.00', likes: video._count.likes, comments: video._count.comments, engagement, avgPercentWatched: avgWatched, totalSecondsWatched: stats ? Number(stats.totalSecondsWatched) : 0, totalSegments: stats ? Number(stats.totalSegments) : 0, durationSec: video.durationSec, createdAt: video.createdAt, }; }); return NextResponse.json(videosWithStats); } catch (err: any) { console.error('get stats error', err); return NextResponse.json( { error: err?.message ?? 'server error' }, { status: 500 } ); } }