/**
 * GET /api/notifications?brandId=X&unreadOnly=true&limit=20&page=1
 * ────────────────────────────────────────────────────────────────
 * Returns notifications from two sources, merged + normalised:
 *
 *   • prisma.Notification — the canonical notification table.
 *   • signal-type SiteEvent rows — output of the signal-detection
 *     engine (signal_*) and the rank-check cron (rank_*). Normalised
 *     via src/lib/services/notification-sources.ts.
 *
 * Models the original spec mentioned (DetectedSignal, AiVisibilityChange,
 * IndustryAlert) don't exist as Prisma tables in this repo — SiteEvent
 * is the live analog. When those models land, extend listSignalEvents().
 *
 * The response shape keeps the existing `notifications` key (which the
 * bell already consumes) but every item now carries a normalised
 * sourceUrl for routing and a `source` tag so the UI can colour-code.
 */
import { NextResponse } from "next/server";
import { getCurrentUser } from "@/lib/auth";
import { prisma } from "@/lib/prisma";
import { listSignalEvents } from "@/lib/services/notification-sources";

export const dynamic = "force-dynamic";

export async function GET(req: Request) {
  const user = await getCurrentUser();
  if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  const { searchParams } = new URL(req.url);
  const brandId = searchParams.get("brandId");
  // Return empty instead of 400 when brandId is missing — the topnav
  // bell polls this on mount before the brand context resolves,
  // producing a 400 that triggered an infinite re-render loop (the
  // error state update caused a re-render which re-triggered the
  // fetch which 400d again).
  if (!brandId) {
    return NextResponse.json({ notifications: [], unreadCount: 0 });
  }

  const brand = await prisma.brand.findUnique({ where: { id: brandId }, include: { organization: { include: { memberships: true } } } });
  if (!brand) return NextResponse.json({ error: "Brand not found" }, { status: 404 });
  if (!brand.organization.memberships.some((m) => m.userId === user.id)) return NextResponse.json({ error: "Access denied" }, { status: 403 });

  const limit = Math.max(1, Math.min(100, Number(searchParams.get("limit") || 20)));
  const unreadOnly = searchParams.get("unreadOnly") === "true";

  // Pull both sources in parallel, cap each at `limit` so even a very
  // chatty brand can't starve one source out of the merged view.
  const [notifRows, signalItems] = await Promise.all([
    prisma.notification.findMany({
      where: {
        brandId,
        ...(unreadOnly ? { isRead: false } : {}),
        ...(searchParams.get("channel") ? { channel: searchParams.get("channel")! } : {}),
      },
      orderBy: { createdAt: "desc" },
      take: limit,
    }),
    listSignalEvents(brandId, limit),
  ]);

  // Shape the Notification rows into the same unified shape listSignalEvents
  // returns, then keep the original fields the bell already renders (title,
  // message, severity, isRead, metadata) by spreading at the end. The bell's
  // type signature is loose so the extra source + sourceUrl fields are safe.
  interface NotifRow {
    id: string; title: string; message: string; type: string; severity: string;
    channel: string; isRead: boolean; readAt: Date | null; metadata: unknown;
    createdAt: Date;
  }
  const notifNormalised = (notifRows as NotifRow[]).map((n) => {
    const meta = (n.metadata ?? {}) as Record<string, unknown>;
    const sourceUrl = typeof meta.link === "string" ? meta.link : "/notifications";
    return {
      id: n.id,
      source: "notification" as const,
      title: n.title,
      message: n.message,
      description: n.message,
      type: n.type,
      severity: n.severity,
      priority: n.severity,
      isRead: n.isRead,
      read: n.isRead,
      metadata: n.metadata,
      createdAt: n.createdAt.toISOString(),
      sourceUrl,
    };
  });

  // Signal items already have `read`, `priority`, `sourceUrl`. Add `isRead`
  // + `severity` aliases so the bell's existing render path (which uses
  // isRead + severity) Just Works without a rewrite.
  const signalRendered = signalItems
    .filter((s) => !unreadOnly || !s.read)
    .map((s) => ({
      id: s.id,
      source: s.source,
      title: s.title,
      message: s.description,
      description: s.description,
      type: s.source === "signal" ? "site_tag_signal" : "rank_change",
      severity: s.priority,
      priority: s.priority,
      isRead: s.read,
      read: s.read,
      metadata: { link: s.sourceUrl },
      createdAt: s.createdAt,
      sourceUrl: s.sourceUrl,
    }));

  const merged = [...notifNormalised, ...signalRendered]
    .sort((a, b) => b.createdAt.localeCompare(a.createdAt))
    .slice(0, limit);

  return NextResponse.json({
    notifications: merged,
    total: merged.length,
    counts: {
      notifications: notifNormalised.length,
      signals: signalRendered.length,
    },
  });
}
