import { NextRequest, NextResponse } from 'next/server'; import { z } from 'zod'; import { withAuth, withPermission } from '@/lib/api/helpers'; import { errorResponse } from '@/lib/errors'; import { getOperationalKpis, getUtilisationHeatmap, getStatusMixOverTime, getTenancyChurn, getTenureDistribution, getSigningBoxPlot, getOccupancyByArea, getDocumentsInPipeline, getTenanciesEndingSoon, getVacantBerths, getStuckSigning, getHighestValueVacant, } from '@/lib/services/reports/operational.service'; const querySchema = z.object({ from: z.string().datetime().optional(), to: z.string().datetime().optional(), }); function resolveRange(from?: string, to?: string): { from: Date; to: Date } { const now = new Date(); const defaultFrom = new Date(now); defaultFrom.setDate(defaultFrom.getDate() - 30); return { from: from ? new Date(from) : defaultFrom, to: to ? new Date(to) : now, }; } export const GET = withAuth( withPermission('reports', 'view_dashboard', async (req: NextRequest, ctx) => { try { const params = req.nextUrl.searchParams; const { from, to } = querySchema.parse({ from: params.get('from') ?? undefined, to: params.get('to') ?? undefined, }); const range = resolveRange(from, to); const [ kpis, utilisationHeatmap, statusMix, tenancyChurn, tenureDistribution, signingBoxPlot, occupancyByArea, docsInPipeline, endingSoon, vacantBerths, stuckSigning, highestValueVacant, ] = await Promise.all([ getOperationalKpis(ctx.portId, range), getUtilisationHeatmap(ctx.portId), getStatusMixOverTime(ctx.portId), getTenancyChurn(ctx.portId), getTenureDistribution(ctx.portId), getSigningBoxPlot(ctx.portId), getOccupancyByArea(ctx.portId), getDocumentsInPipeline(ctx.portId), getTenanciesEndingSoon(ctx.portId), getVacantBerths(ctx.portId), getStuckSigning(ctx.portId), getHighestValueVacant(ctx.portId), ]); return NextResponse.json({ data: { kpis, utilisationHeatmap, statusMix, tenancyChurn, tenureDistribution, signingBoxPlot, occupancyByArea, docsInPipeline, endingSoon, vacantBerths, stuckSigning, highestValueVacant, range: { from: range.from.toISOString(), to: range.to.toISOString(), }, }, }); } catch (error) { return errorResponse(error); } }), );