import { NextRequest, NextResponse } from 'next/server'; import { z } from 'zod'; import { createClient } from '@/lib/auth/server'; import { CreateReportSchema, CreateVerpleegkundigSchema, calculateShiftDate, type ReportListResponse, VERPLEEG_REPORT_TYPES, } from '@/lib/types/report'; export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const patientId = searchParams.get('patientId'); const type = searchParams.get('type'); // Optional: filter by type const types = searchParams.get('types'); // Optional: comma-separated list of types const startDate = searchParams.get('startDate'); // Optional: YYYY-MM-DD const endDate = searchParams.get('endDate'); // Optional: YYYY-MM-DD const includeInHandover = searchParams.get('includeInHandover'); // Optional: 'true' // Pagination parameters const limitParam = searchParams.get('limit'); const offsetParam = searchParams.get('offset'); const limit = Math.min(Math.max(parseInt(limitParam ?? '50'), 1), 100); // 1-100, default 50 const offset = Math.max(parseInt(offsetParam ?? '0'), 0); if (!patientId) { return NextResponse.json( { error: 'patientId query parameter is verplicht' }, { status: 400 } ); } if (!z.string().uuid().safeParse(patientId).success) { return NextResponse.json( { error: 'patientId moet een geldige UUID zijn' }, { status: 400 } ); } // Validate date formats const dateRegex = /^\d{4}-\d{2}-\d{2}$/; if (startDate && !dateRegex.test(startDate)) { return NextResponse.json( { error: 'startDate moet in YYYY-MM-DD formaat zijn' }, { status: 400 } ); } if (endDate && !dateRegex.test(endDate)) { return NextResponse.json( { error: 'endDate moet in YYYY-MM-DD formaat zijn' }, { status: 400 } ); } const supabase = await createClient(); // Selectieve kolommen voor betere performance // Grote kolommen (ai_reasoning, audio_url) worden niet opgehaald tenzij nodig const selectColumns = [ 'id', 'patient_id', 'type', 'content', 'created_at', 'updated_at', 'shift_date', 'include_in_handover', 'structured_data', 'created_by', ].join(', '); let query = supabase .from('reports') .select(selectColumns) .eq('patient_id', patientId) .is('deleted_at', null) .order('created_at', { ascending: false }); // Filter by single type if (type) { query = query.eq('type', type); } // Filter by multiple types (comma-separated) if (types) { const typeList = types.split(',').map((t) => t.trim()); query = query.in('type', typeList); } // Filter by date range (for shift_date, used by verpleegkundig) if (startDate && endDate) { query = query.gte('shift_date', startDate).lte('shift_date', endDate); } else if (startDate) { query = query.gte('shift_date', startDate); } else if (endDate) { query = query.lte('shift_date', endDate); } // Filter for handover reports only if (includeInHandover === 'true') { query = query.eq('include_in_handover', true); } // Apply pagination query = query.range(offset, offset + limit - 1); // Execute query with count const { data, error, count } = await query; if (error) { console.error('Error fetching reports:', error); return NextResponse.json( { error: 'Fout bij ophalen rapportages', details: error.message }, { status: 500 } ); } // Get total count (separate query for accurate pagination) const countQuery = supabase .from('reports') .select('*', { count: 'exact', head: true }) .eq('patient_id', patientId) .is('deleted_at', null); // Apply same filters to count query if (type) countQuery.eq('type', type); if (types) countQuery.in('type', types.split(',').map((t) => t.trim())); if (startDate && endDate) { countQuery.gte('shift_date', startDate).lte('shift_date', endDate); } else if (startDate) { countQuery.gte('shift_date', startDate); } else if (endDate) { countQuery.lte('shift_date', endDate); } if (includeInHandover === 'true') countQuery.eq('include_in_handover', true); const { count: totalCount } = await countQuery; const total = totalCount ?? 0; return NextResponse.json({ reports: data ?? [], total, limit, offset, hasMore: offset + limit < total, }); } catch (error) { console.error('Unexpected error in GET /api/reports:', error); return NextResponse.json( { error: 'Onverwachte serverfout' }, { status: 500 } ); } } export async function POST(request: NextRequest) { try { const body = await request.json(); // Check if this is a verpleegkundig report const isVerpleegkundig = body.type === 'verpleegkundig'; // Use appropriate schema const result = isVerpleegkundig ? CreateVerpleegkundigSchema.safeParse(body) : CreateReportSchema.safeParse(body); if (!result.success) { return NextResponse.json( { error: 'Validatiefout', details: result.error.issues.map((issue) => ({ field: issue.path.join('.'), message: issue.message, })), }, { status: 400 } ); } const supabase = await createClient(); const { data: authData } = await supabase.auth.getUser(); if (!authData?.user) { return NextResponse.json({ error: 'Niet geautoriseerd' }, { status: 401 }); } // Get practitioner ID for the current user const { data: practitioner } = await supabase .from('practitioners') .select('id') .eq('user_id', authData.user.id) .single(); if (isVerpleegkundig) { // Handle verpleegkundig report const { patient_id, content, category, include_in_handover } = result.data as z.infer; const now = new Date(); const shiftDate = calculateShiftDate(now); const { data, error } = await supabase .from('reports') .insert({ patient_id, type: 'verpleegkundig', content, structured_data: { category }, include_in_handover: include_in_handover ?? false, shift_date: shiftDate, created_by: practitioner?.id ?? null, }) .select('*') .single(); if (error) { console.error('Error creating verpleegkundig report:', error); return NextResponse.json( { error: 'Opslaan mislukt', details: error.message }, { status: 500 } ); } return NextResponse.json(data, { status: 201 }); } else { // Handle standard report const { patient_id, type, content, ai_confidence, ai_reasoning, encounter_id, intake_id, } = result.data as z.infer; const { data, error } = await supabase .from('reports') .insert({ patient_id, type, content, ai_confidence, ai_reasoning, encounter_id, intake_id, created_by: practitioner?.id ?? null, }) .select('*') .single(); if (error) { console.error('Error creating report:', error); return NextResponse.json( { error: 'Opslaan mislukt', details: error.message }, { status: 500 } ); } return NextResponse.json(data, { status: 201 }); } } catch (error) { console.error('Unexpected error in POST /api/reports:', error); if (error instanceof SyntaxError) { return NextResponse.json( { error: 'Ongeldige JSON in request body' }, { status: 400 } ); } return NextResponse.json( { error: 'Onverwachte serverfout' }, { status: 500 } ); } }