/* Supplemental seeder for the Final Result (3 Sets) module:
 *  six exams for the primary demo institution (code PS-1004) —
 *  1st/2nd/3rd Tutorial + 1st/2nd/3rd Semester — each with 4 subject papers,
 *  entered marks for the 5 demo students, and attendance rows inside every
 *  exam window so the per-set attendance summary has data.
 *
 * Idempotent — skips when the first exam already exists. Runs standalone
 * (`npx tsx prisma/seed-final-exams.ts`) and is also called by the main seed.
 */
import { PrismaClient } from "@prisma/client";

type Prisma = PrismaClient;

const EXAM_DEFS: { name: string; nameBn: string; start: string; kind: "tut" | "sem" }[] = [
  { name: "1st Tutorial 2026", nameBn: "১ম টিউটোরিয়াল ২০২৬", start: "2026-02-08", kind: "tut" },
  { name: "1st Semester 2026", nameBn: "১ম সেমিস্টার ২০২৬", start: "2026-03-15", kind: "sem" },
  { name: "2nd Tutorial 2026", nameBn: "২য় টিউটোরিয়াল ২০২৬", start: "2026-05-10", kind: "tut" },
  { name: "2nd Semester 2026", nameBn: "২য় সেমিস্টার ২০২৬", start: "2026-06-14", kind: "sem" },
  { name: "3rd Tutorial 2026", nameBn: "৩য় টিউটোরিয়াল ২০২৬", start: "2026-08-16", kind: "tut" },
  { name: "3rd Semester 2026", nameBn: "৩য় সেমিস্টার ২০২৬", start: "2026-09-13", kind: "sem" },
];

export async function seedFinalExams(prisma: Prisma) {
  const inst = await prisma.institution.findUnique({ where: { code: "PS-1004" } });
  if (!inst) return; // primary demo institution not present

  const existing = await prisma.exam.findFirst({
    where: { institutionId: inst.id, name: EXAM_DEFS[0].name },
    select: { id: true },
  });
  if (existing) return; // already seeded

  const [classItem, subjects, students] = await Promise.all([
    prisma.academicItem.findFirst({ where: { category: "CLASS", name: "Class 3" }, select: { id: true } }),
    prisma.academicItem.findMany({
      where: { category: "SUBJECT", name: { in: ["Bangla", "English", "Mathematics", "Science"] } },
      select: { id: true, name: true },
    }),
    prisma.student.findMany({
      where: { institutionId: inst.id, status: "ACTIVE" },
      orderBy: { roll: "asc" },
      select: { id: true, roll: true },
    }),
  ]);
  if (!classItem || subjects.length === 0 || students.length === 0) return;

  const subjectOrder = ["Bangla", "English", "Mathematics", "Science"];
  const subjectsSorted = subjectOrder
    .map((n) => subjects.find((s) => s.name === n))
    .filter((s): s is { id: number; name: string } => !!s);

  // deterministic score bands per student (index by student ordinal) so the
  // weighted final spreads the class: strong → weak, weakest fails at 33%
  const tutBase = [22, 18, 14, 10, 6];
  const semBase = [66, 55, 44, 33, 20];

  for (const [ei, def] of EXAM_DEFS.entries()) {
    const full = def.kind === "tut" ? 25 : 75;
    const pass = def.kind === "tut" ? 8 : 25;
    const base = def.kind === "tut" ? tutBase : semBase;
    const exam = await prisma.exam.create({
      data: {
        institutionId: inst.id,
        name: def.name,
        nameBn: def.nameBn,
        classItemId: classItem.id,
        startDate: new Date(def.start),
        endDate: new Date(def.start),
        status: "FINISHED",
        format: "PERIODICAL",
        schedulePublished: true,
        resultPublished: true,
      },
    });
    for (const [si, subj] of subjectsSorted.entries()) {
      const schedule = await prisma.examSchedule.create({
        data: {
          institutionId: inst.id,
          examId: exam.id,
          subjectItemId: subj.id,
          date: new Date(def.start),
          startTime: "10:00",
          endTime: def.kind === "tut" ? "11:00" : "13:00",
          fullMarks: full,
          totalPassMarks: pass,
        },
      });
      for (const [stu, student] of students.entries()) {
        // small per-subject / per-exam wobble around the student's band
        const score = Math.max(
          0,
          Math.min(full, base[stu % base.length] + ((si * 2 + ei) % 5) - 2)
        );
        await prisma.examMark.create({
          data: {
            institutionId: inst.id,
            examScheduleId: schedule.id,
            studentId: student.id,
            total: score,
          },
        });
      }
    }

    // attendance inside each exam window (start-3 … start) for the per-set summary
    for (let d = 3; d >= 0; d--) {
      const day = new Date(def.start);
      day.setUTCDate(day.getUTCDate() - d);
      if (day.getUTCDay() === 5) continue; // Friday off
      for (const [stu, student] of students.entries()) {
        const absent = d === 1 && stu === 4; // weakest student misses one day per window
        await prisma.studentAttendance.create({
          data: {
            institutionId: inst.id,
            studentId: student.id,
            date: day,
            status: absent ? "ABSENT" : "PRESENT",
          },
        });
      }
    }
  }
}

// Standalone execution: npx tsx prisma/seed-final-exams.ts
if (process.argv[1] && process.argv[1].replace(/\\/g, "/").includes("seed-final-exams")) {
  const prisma = new PrismaClient();
  seedFinalExams(prisma)
    .then(() => console.log("🌱 Final Result exams seeded (6 exams + marks + attendance)."))
    .catch((e) => {
      console.error(e);
      process.exitCode = 1;
    })
    .finally(() => prisma.$disconnect());
}
