export const runtime = 'nodejs' import { NextResponse } from 'next/server' import { PrismaClient } from '@/app/generated/prisma' import { auth } from '@/auth' function parseIsoDate(value: string | null): Date | null { if (!value) return null const d = new Date(value) return Number.isFinite(d.getTime()) ? d : null } export async function GET(request: Request) { const prisma = new PrismaClient() try { const session = await auth() if (!session?.user?.email) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) } const { searchParams } = new URL(request.url) const startParam = searchParams.get('start') const endParam = searchParams.get('end') const start = parseIsoDate(startParam) const end = parseIsoDate(endParam) if (!start || !end) { return NextResponse.json({ error: 'invalid start/end' }, { status: 400 }) } if (start > end) { return NextResponse.json({ error: 'start after end' }, { status: 400 }) } // 날짜를 UTC 기준 하루 경계로 확장 const startDay = new Date(Date.UTC(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate(), 0, 0, 0, 0)) const endDay = new Date(Date.UTC(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate(), 23, 59, 59, 999)) // 사용자 소속 핸들 조회 (없으면 사용자 필터 생략) const userHandles = await prisma.handle.findMany({ where: { users: { some: { email: session.user.email } } }, select: { id: true, handle: true }, }) const handleIds = userHandles.map(h => h.id) // 선택된 채널 필터(query): handleId, handleIds(쉼표), handle, handles(쉼표) const handleIdParam = searchParams.get('handleId') const handleIdsParam = searchParams.get('handleIds') const handleParam = searchParams.get('handle') const handlesParam = searchParams.get('handles') let selectedHandleIds: string[] | null = null if (handleIdParam) selectedHandleIds = [handleIdParam] if (!selectedHandleIds && handleIdsParam) selectedHandleIds = handleIdsParam.split(',').map(s => s.trim()).filter(Boolean) if (!selectedHandleIds && (handleParam || handlesParam)) { const targetHandles = (handlesParam ? handlesParam.split(',') : [handleParam!]).map(s => s!.trim()).filter(Boolean) if (targetHandles.length > 0) { const matched = await prisma.handle.findMany({ where: { handle: { in: targetHandles } }, select: { id: true } }) selectedHandleIds = matched.map(m => m.id) } } const where: any = { date: { gte: startDay, lte: endDay }, } if (selectedHandleIds && selectedHandleIds.length > 0) { // 지정된 채널만 where.content = { handleId: { in: selectedHandleIds } } } else if (handleIds.length > 0) { // 사용자 소속 채널만 where.content = { handleId: { in: handleIds } } } const grouped = await prisma.contentDayView.groupBy({ by: ['contentId'], where, _sum: { views: true, validViews: true, premiumViews: true, watchTime: true, }, }) const contentIds = grouped.map(g => g.contentId).filter(Boolean) const contents = contentIds.length > 0 ? await prisma.content.findMany({ where: { id: { in: contentIds } }, select: { id: true, subject: true, pubDate: true, handle: { select: { id: true, handle: true, avatar: true, costPerView: true } }, }, }) : [] const idToContent = new Map(contents.map(c => [c.id, c])) const items = grouped.map(g => { const c = idToContent.get(g.contentId) as any const h = c?.handle as (undefined | { id: string, handle: string, avatar: string | null, costPerView?: number }) const views = g._sum?.views ?? 0 const validViews = g._sum?.validViews ?? 0 const premiumViews = g._sum?.premiumViews ?? 0 const watchTime = g._sum?.watchTime ?? 0 const cpv = typeof h?.costPerView === 'number' ? h!.costPerView! : 0 const expectedRevenue = Math.max(0, Math.round(validViews * cpv)) return { id: c?.id ?? g.contentId, subject: c?.subject ?? '', pubDate: (c?.pubDate ?? null) as any, views, premiumViews, watchTime, handle: h?.handle ?? '', handleId: h?.id ?? null, icon: h?.avatar ?? '', validViews, expectedRevenue, } }) items.sort((a, b) => { const pa = a.pubDate ? new Date(a.pubDate as any).getTime() : 0 const pb = b.pubDate ? new Date(b.pubDate as any).getTime() : 0 return pb - pa }) return NextResponse.json({ success: true, start: startDay.toISOString(), end: endDay.toISOString(), count: items.length, items }) } catch (e) { console.error('[contents/mycontent] error:', e) return NextResponse.json({ error: 'query failed' }, { status: 500 }) } finally { try { await (prisma as any).$disconnect() } catch {} } }