import { NextResponse } from 'next/server'; import { auth } from '@/auth'; import { PrismaClient } from '@/app/generated/prisma'; const prisma = new PrismaClient(); function parseDateOr(value: string | null, fallback: Date): Date { if (!value) return fallback; const d = new Date(value); return isNaN(d.getTime()) ? fallback : d; } export async function GET(request: Request) { try { const session = await auth(); if (!session) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); const email = session.user?.email as string | undefined; if (!email) return NextResponse.json({ error: '세션 이메일을 찾을 수 없습니다' }, { status: 400 }); const { searchParams } = new URL(request.url); const endDefault = new Date(); const startDefault = new Date(endDefault.getTime() - 30 * 24 * 60 * 60 * 1000); const startParam = searchParams.get('start'); const endParam = searchParams.get('end'); const startDate = startParam ? new Date(startParam) : startDefault; const endDate = endParam ? new Date(endParam) : endDefault; // 날짜 경계 보정: 하루 전체 포함 (UTC 기준) const startInclusive = new Date(startDate); startInclusive.setUTCHours(0, 0, 0, 0); const endInclusive = new Date(endDate); endInclusive.setUTCHours(23, 59, 59, 999); // 안전가드 if (endInclusive < startInclusive) endInclusive.setTime(startInclusive.getTime()); console.log('startDate', startDate.toISOString()); console.log('endDate', endDate.toISOString()); // 1) 내 핸들 const handles = await prisma.userHandle.findMany({ where: { email }, select: { id: true, handle: true, icon: true } }); if (handles.length === 0) return NextResponse.json({ items: [] }); const handleStrs = handles.map(h => h.handle); const handleByStr = new Map(handles.map(h => [h.handle, h] as const)); // 2) 매핑된 콘텐츠 const links = await prisma.contentHandle.findMany({ where: { handle: { in: handleStrs } }, select: { contentId: true, handle: true } }); if (links.length === 0) return NextResponse.json({ items: [] }); const contentIds = links.map(l => l.contentId); const normalizeId = (s: string) => (s ?? '').trim(); const contentIdsNormalized = Array.from(new Set(contentIds.map(normalizeId))); const idsForQuery = Array.from(new Set([...contentIds, ...contentIdsNormalized])); const handleByContentId = new Map(links.map(l => [l.contentId, l.handle] as const)); // 3) 콘텐츠 본문 const contents = await prisma.content.findMany({ where: { id: { in: contentIds } }, select: { id: true, subject: true, pubDate: true, views: true, premiumViews: true, watchTime: true } }); // 4) 기간 합계 유효조회수 (findMany로 가져와 JS에서 합산 - groupBy 일부 환경 이슈 회피) const viewRows = await prisma.viewPerDay.findMany({ where: { contented: { in: idsForQuery }, date: { gte: startInclusive, lte: endInclusive } }, select: { contented: true, validViewDay: true } }); const validSumById = new Map(); for (const r of viewRows) { const key = normalizeId(r.contented); validSumById.set(key, (validSumById.get(key) ?? 0) + (r.validViewDay ?? 0)); } // 5) 비용 단가 const cpvRow = await prisma.costPerView.findUnique({ where: { id: 1 } }); const cpv = cpvRow?.costPerView ?? 0; const items = contents.map(c => { const handle = handleByContentId.get(c.id) ?? ''; const handleObj = handleByStr.get(handle); const validViews = validSumById.get(normalizeId(c.id)) ?? 0; const expectedRevenue = validViews * cpv; return { id: c.id, subject: c.subject, pubDate: c.pubDate, views: c.views, premiumViews: c.premiumViews, watchTime: c.watchTime, handle, handleId: handleObj?.id ?? null, icon: handleObj?.icon ?? '', validViews, expectedRevenue, }; }); return NextResponse.json({ items, cpv, start: startInclusive.toISOString(), end: endInclusive.toISOString() }); } catch (e) { console.error('my_contents 오류:', e); return NextResponse.json({ error: '조회 실패' }, { status: 500 }); } finally { await prisma.$disconnect(); } }