import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireAnyRole } from "@/lib/auth";
import { getMemberStudentId } from "@/lib/member";
import { gradeFromPercent } from "@/lib/constants";
import { buildSingleExamSheet, principalSignatureFor } from "@/lib/result-sheet";

/** Published exam results of the caller's own (child's) class — students and
    parents only ever see exams whose results the institution published.
    Without params: every published exam with per-subject breakdown + grades.
    ?examId=<id>: one exam returning the SAME portal-grade marksheet row the
    institution prints (per-subject cells, highest marks, merit position,
    attendance, verification QR) plus the letterhead and principal signature. */
export async function GET(req: Request) {
  const session = await requireAnyRole(["STUDENT", "PARENT"]);
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const studentId = await getMemberStudentId(session.userId);
  if (!studentId) {
    return NextResponse.json({ error: "NO_LINKED_STUDENT" }, { status: 409 });
  }
  const student = await prisma.student.findUnique({
    where: { id: studentId },
    select: { classItemId: true, sectionItemId: true, roll: true, name: true, nameBn: true },
  });
  if (!student) {
    return NextResponse.json({ error: "NO_LINKED_STUDENT" }, { status: 409 });
  }

  // exams for the student's class — whole-class (no section) or their section
  const scope = [
    { classItemId: student.classItemId, sectionItemId: null },
    { classItemId: student.classItemId, sectionItemId: student.sectionItemId },
  ];

  const examId = Number(new URL(req.url).searchParams.get("examId") ?? "");

  // ---------- marksheet mode: one exam, portal-grade row ----------
  if (Number.isInteger(examId) && examId > 0) {
    // the exam must be result-published AND belong to the student's class scope
    const allowed = await prisma.exam.findFirst({
      where: {
        id: examId,
        institutionId: session.institutionId,
        resultPublished: true,
        OR: scope,
      },
      select: { id: true },
    });
    if (!allowed) return NextResponse.json({ error: "EXAM_NOT_FOUND" }, { status: 404 });

    const [built, institution, sig] = await Promise.all([
      buildSingleExamSheet(session.institutionId, examId),
      prisma.institution.findUnique({
        where: { id: session.institutionId },
        select: { name: true, address: true, phone: true, logo: true },
      }),
      principalSignatureFor(session.institutionId),
    ]);
    if (!built) return NextResponse.json({ error: "EXAM_NOT_FOUND" }, { status: 404 });

    const row = built.rows.find((r) => r.studentId === studentId);
    if (!row) return NextResponse.json({ error: "EXAM_NOT_FOUND" }, { status: 404 });

    return NextResponse.json({
      exam: built.exam,
      row,
      institution: institution ?? null,
      principalSignature: sig.principalSignature,
      principalName: sig.principalName,
    });
  }

  // ---------- list mode: every published exam, summarized ----------
  const exams = await prisma.exam.findMany({
    where: {
      institutionId: session.institutionId,
      resultPublished: true,
      OR: scope,
    },
    orderBy: { startDate: "desc" },
    select: {
      id: true,
      name: true,
      nameBn: true,
      classItem: { select: { name: true, nameBn: true } },
      status: true,
      startDate: true,
      endDate: true,
      resultPublishedAt: true,
      schedules: {
        orderBy: { date: "asc" },
        select: {
          id: true,
          date: true,
          fullMarks: true,
          totalPassMarks: true,
          subjectItem: { select: { id: true, name: true, nameBn: true } },
          marks: {
            where: { studentId },
            select: { cq: true, mcq: true, applied: true, total: true, note: true },
          },
        },
      },
    },
  });

  const result = exams.map((exam) => {
    const subjects = exam.schedules.map((s) => {
      const mark = s.marks[0] ?? null;
      const total = mark?.total ?? null;
      const percent = total != null && s.fullMarks > 0 ? (total / s.fullMarks) * 100 : null;
      const failed = total != null && s.totalPassMarks != null && total < s.totalPassMarks;
      return {
        scheduleId: s.id,
        subject: s.subjectItem?.name ?? null,
        subjectBn: s.subjectItem?.nameBn ?? null,
        date: s.date,
        fullMarks: s.fullMarks,
        passMarks: s.totalPassMarks,
        cq: mark?.cq ?? null,
        mcq: mark?.mcq ?? null,
        applied: mark?.applied ?? null,
        total,
        note: mark?.note ?? null,
        grade: percent != null ? gradeFromPercent(percent).grade : null,
        point: percent != null ? gradeFromPercent(percent).point : null,
        failed,
      };
    });
    const entered = subjects.filter((s) => s.total != null);
    const obtained = entered.reduce((sum, s) => sum + (s.total ?? 0), 0);
    const fullTotal = exam.schedules.reduce((sum, s) => sum + s.fullMarks, 0);
    const percent = fullTotal > 0 ? Math.round((obtained / fullTotal) * 1000) / 10 : null;
    const anyFailed = subjects.some((s) => s.failed);
    return {
      id: exam.id,
      name: exam.name,
      nameBn: exam.nameBn,
      className: exam.classItem?.name ?? null,
      classNameBn: exam.classItem?.nameBn ?? null,
      status: exam.status,
      startDate: exam.startDate,
      endDate: exam.endDate,
      resultPublishedAt: exam.resultPublishedAt,
      subjects,
      marksEntered: entered.length,
      totalSubjects: subjects.length,
      obtained,
      fullTotal,
      percent,
      grade: percent != null ? gradeFromPercent(percent).grade : null,
      gpa: percent != null ? gradeFromPercent(percent).point : null,
      result: anyFailed ? "FAILED" : entered.length < subjects.length ? "INCOMPLETE" : "PASSED",
    };
  });

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