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

/** Optional-subject pools: admins decide which subjects are optional per class.
    GET returns every class's pool; PUT replaces one class's pool. */
export async function GET() {
  const session = await requireAnyRole(["INSTITUTION_ADMIN", "TEACHER", "STUDENT", "PARENT"]);
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const institutionId = session.institutionId;

  const [pools, studentClasses, selClasses, schedSubjects, selSubjects] = await Promise.all([
    prisma.classOptionalSubject.findMany({
      where: { institutionId },
      include: {
        classItem: { select: { id: true, name: true, nameBn: true } },
        subjectItem: { select: { id: true, name: true, nameBn: true } },
      },
    }),
    // classes actually used by enrolled students
    prisma.student.findMany({
      where: { institutionId, classItemId: { not: null } },
      select: { classItemId: true },
      distinct: ["classItemId"],
    }),
    // classes linked through selections
    prisma.academicSelection.findMany({
      where: { institutionId, academicItem: { category: "CLASS" } },
      select: { academicItemId: true },
    }),
    // subjects used in exam schedules
    prisma.examSchedule.findMany({
      where: { institutionId, subjectItemId: { not: null } },
      select: { subjectItemId: true },
      distinct: ["subjectItemId"],
    }),
    // subjects linked through selections
    prisma.academicSelection.findMany({
      where: { institutionId, academicItem: { category: "SUBJECT" } },
      select: { academicItemId: true },
    }),
  ]);

  const classIds = new Set<number>([
    ...studentClasses.map((s) => s.classItemId!).filter(Boolean),
    ...selClasses.map((s) => s.academicItemId),
  ]);
  const subjectIds = new Set<number>([
    ...schedSubjects.map((s) => s.subjectItemId!).filter(Boolean),
    ...selSubjects.map((s) => s.academicItemId),
  ]);

  const [classes, subjects] = await Promise.all([
    classIds.size
      ? prisma.academicItem.findMany({
          where: { id: { in: [...classIds] } },
          select: { id: true, name: true, nameBn: true },
          orderBy: { name: "asc" },
        })
      : Promise.resolve([]),
    subjectIds.size
      ? prisma.academicItem.findMany({
          where: { id: { in: [...subjectIds] } },
          select: { id: true, name: true, nameBn: true },
          orderBy: { name: "asc" },
        })
      : Promise.resolve([]),
  ]);

  const byClass: Record<number, { id: number; name: string; nameBn: string }[]> = {};
  for (const p of pools) {
    (byClass[p.classItemId] ??= []).push(p.subjectItem);
  }

  return NextResponse.json({ classes, subjects, byClass });
}

/** Replace the optional pool for one class (admin only). */
export async function PUT(req: Request) {
  const session = await requireAnyRole(["INSTITUTION_ADMIN"]);
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const body = await req.json();
    const classItemId = Number(body.classItemId);
    const subjectIds: number[] = Array.isArray(body.subjectIds)
      ? body.subjectIds.map((v: unknown) => Number(v)).filter((n: number) => Boolean(n))
      : [];
    if (!classItemId) {
      return NextResponse.json({ error: "Missing class" }, { status: 400 });
    }

    await prisma.$transaction([
      prisma.classOptionalSubject.deleteMany({
        where: { institutionId: session.institutionId, classItemId },
      }),
      ...subjectIds.map((subjectItemId) =>
        prisma.classOptionalSubject.create({
          data: { institutionId: session.institutionId!, classItemId, subjectItemId },
        })
      ),
    ]);
    return NextResponse.json({ ok: true });
  } catch {
    return NextResponse.json({ error: "Could not save pool" }, { status: 500 });
  }
}
