/** * Intake Risk Assessment API * * GET /api/cortex/intake/risico?patientId=xxx&intakeId=xxx * * Returns risk assessments for an intake. * Used by RisicoBlock in Cortex Command Center. */ import { NextRequest, NextResponse } from 'next/server'; import { createClient } from '@/lib/auth/server'; import { z } from 'zod'; // Query parameter schema const QuerySchema = z.object({ patientId: z.string().uuid({ message: 'patientId moet een geldige UUID zijn' }), intakeId: z.string().uuid({ message: 'intakeId moet een geldige UUID zijn' }).optional(), }); // Risk level type type RiskLevel = 'laag' | 'matig' | 'hoog' | 'acuut'; export interface RiskAssessmentItem { id: string; type: string; level: RiskLevel; rationale: string; measures: string | null; assessmentDate: string; evaluationDate: string | null; notes: string | null; } export interface IntakeRisicoResponse { intakeId: string; patientId: string; risks: RiskAssessmentItem[]; summary: { total: number; highestLevel: RiskLevel | null; hasSuicideRisk: boolean; hasSelfHarmRisk: boolean; hasAggressionRisk: boolean; }; lastUpdated: string | null; } // Map risk type to category for summary function categorizeRiskType(type: string): 'suicide' | 'selfharm' | 'aggression' | 'other' { const lowerType = type.toLowerCase(); if (lowerType.includes('suïcid') || lowerType.includes('suicide') || lowerType.includes('suicid')) { return 'suicide'; } if (lowerType.includes('zelfbeschadig') || lowerType.includes('automutil')) { return 'selfharm'; } if (lowerType.includes('agressie') || lowerType.includes('geweld')) { return 'aggression'; } return 'other'; } // Determine highest risk level function getHighestLevel(levels: RiskLevel[]): RiskLevel | null { if (levels.length === 0) return null; const priority: Record = { laag: 1, matig: 2, hoog: 3, acuut: 4, }; return levels.reduce((highest, level) => { return priority[level] > priority[highest] ? level : highest; }); } export async function GET(request: NextRequest) { try { // Auth check const supabase = await createClient(); const { data: { user }, error: authError, } = await supabase.auth.getUser(); if (authError || !user) { return NextResponse.json( { error: 'Niet geautoriseerd. Log opnieuw in.' }, { status: 401 } ); } // Parse and validate query parameters const searchParams = request.nextUrl.searchParams; const patientId = searchParams.get('patientId'); const intakeId = searchParams.get('intakeId'); if (!patientId) { return NextResponse.json( { error: 'Query parameter "patientId" is verplicht' }, { status: 400 } ); } const validation = QuerySchema.safeParse({ patientId, intakeId }); if (!validation.success) { const errorMessage = validation.error.issues .map((e) => e.message) .join(', '); return NextResponse.json({ error: errorMessage }, { status: 400 }); } // If no intakeId provided, get the most recent active intake for this patient let targetIntakeId = validation.data.intakeId; if (!targetIntakeId) { const { data: latestIntake, error: intakeError } = await supabase .from('intakes') .select('id') .eq('patient_id', patientId) .eq('status', 'bezig') .order('start_date', { ascending: false }) .limit(1) .maybeSingle(); if (intakeError) { console.error('Error fetching latest intake:', intakeError); return NextResponse.json( { error: 'Fout bij ophalen intake' }, { status: 500 } ); } if (!latestIntake) { return NextResponse.json( { error: 'Geen actieve intake gevonden voor deze patiënt' }, { status: 404 } ); } targetIntakeId = latestIntake.id; } // Fetch risk assessments const { data: riskData, error: riskError } = await supabase .from('risk_assessments') .select('*') .eq('intake_id', targetIntakeId) .order('assessment_date', { ascending: false }); if (riskError) { console.error('Error fetching risk assessments:', riskError); return NextResponse.json( { error: 'Fout bij ophalen risicotaxaties' }, { status: 500 } ); } const risks: RiskAssessmentItem[] = (riskData || []).map((risk) => ({ id: risk.id, type: risk.risk_type, level: risk.risk_level as RiskLevel, rationale: risk.rationale, measures: risk.measures, assessmentDate: risk.assessment_date, evaluationDate: risk.evaluation_date, notes: risk.notes, })); // Build summary const riskCategories = risks.map((r) => categorizeRiskType(r.type)); const riskLevels = risks.map((r) => r.level); const summary = { total: risks.length, highestLevel: getHighestLevel(riskLevels), hasSuicideRisk: riskCategories.includes('suicide'), hasSelfHarmRisk: riskCategories.includes('selfharm'), hasAggressionRisk: riskCategories.includes('aggression'), }; // Get last updated timestamp const lastUpdated = risks.length > 0 ? risks[0].assessmentDate : null; const response: IntakeRisicoResponse = { intakeId: targetIntakeId, patientId, risks, summary, lastUpdated, }; return NextResponse.json(response, { status: 200 }); } catch (error) { console.error('Error in intake risk API:', error); return NextResponse.json( { error: 'Er ging iets mis bij het ophalen van de risicotaxaties.' }, { status: 500 } ); } }