import { NextResponse } from 'next/server'; import { getServerSession } from 'next-auth'; import { authOptions } from '@/lib/auth'; import { prisma } from '@/lib/prisma'; import { getHolidayHint } from '@/lib/holidays'; export async function GET(req: Request) { try { const session = await getServerSession(authOptions); if (!session || !session.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const userId = (session.user as any).id; if (!userId) { return NextResponse.json({ error: 'User ID missing from session' }, { status: 400 }); } const { searchParams } = new URL(req.url); const weekStartParam = searchParams.get('weekStart'); if (!weekStartParam) { return NextResponse.json({ error: 'weekStart is required' }, { status: 400 }); } const date = new Date(weekStartParam); date.setUTCHours(0, 0, 0, 0); // Fetch user preferences const user = await prisma.user.findUnique({ where: { id: userId }, select: { goalFallbackType: true, goalDefaultSentence: true, } }); // 1. Check if user has a custom set goal for THIS week specifically const goal = await prisma.weeklyGoal.findUnique({ where: { userId_weekStart: { userId: userId, weekStart: date, }, }, }); if (goal && goal.text && goal.text !== 'your goal of this week' && goal.text !== user?.goalDefaultSentence) { return NextResponse.json({ goal: goal.text }); } // 2. Handle Fallbacks based on user settings const fallbackType = user?.goalFallbackType || 'quote'; if (fallbackType === 'next_todo') { // Fetch first incomplete task for this week const weekEnd = new Date(date); weekEnd.setDate(weekEnd.getDate() + 7); const nextTask = await prisma.task.findFirst({ where: { userId, completed: false, scheduledDate: { gte: date, lt: weekEnd } }, orderBy: [ { scheduledDate: 'asc' }, { order: 'asc' } ] }); if (nextTask) { return NextResponse.json({ goal: `Next: ${nextTask.title}`, isNextTask: true }); } // If no tasks, fall back to quote or default? Let's go to quote. } if (fallbackType === 'default') { return NextResponse.json({ goal: user?.goalDefaultSentence || 'goal of the week', isDefault: true }); } // 3. Fallback to holiday/celebration hints (High priority for "quote" type) const holidayHint = getHolidayHint(date); if (holidayHint) { return NextResponse.json({ goal: holidayHint, isHoliday: true }); } // 4. Fallback to ZenQuotes motivational quote try { const res = await fetch('https://zenquotes.io/api/random', { signal: AbortSignal.timeout(3000) }); if (res.ok) { const data = await res.json(); if (data && data[0] && data[0].q) { return NextResponse.json({ goal: `${data[0].q} — ${data[0].a}`, isQuote: true }); } } } catch (e) { console.error('Failed to fetch from ZenQuotes:', e); } // Final default fallback return NextResponse.json({ goal: user?.goalDefaultSentence || 'goal of the week', isDefault: true }); } catch (error) { console.error('API Error:', error); return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); } } // POST delegates to PUT for client compatibility export async function POST(req: Request) { return PUT(req); } export async function PUT(req: Request) { try { const session = await getServerSession(authOptions); if (!session || !session.user) { return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } const userId = (session.user as any).id; if (!userId) { return NextResponse.json({ error: 'User ID missing from session' }, { status: 400 }); } const { weekStart, text } = await req.json(); if (!weekStart) { return NextResponse.json({ error: 'weekStart is required' }, { status: 400 }); } const date = new Date(weekStart); date.setUTCHours(0, 0, 0, 0); const goal = await prisma.weeklyGoal.upsert({ where: { userId_weekStart: { userId: userId, weekStart: date, }, }, update: { text }, create: { userId: userId, weekStart: date, text, }, }); return NextResponse.json({ goal: goal.text }); } catch (error) { console.error('API Error:', error); return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); } }