import { NextRequest, NextResponse } from "next/server" import prisma from "@/lib/prisma" import { stackServerApp } from "@/lib/stack-server" // GET - Get detailed analytics for a creator export async function GET(request: NextRequest) { try { const user = await stackServerApp.getUser() if (!user) { return NextResponse.json( { error: "Unauthorized" }, { status: 401 } ) } const { searchParams } = new URL(request.url) const days = parseInt(searchParams.get("days") || "30") const daysAgo = new Date() daysAgo.setDate(daysAgo.getDate() - days) // Get all prompts by this user const prompts = await prisma.prompt.findMany({ where: { creatorId: user.id }, select: { id: true, title: true, slug: true, totalRuns: true, starsCount: true, remixesCount: true, framework: true, badges: true, parentId: true, createdAt: true, }, orderBy: { totalRuns: "desc" }, }) // Get runs data for the period const runs = await prisma.run.findMany({ where: { prompt: { creatorId: user.id }, createdAt: { gte: daysAgo }, }, select: { id: true, model: true, tokens: true, cached: true, createdAt: true, promptId: true, }, orderBy: { createdAt: "desc" }, }) // Get engagement metrics (errors tracked separately) const engagementMetrics = await prisma.engagementMetric.findMany({ where: { targetType: "prompt", targetId: { in: prompts.map(p => p.id) }, createdAt: { gte: daysAgo }, }, select: { action: true, createdAt: true, targetId: true, } }) // Aggregate runs by day const runsByDay: Record = {} runs.forEach(run => { const day = run.createdAt.toISOString().split("T")[0] if (!runsByDay[day]) { runsByDay[day] = { runs: 0, errors: 0, tokens: 0 } } runsByDay[day].runs += 1 runsByDay[day].tokens += run.tokens || 0 }) // Prepare daily data for chart const dailyData = [] for (let i = days - 1; i >= 0; i--) { const date = new Date() date.setDate(date.getDate() - i) const dateStr = date.toISOString().split("T")[0] const dayData = runsByDay[dateStr] || { runs: 0, errors: 0, tokens: 0 } dailyData.push({ date: dateStr, runs: dayData.runs, errors: dayData.errors, tokens: dayData.tokens, }) } // Model usage stats const modelUsage: Record = {} runs.forEach(run => { if (!modelUsage[run.model]) { modelUsage[run.model] = { runs: 0, tokens: 0 } } modelUsage[run.model].runs += 1 modelUsage[run.model].tokens += run.tokens || 0 }) // Token usage per prompt const tokensByPrompt: Record = {} runs.forEach(run => { if (!tokensByPrompt[run.promptId]) { tokensByPrompt[run.promptId] = 0 } tokensByPrompt[run.promptId] += run.tokens || 0 }) // Remix traffic - find remixes of user's prompts const remixTraffic = await prisma.prompt.findMany({ where: { parentId: { in: prompts.map(p => p.id) }, createdAt: { gte: daysAgo }, }, select: { id: true, title: true, parentId: true, totalRuns: true, createdAt: true, }, orderBy: { createdAt: "desc" }, take: 20, }) // Engagement breakdown const engagementByAction: Record = {} engagementMetrics.forEach(metric => { engagementByAction[metric.action] = (engagementByAction[metric.action] || 0) + 1 }) // Total tokens used const totalTokens = runs.reduce((sum, run) => sum + (run.tokens || 0), 0) const cachedRuns = runs.filter(r => r.cached).length const cacheHitRate = runs.length > 0 ? (cachedRuns / runs.length) * 100 : 0 // Calculate totals const totalRuns = prompts.reduce((sum, p) => sum + p.totalRuns, 0) const totalStars = prompts.reduce((sum, p) => sum + p.starsCount, 0) const totalRemixes = prompts.reduce((sum, p) => sum + p.remixesCount, 0) // Error rate estimation (based on low token runs which might indicate errors) const potentialErrors = runs.filter(r => r.tokens !== null && r.tokens < 10).length const errorRate = runs.length > 0 ? (potentialErrors / runs.length) * 100 : 0 return NextResponse.json({ prompts: prompts.map(p => ({ ...p, tokens: tokensByPrompt[p.id] || 0, })), dailyData, modelUsage, totalTokens, cacheHitRate, errorRate, remixTraffic, engagementByAction, totals: { runs: totalRuns, stars: totalStars, remixes: totalRemixes, prompts: prompts.length, periodRuns: runs.length, periodTokens: totalTokens, }, }) } catch (error) { console.error("Error fetching analytics:", error) return NextResponse.json( { error: "Failed to fetch analytics" }, { status: 500 } ) } }