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

/* Subject-based monthly fees (Control Panel feature).
   GET  ?classItemId= → students with their subject-fee summary + the
                        institution's per-subject default rates
   GET  ?studentId=   → that student's itemized assignments
   PUT  { studentId, items:[{subjectItemId, monthlyFee}] } → replace the set
   PUT  { rates:[{subjectItemId, monthlyFee}] } → save default per-subject
        rates (Math 1000, Bangla 800 …) used to auto-fill assignments
   POST { action:"generate", month:"YYYY-MM", classItemId? } → materialize
        the assignments into FeeSchedule rows (one per student × subject)
        so collection, dashboards and member statements work unchanged. */

export async function GET(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session?.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const institutionId = session.institutionId;
  const url = new URL(req.url);
  const studentId = Number(url.searchParams.get("studentId") ?? 0);
  const classItemId = Number(url.searchParams.get("classItemId") ?? 0);

  if (studentId) {
    const student = await prisma.student.findFirst({
      where: { id: studentId, institutionId },
      select: { groupItemId: true, departmentItemId: true },
    });
    // the student's group (school/college) or department (university) subject
    // set — used by the assign modal to pre-tick the right subjects
    const suggestedRows = student
      ? await prisma.groupSubjectSet.findMany({
          where: {
            institutionId,
            OR: [
              { basis: "GROUP", itemId: student.groupItemId ?? -1 },
              { basis: "DEPARTMENT", itemId: student.departmentItemId ?? -1 },
            ],
          },
          select: { subjectItemId: true, basis: true },
        })
      : [];
    const items = await prisma.studentSubjectFee.findMany({
      where: { studentId, institutionId },
      select: {
        subjectItemId: true,
        monthlyFee: true,
        subjectItem: { select: { name: true, nameBn: true } },
      },
      orderBy: { subjectItem: { name: "asc" } },
    });
    const rates = await prisma.subjectFeeRate.findMany({
      where: { institutionId },
      select: { subjectItemId: true, monthlyFee: true },
    });
    return NextResponse.json({
      items: items.map((i) => ({
        subjectItemId: i.subjectItemId,
        subjectName: i.subjectItem.name,
        subjectNameBn: i.subjectItem.nameBn,
        monthlyFee: Number(i.monthlyFee),
      })),
      rates: rates.map((r) => ({ subjectItemId: r.subjectItemId, monthlyFee: Number(r.monthlyFee) })),
      suggested: [...new Set(suggestedRows.map((r) => r.subjectItemId))],
      suggestedBasis: student?.groupItemId ? "GROUP" : student?.departmentItemId ? "DEPARTMENT" : null,
    });
  }

  const students = await prisma.student.findMany({
    where: {
      institutionId,
      status: "ACTIVE",
      ...(classItemId ? { classItemId } : {}),
    },
    select: {
      id: true,
      roll: true,
      name: true,
      nameBn: true,
      classItem: { select: { id: true, name: true, nameBn: true } },
      subjectFees: { select: { monthlyFee: true } },
    },
    orderBy: [{ classItem: { name: "asc" } }, { roll: "asc" }],
  });

  const rates = await prisma.subjectFeeRate.findMany({
    where: { institutionId },
    select: { subjectItemId: true, monthlyFee: true },
  });

  return NextResponse.json({
    rates: rates.map((r) => ({ subjectItemId: r.subjectItemId, monthlyFee: Number(r.monthlyFee) })),
    students: students.map((s) => ({
      id: s.id,
      roll: s.roll,
      name: s.name,
      nameBn: s.nameBn,
      classItemId: s.classItem?.id ?? null,
      className: s.classItem?.name ?? null,
      classNameBn: s.classItem?.nameBn ?? null,
      subjectCount: s.subjectFees.length,
      monthlyTotal: s.subjectFees.reduce((sum, f) => sum + Number(f.monthlyFee), 0),
    })),
  });
}

export async function PUT(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session?.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }
  const institutionId = session.institutionId;
  const body = (await req.json().catch(() => ({}))) as {
    studentId?: number;
    items?: { subjectItemId: number; monthlyFee: number | string }[];
    rates?: { subjectItemId: number; monthlyFee: number | string }[];
  };

  // default per-subject rates management (Math 1000, Bangla 800, …)
  if (body.rates) {
    const wanted = new Map<number, number>();
    for (const r of body.rates) {
      const sid = Number(r.subjectItemId);
      const fee = Number(r.monthlyFee);
      if (!sid) continue;
      if (!Number.isFinite(fee) || fee < 0) {
        return NextResponse.json({ error: "INVALID_FEE" }, { status: 400 });
      }
      if (fee > 0) wanted.set(sid, fee); // 0 = remove the rate
    }
    if (wanted.size > 0) {
      const valid = await prisma.academicItem.count({
        where: { id: { in: [...wanted.keys()] }, category: "SUBJECT", isActive: true },
      });
      if (valid !== wanted.size) {
        return NextResponse.json({ error: "INVALID_SUBJECT" }, { status: 400 });
      }
    }
    await prisma.$transaction(async (tx) => {
      await tx.subjectFeeRate.deleteMany({ where: { institutionId } });
      if (wanted.size > 0) {
        await tx.subjectFeeRate.createMany({
          data: [...wanted.entries()].map(([subjectItemId, monthlyFee]) => ({
            institutionId,
            subjectItemId,
            monthlyFee,
          })),
        });
      }
    });
    return NextResponse.json({ ok: true, count: wanted.size });
  }

  const studentId = Number(body.studentId ?? 0);
  if (!studentId) return NextResponse.json({ error: "STUDENT_REQUIRED" }, { status: 400 });

  const student = await prisma.student.findFirst({
    where: { id: studentId, institutionId },
    select: { id: true },
  });
  if (!student) return NextResponse.json({ error: "Not found" }, { status: 404 });

  // validate subject ids belong to this institution's subject pool
  const wanted = new Map<number, number>();
  for (const it of body.items ?? []) {
    const sid = Number(it.subjectItemId);
    const fee = Number(it.monthlyFee);
    if (!sid) continue;
    if (!Number.isFinite(fee) || fee < 0) {
      return NextResponse.json({ error: "INVALID_FEE" }, { status: 400 });
    }
    wanted.set(sid, fee);
  }
  if (wanted.size > 0) {
    const valid = await prisma.academicItem.count({
      where: { id: { in: [...wanted.keys()] }, category: "SUBJECT", isActive: true },
    });
    if (valid !== wanted.size) {
      return NextResponse.json({ error: "INVALID_SUBJECT" }, { status: 400 });
    }
  }

  await prisma.$transaction(async (tx) => {
    await tx.studentSubjectFee.deleteMany({ where: { studentId, institutionId } });
    if (wanted.size > 0) {
      await tx.studentSubjectFee.createMany({
        data: [...wanted.entries()].map(([subjectItemId, monthlyFee]) => ({
          institutionId,
          studentId,
          subjectItemId,
          monthlyFee,
          assignedById: session.userId,
        })),
      });
    }
  });

  return NextResponse.json({ ok: true, count: wanted.size });
}
