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 { clients, clientTags } from '@/lib/db/schema/clients'; import { archiveClient, setClientTags } from '@/lib/services/clients.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?.clients?.[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 archiveClient(id, ctx.portId, meta); return; } const client = await db.query.clients.findFirst({ where: and(eq(clients.id, id), eq(clients.portId, ctx.portId)), }); if (!client) throw new Error('Client not found'); const existing = await db .select({ tagId: clientTags.tagId }) .from(clientTags) .where(eq(clientTags.clientId, 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 setClientTags(id, ctx.portId, Array.from(current), meta); }); return NextResponse.json({ data: { results, summary } }); });