import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireAnyRole } from "@/lib/auth";
import { getMemberStudentId } from "@/lib/member";

/** The caller's push notifications — in-app bell feed for every credential.
    Matching: institution-scoped pushes for the caller's institution plus
    central announcements (institutionId null), addressed to any of the
    caller's roles, optionally narrowed to the student's class. */

async function myRolesAndScope(userId: number, role: string, institutionId: number | null) {
  if (role === "STUDENT" || role === "PARENT") {
    const studentId = await getMemberStudentId(userId);
    const classItemId = studentId
      ? (await prisma.student.findUnique({ where: { id: studentId }, select: { classItemId: true } }))
          ?.classItemId ?? null
      : null;
    return { roles: role === "STUDENT" ? ["STUDENT"] : ["PARENT"], classItemId };
  }
  return { roles: [role], classItemId: null };
}

export async function GET(req: Request) {
  const session = await requireAnyRole([
    "SUPER_ADMIN",
    "INSTITUTION_ADMIN",
    "STUDENT",
    "PARENT",
    "TEACHER",
    "STAFF",
    "PRINCIPAL",
    "VICE_PRINCIPAL",
    "EXECUTIVE_MEMBER",
  ]);
  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { roles, classItemId } = await myRolesAndScope(session.userId, session.role, session.institutionId ?? null);
  const url = new URL(req.url);
  const take = Math.min(50, Math.max(1, Number(url.searchParams.get("limit") ?? 25)));

  const roleMatch = roles.map((r) => ({ audienceRoles: { contains: `,${r},` } }));
  const where = {
    OR: [
      // my institution's pushes …
      ...(session.institutionId ? [{ institutionId: session.institutionId }] : []),
      // … and central announcements
      { institutionId: null },
    ],
    AND: [
      { OR: roleMatch },
      // class-scoped pushes only reach that class's students/parents
      ...(roles.some((r) => r === "STUDENT" || r === "PARENT")
        ? [{ OR: [{ classItemId: null }, ...(classItemId ? [{ classItemId }] : [])] }]
        : []),
    ],
  };

  const [rows, unread] = await Promise.all([
    prisma.appNotification.findMany({
      where,
      orderBy: { createdAt: "desc" },
      take,
      include: { reads: { where: { userId: session.userId }, select: { id: true } } },
    }),
    prisma.appNotification.count({
      where: { ...where, reads: { none: { userId: session.userId } } },
    }),
  ]);

  return NextResponse.json({
    unread,
    notifications: rows.map((n) => ({
      id: n.id,
      kind: n.kind,
      title: n.title,
      body: n.body,
      link: n.link,
      classItemId: n.classItemId,
      createdAt: n.createdAt,
      read: n.reads.length > 0,
    })),
  });
}

/** mark notifications read for the caller: { ids: number[] } or { all: true } */
export async function POST(req: Request) {
  const session = await requireAnyRole([
    "SUPER_ADMIN",
    "INSTITUTION_ADMIN",
    "STUDENT",
    "PARENT",
    "TEACHER",
    "STAFF",
    "PRINCIPAL",
    "VICE_PRINCIPAL",
    "EXECUTIVE_MEMBER",
  ]);
  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const body = await req.json();
    let ids: number[] = Array.isArray(body.ids) ? body.ids.map(Number).filter(Number.isInteger) : [];
    if (body.all) {
      const { roles, classItemId } = await myRolesAndScope(session.userId, session.role, session.institutionId ?? null);
      const roleMatch = roles.map((r) => ({ audienceRoles: { contains: `,${r},` } }));
      const mine = await prisma.appNotification.findMany({
        where: {
          OR: [
            ...(session.institutionId ? [{ institutionId: session.institutionId }] : []),
            { institutionId: null },
          ],
          AND: [
            { OR: roleMatch },
            ...(roles.some((r) => r === "STUDENT" || r === "PARENT")
              ? [{ OR: [{ classItemId: null }, ...(classItemId ? [{ classItemId }] : [])] }]
              : []),
          ],
        },
        select: { id: true },
      });
      ids = mine.map((m) => m.id);
    }
    if (ids.length === 0) return NextResponse.json({ success: true, marked: 0 });

    const data = ids.map((notificationId) => ({ notificationId, userId: session.userId }));
    const res = await prisma.appNotificationRead.createMany({ data, skipDuplicates: true });
    return NextResponse.json({ success: true, marked: res.count });
  } catch {
    return NextResponse.json({ error: "Could not mark notifications read" }, { status: 500 });
  }
}
