/**
 * Vendor-attributed SLA (2026-06-02) — assign/unassign monitors to a vendor.
 *
 *   PUT /api/vendors/[id]/monitors   body { monitorIds: number[] }
 *
 * Sets each listed monitor's vendorId to this vendor, and clears the vendorId
 * of any monitor previously linked to this vendor but NOT in the list (so PUT
 * is the full membership set, idempotent). ADMIN/EDITOR only.
 */
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/lib/auth';
import { prisma } from '@/lib/prisma';
import { parseJsonBounded, BodyTooLargeError, BodyParseError } from '@/lib/api-helpers/parse-json';
import { assignMonitorsSchema } from '@/lib/validations/vendor.schema';

const ROLES_WRITE = ['ADMIN', 'EDITOR'];

export async function PUT(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
    const session = await getServerSession(authOptions);
    if (!session?.user?.id) {
        return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }
    const role = (session.user as { role?: string }).role;
    if (!role || !ROLES_WRITE.includes(role)) {
        return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
    }

    const { id } = await params;
    const vendorId = parseInt(id, 10);
    if (!Number.isFinite(vendorId) || vendorId <= 0) {
        return NextResponse.json({ error: 'Invalid vendor id' }, { status: 400 });
    }

    try {
        const raw = await parseJsonBounded<unknown>(req, { maxBytes: 64 * 1024 });
        const parsed = assignMonitorsSchema.safeParse(raw);
        if (!parsed.success) {
            return NextResponse.json(
                { error: 'Invalid payload', details: parsed.error.flatten() },
                { status: 400 },
            );
        }
        const monitorIds = parsed.data.monitorIds;

        const vendor = await prisma.vendor.findFirst({ where: { id: vendorId, deletedAt: null }, select: { id: true } });
        if (!vendor) {
            return NextResponse.json({ error: 'Vendor not found' }, { status: 404 });
        }

        await prisma.$transaction([
            // Unlink monitors currently on this vendor that aren't in the new set.
            prisma.monitor.updateMany({
                where: { vendorId, id: { notIn: monitorIds.length > 0 ? monitorIds : [-1] } },
                data: { vendorId: null },
            }),
            // Link the requested monitors (only undeleted ones).
            prisma.monitor.updateMany({
                where: { id: { in: monitorIds }, deletedAt: null },
                data: { vendorId },
            }),
        ]);

        const monitors = await prisma.monitor.findMany({
            where: { vendorId, deletedAt: null },
            select: { id: true, name: true, type: true, region: true },
            orderBy: { name: 'asc' },
        });

        return NextResponse.json({ success: true, monitors });
    } catch (error: unknown) {
        if (error instanceof BodyTooLargeError) {
            return NextResponse.json({ error: error.message }, { status: 413 });
        }
        if (error instanceof BodyParseError) {
            return NextResponse.json({ error: error.message }, { status: 400 });
        }
        console.error('Vendor monitor assignment failed:', error);
        return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
    }
}
