import { NextRequest, NextResponse } from 'next/server'; import { db } from '@/lib/db'; import { annotations, candles, charts } from '@/lib/db/schema'; import { eq, and, desc } from 'drizzle-orm'; export async function GET(request: NextRequest) { try { const { searchParams } = request.nextUrl; let chartId = searchParams.get('chartId'); // Fall back to most recent chart if no chartId provided if (!chartId) { const latest = await db.select({ id: charts.id }).from(charts).orderBy(desc(charts.created_at)).limit(1); if (latest.length === 0) { return new NextResponse('timestamp,label_type,price\n', { headers: { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="annotations.csv"', }, }); } chartId = String(latest[0].id); } const chartIdNum = parseInt(chartId, 10); const allAnnotations = await db .select() .from(annotations) .where(eq(annotations.chart_id, chartIdNum)); // Build CSV content const csvRows = ['timestamp,label_type,price']; for (const annotation of allAnnotations) { let price: number | null = null; if (annotation.label_type === 'break_up' || annotation.label_type === 'break_down') { const candleResult = await db .select() .from(candles) .where(and(eq(candles.chart_id, chartIdNum), eq(candles.time, annotation.timestamp))) .limit(1); if (candleResult.length > 0) { price = candleResult[0].close; } } else if (annotation.label_type === 'line' && annotation.geometry) { const geometry = annotation.geometry as any; price = geometry.startPrice || null; } csvRows.push( `${annotation.timestamp},${annotation.label_type},${price !== null ? price : ''}` ); } const csvContent = csvRows.join('\n'); return new NextResponse(csvContent, { headers: { 'Content-Type': 'text/csv', 'Content-Disposition': 'attachment; filename="annotations.csv"', }, }); } catch (error: any) { return NextResponse.json( { error: error.message || 'Failed to export annotations' }, { status: 500 } ); } }