import { NextResponse } from 'next/server' import prisma from '@/lib/prisma' import { getAuthUser } from '@/lib/auth' import { updateProfileSchema, syncProfileSchema, parseBody } from '@/lib/validations' export const dynamic = 'force-dynamic' // GET - Fetch user profile // Only the profile owner can see private fields (email, notification prefs) export async function GET(req: Request) { try { const { searchParams } = new URL(req.url) const userId = searchParams.get('userId') const username = searchParams.get('username') if (!userId && !username) { return NextResponse.json( { error: 'userId or username required' }, { status: 400 } ) } // Check if the viewer is the profile owner const authUser = await getAuthUser() const isOwner = authUser && ( (userId && authUser.id === userId) || false // username check happens after fetch ) const user = await prisma.user.findFirst({ where: userId ? { id: userId } : { username }, select: { id: true, name: true, username: true, image: true, bio: true, rank: true, totalRuns: true, totalStars: true, totalRemixes: true, socialLinks: true, createdAt: true, // Sensitive fields — only for owner email: true, notifyEmail: true, notifyStars: true, notifyRemixes: true, _count: { select: { prompts: true, collections: true, }, }, }, }) if (!user) { return NextResponse.json( { error: 'User not found' }, { status: 404 } ) } // Strip sensitive fields if not the owner const isRealOwner = isOwner || (authUser && authUser.id === user.id) if (!isRealOwner) { return NextResponse.json({ id: user.id, name: user.name, username: user.username, image: user.image, bio: user.bio, rank: user.rank, totalRuns: user.totalRuns, totalStars: user.totalStars, totalRemixes: user.totalRemixes, socialLinks: user.socialLinks, createdAt: user.createdAt, _count: user._count, }) } return NextResponse.json(user) } catch (error) { console.error('Get profile error:', error) return NextResponse.json( { error: 'Failed to fetch profile' }, { status: 500 } ) } } // PUT - Update user profile — requires authentication (uses server-side auth, not client userId) export async function PUT(req: Request) { try { const authUser = await getAuthUser() if (!authUser) { return NextResponse.json({ error: 'Authentication required' }, { status: 401 }) } const body = await req.json() const parsed = parseBody(updateProfileSchema, body) if (!parsed.success) return parsed.response const { name, username, bio, socialLinks, image, notifyEmail, notifyStars, notifyRemixes } = parsed.data // Check if username is taken (if changing username) if (username) { const existingUser = await prisma.user.findFirst({ where: { username, NOT: { id: authUser.id }, }, }) if (existingUser) { return NextResponse.json( { error: 'Username is already taken' }, { status: 409 } ) } } // Upsert — uses authUser.id from server session, NOT from client body const updatedUser = await prisma.user.upsert({ where: { id: authUser.id }, create: { id: authUser.id, email: authUser.email || `${authUser.id}@stackauth.local`, name: name || null, username: username || null, bio: bio || null, image: image || null, notifyEmail: notifyEmail ?? true, notifyStars: notifyStars ?? true, notifyRemixes: notifyRemixes ?? true, }, update: { ...(name !== undefined && { name }), ...(username !== undefined && { username }), ...(bio !== undefined && { bio }), ...(socialLinks !== undefined && { socialLinks }), ...(image !== undefined && { image }), ...(notifyEmail !== undefined && { notifyEmail }), ...(notifyStars !== undefined && { notifyStars }), ...(notifyRemixes !== undefined && { notifyRemixes }), }, select: { id: true, name: true, username: true, image: true, bio: true, socialLinks: true, notifyEmail: true, notifyStars: true, notifyRemixes: true, }, }) return NextResponse.json(updatedUser) } catch (error) { console.error('Update profile error:', error) return NextResponse.json( { error: 'Failed to update profile' }, { status: 500 } ) } } // POST - Create or sync user from Stack Auth export async function POST(req: Request) { try { const body = await req.json() const parsed = parseBody(syncProfileSchema, body) if (!parsed.success) return parsed.response const { id, email, name, image } = parsed.data // Upsert user - create if doesn't exist, update if does const user = await prisma.user.upsert({ where: { id }, create: { id, email, name: name || null, image: image || null, username: email.split('@')[0], // Default username from email }, update: { email, name: name || null, image: image || null, }, }) return NextResponse.json(user) } catch (error) { console.error('Sync user error:', error) return NextResponse.json( { error: 'Failed to sync user' }, { status: 500 } ) } }