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

export async function GET() {
  const session = await requireAnyRole(["INSTITUTION_ADMIN", "TEACHER"]);
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const students = await prisma.student.findMany({
    where: { institutionId: session.institutionId },
    orderBy: { roll: "asc" },
    include: {
      classItem: { select: { name: true, nameBn: true } },
      sectionItem: { select: { name: true, nameBn: true } },
      shiftItem: { select: { name: true, nameBn: true } },
      groupItem: { select: { name: true, nameBn: true } },
      departmentItem: { select: { name: true, nameBn: true } },
      optionalSubjects: {
        include: { subjectItem: { select: { id: true, name: true, nameBn: true } } },
      },
      feeSchedules: { select: { amount: true } },
      feeCollections: { select: { amount: true } },
    },
  });

  const result = students.map((s) => {
    const assigned = s.feeSchedules.reduce((sum, x) => sum + Number(x.amount), 0);
    const paid = s.feeCollections.reduce((sum, x) => sum + Number(x.amount), 0);
    return {
      id: s.id,
      roll: s.roll,
      registrationNo: s.registrationNo,
      cardNo: s.cardNo,
      rfidCardNo: s.rfidCardNo,
      cardValidTill: s.cardValidTill,
      bloodGroup: s.bloodGroup,
      name: s.name,
      nameBn: s.nameBn,
      gender: s.gender,
      dob: s.dob,
      guardianName: s.guardianName,
      guardianNameBn: s.guardianNameBn,
      guardianPhone: s.guardianPhone,
      motherName: s.motherName,
      motherNameBn: s.motherNameBn,
      address: s.address,
      photoUrl: s.photoUrl ?? null,
      status: s.status,
      createdAt: s.createdAt,
      classItemId: s.classItemId ?? null,
      className: s.classItem?.name ?? null,
      classNameBn: s.classItem?.nameBn ?? null,
      sectionItemId: s.sectionItemId ?? null,
      sectionName: s.sectionItem?.name ?? null,
      sectionNameBn: s.sectionItem?.nameBn ?? null,
      shiftItemId: s.shiftItemId ?? null,
      shiftName: s.shiftItem?.name ?? null,
      shiftNameBn: s.shiftItem?.nameBn ?? null,
      groupItemId: s.groupItemId ?? null,
      groupName: s.groupItem?.name ?? null,
      groupNameBn: s.groupItem?.nameBn ?? null,
      departmentItemId: s.departmentItemId ?? null,
      departmentName: s.departmentItem?.name ?? null,
      departmentNameBn: s.departmentItem?.nameBn ?? null,
      optionalSubjects: s.optionalSubjects.map((o) => o.subjectItem),
      feesAssigned: assigned,
      feesPaid: paid,
      feesDue: Math.max(0, assigned - paid),
    };
  });

  return NextResponse.json({ students: result });
}

/* Datagrid / bulk academic-info updates. The student list can update one
   row inline (single-id call) or apply an academic-info assignment to a
   multi-selection at once. Only fields present in the body change; null
   clears the assignment. Admin-only — academic structure is an admin task. */

const ACADEMIC_FIELDS = [
  ["classItemId", "CLASS"],
  ["sectionItemId", "SECTION"],
  ["shiftItemId", "SHIFT"],
  ["groupItemId", "GROUP"],
  ["departmentItemId", "DEPARTMENT"],
] as const;

export async function PATCH(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()) as Record<string, unknown>;
    const rawIds: unknown[] = Array.isArray(body.studentIds) ? body.studentIds : [];
    const ids: number[] = [
      ...new Set(
        rawIds
          .map((v) => Number(v))
          .filter((n) => Number.isInteger(n) && n > 0)
      ),
    ];
    if (ids.length === 0) {
      return NextResponse.json({ error: "NO_STUDENTS" }, { status: 400 });
    }

    // the academic catalog covers central (global) items, the institution's
    // own items and — for branches — the parent's items
    const inst = await prisma.institution.findUnique({
      where: { id: session.institutionId },
      select: { parentId: true },
    });
    const scope = [
      { institutionId: null },
      { institutionId: session.institutionId },
      ...(inst?.parentId ? [{ institutionId: inst.parentId }] : []),
    ];

    const data: Record<string, number | null> = {};
    for (const [field, category] of ACADEMIC_FIELDS) {
      if (body[field] === undefined) continue;
      const n = Number(body[field]);
      if (body[field] !== null && Number.isFinite(n) && n > 0) {
        const item = await prisma.academicItem.findFirst({
          where: { id: n, category, isActive: true, OR: scope },
          select: { id: true },
        });
        if (!item) {
          return NextResponse.json({ error: `INVALID_${category}` }, { status: 400 });
        }
        data[field] = n;
      } else {
        data[field] = null;
      }
    }
    if (Object.keys(data).length === 0) {
      return NextResponse.json({ error: "NO_FIELDS" }, { status: 400 });
    }

    const result = await prisma.student.updateMany({
      where: { id: { in: ids }, institutionId: session.institutionId },
      data,
    });
    return NextResponse.json({ updated: result.count });
  } catch {
    return NextResponse.json({ error: "Could not update students" }, { status: 500 });
  }
}
