import { NextResponse } from 'next/server'; import { z } from 'zod'; import { eq, and } from 'drizzle-orm'; import { withAuth } from '@/lib/api/helpers'; import { parseBody } from '@/lib/api/route-helpers'; import { runBulk } from '@/lib/api/bulk-helpers'; import { db } from '@/lib/db'; import { yachts, yachtTags } from '@/lib/db/schema/yachts'; import { archiveYacht, setYachtTags } from '@/lib/services/yachts.service'; import { errorResponse } from '@/lib/errors'; const bulkSchema = z.discriminatedUnion('action', [ z.object({ action: z.literal('archive'), ids: z.array(z.string().min(1)).min(1).max(100), }), z.object({ action: z.literal('add_tag'), ids: z.array(z.string().min(1)).min(1).max(100), tagId: z.string().min(1), }), z.object({ action: z.literal('remove_tag'), ids: z.array(z.string().min(1)).min(1).max(100), tagId: z.string().min(1), }), ]); const PERMISSION_BY_ACTION = { archive: 'delete' as const, add_tag: 'edit' as const, remove_tag: 'edit' as const, }; export const POST = withAuth(async (req, ctx) => { let body: z.infer; try { body = await parseBody(req, bulkSchema); } catch (error) { return errorResponse(error); } const allowed = ctx.isSuperAdmin ? true : !!ctx.permissions?.yachts?.[PERMISSION_BY_ACTION[body.action]]; if (!allowed) return NextResponse.json({ error: 'Forbidden' }, { status: 403 }); const meta = { userId: ctx.userId, portId: ctx.portId, ipAddress: ctx.ipAddress, userAgent: ctx.userAgent, }; const { results, summary } = await runBulk(body.ids, async (id) => { if (body.action === 'archive') { await archiveYacht(id, ctx.portId, meta); return; } const yacht = await db.query.yachts.findFirst({ where: and(eq(yachts.id, id), eq(yachts.portId, ctx.portId)), }); if (!yacht) throw new Error('Yacht not found'); const existing = await db .select({ tagId: yachtTags.tagId }) .from(yachtTags) .where(eq(yachtTags.yachtId, id)); const current = new Set(existing.map((t) => t.tagId)); if (body.action === 'add_tag') current.add(body.tagId); else current.delete(body.tagId); await setYachtTags(id, ctx.portId, Array.from(current), meta); }); return NextResponse.json({ data: { results, summary } }); });