/**
 * PUT /api/notifications/read — mark notifications as read.
 *
 * Body:
 *   { ids: string[] }                 — mixed Notification + signal SiteEvent IDs
 *   { all: true, brandId: string }    — mark every unread item across both sources
 *
 * The route auto-detects which table each id belongs to by looking it
 * up in both tables. Signal SiteEvent rows are marked read via
 * eventData mutation (see markSignalsRead in notification-sources.ts)
 * so the detection engine's status/readAt convention stays intact.
 */
import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { markAllSignalsRead, markSignalsRead } from "@/lib/services/notification-sources";

export const dynamic = "force-dynamic";

export async function PUT(req: Request) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  const body = await req.json().catch(() => null) as { ids?: string[]; all?: boolean; brandId?: string } | null;
  if (!body) return NextResponse.json({ error: "Invalid body" }, { status: 400 });

  const now = new Date();

  if (body.all && body.brandId) {
    // Authorise — user must be a member of the brand's org.
    const brand = await prisma.brand.findUnique({
      where: { id: body.brandId },
      include: { organization: { include: { memberships: true } } },
    });
    if (!brand || !brand.organization.memberships.some((m) => m.userId === user.id)) {
      return NextResponse.json({ error: "Access denied" }, { status: 403 });
    }
    const [notifResult, signalCount] = await Promise.all([
      prisma.notification.updateMany({
        where: { brandId: body.brandId, isRead: false },
        data: { isRead: true, readAt: now },
      }),
      markAllSignalsRead(body.brandId),
    ]);
    return NextResponse.json({ ok: true, notifications: notifResult.count, signals: signalCount });
  }

  if (Array.isArray(body.ids) && body.ids.length > 0) {
    // Split ids into (Notification, SiteEvent) buckets by looking each
    // up — cheaper than dispatching separate updates to both tables for
    // every id and silently succeeding on the table that doesn't own it.
    const notifIds = await prisma.notification.findMany({
      where: { id: { in: body.ids } },
      select: { id: true, brandId: true },
    });
    const signalIds = await prisma.siteEvent.findMany({
      where: { id: { in: body.ids } },
      select: { id: true, brandId: true },
    });

    // Authorise: every brand referenced in the request must include the user.
    const touchedBrands = new Set<string>([
      ...notifIds.map((n) => n.brandId),
      ...signalIds.map((s) => s.brandId),
    ]);
    if (touchedBrands.size > 0) {
      const brands = await prisma.brand.findMany({
        where: { id: { in: [...touchedBrands] } },
        include: { organization: { include: { memberships: true } } },
      });
      for (const b of brands) {
        if (!b.organization.memberships.some((m) => m.userId === user.id)) {
          return NextResponse.json({ error: "Access denied" }, { status: 403 });
        }
      }
    }

    const [notifResult, signalCount] = await Promise.all([
      notifIds.length > 0
        ? prisma.notification.updateMany({
            where: { id: { in: notifIds.map((n) => n.id) } },
            data: { isRead: true, readAt: now },
          })
        : Promise.resolve({ count: 0 }),
      // markSignalsRead is brand-scoped, so group by brandId.
      (async () => {
        let total = 0;
        const byBrand = new Map<string, string[]>();
        for (const s of signalIds) {
          const list = byBrand.get(s.brandId) ?? [];
          list.push(s.id);
          byBrand.set(s.brandId, list);
        }
        for (const [brandId, ids] of byBrand) {
          total += await markSignalsRead(brandId, ids);
        }
        return total;
      })(),
    ]);

    return NextResponse.json({ ok: true, notifications: notifResult.count, signals: signalCount });
  }

  return NextResponse.json({ error: "ids or {all, brandId} required" }, { status: 400 });
}
