/* Supplemental College & University (campus) demo seed — idempotent.
 *
 * Extends the base seed-campus.ts data with the remaining demo scenarios:
 *  - University (CSE): the 2nd-semester final gets marks + published result
 *    (transcripts now show TWO terms → a real cross-term CGPA); a 3rd term
 *    ("2nd Year 1st Semester") with courses/offerings and a QUIZ exam whose
 *    routine is NOT published (papers editable); RETAKE / DROPPED enrollment
 *    statuses on real students.
 *  - College HSC: a RUNNING half-yearly exam with an unpublished, editable
 *    routine; an older 2024-25 cohort demonstrating GRADUATED / DROPPED /
 *    SUSPENDED student statuses and a published board FINAL (GPA-5
 *    transcript for the graduated student).
 *  - College BBA: a mid-term with marks for only 5 of 8 students (result
 *    stays INCOMPLETE until the rest are entered) and unpublished result.
 */
import { PrismaClient } from "@prisma/client";

function iso(d: string): Date {
  return new Date(`${d}T00:00:00Z`);
}

/** deterministic marks: 55–94, student 1 absent in course 2, student 3 fails course 1 */
function marksFor(i: number, j: number, pass: number): { marks: number | null; absent: boolean } {
  if (i === 1 && j === 2) return { marks: null, absent: true };
  if (i === 3 && j === 1) return { marks: Math.max(10, pass - 12), absent: false };
  return { marks: 55 + ((i * 7 + j * 13) % 40), absent: false };
}

export async function seedCampusExtra(prisma: PrismaClient) {
  await extraUniversity(prisma);
  await extraCollege(prisma);
  await seedRoutineSlots(prisma);
}

/* ------------------- weekly course routine slots ------------------- */

async function seedRoutineSlots(prisma: PrismaClient) {
  // every offering gets a unique (day, time-block) pair — no teacher/room/
  // course clashes can exist in the demo routine
  const DAYS5 = ["SAT", "SUN", "MON", "TUE", "WED"];
  const BLOCKS: [string, string][] = [
    ["09:00", "10:30"],
    ["10:45", "12:15"],
    ["14:00", "15:30"],
  ];
  const ROOMS = ["Room 501", "Room 502", "Room 503", "Lab 1", "Lab 2"];

  for (const instCode of ["CL-2002", "UN-3001"]) {
    const inst = await prisma.institution.findUnique({ where: { code: instCode } });
    if (!inst) continue;
    const existing = await prisma.cuCourseSlot.count({ where: { institutionId: inst.id } });
    if (existing > 0) continue;
    const offerings = await prisma.cuOffering.findMany({
      where: { institutionId: inst.id },
      orderBy: { id: "asc" },
      select: { id: true },
    });
    let added = 0;
    for (const [k, off] of offerings.entries()) {
      const day = DAYS5[k % DAYS5.length];
      const [start, end] = BLOCKS[Math.floor(k / DAYS5.length) % BLOCKS.length];
      const room = ROOMS[k % ROOMS.length];
      await prisma.cuCourseSlot.create({
        data: { institutionId: inst.id, offeringId: off.id, dayOfWeek: day, startTime: start, endTime: end, room },
      }).catch(() => null);
      added++;
    }
    if (added > 0) console.log(`  ✔ ${instCode}: +${added} weekly course routine slots`);
  }
}

/* ------------------------- university extras ------------------------- */

async function extraUniversity(prisma: PrismaClient) {
  const inst = await prisma.institution.findUnique({ where: { code: "UN-3001" } });
  if (!inst) return;
  const cse = await prisma.cuProgram.findFirst({ where: { institutionId: inst.id, code: "CSE-HONS" } });
  if (!cse) return;

  const students = await prisma.cuStudent.findMany({
    where: { institutionId: inst.id, programId: cse.id },
    orderBy: { studentIdNo: "asc" },
  });
  if (students.length === 0) return;

  /* --- publish the 2nd-semester final: marks + FINISHED + result published --- */
  const final2 = await prisma.cuExam.findFirst({
    where: { institutionId: inst.id, name: "2nd Semester Final Examination 2025" },
    include: { schedules: true },
  });
  if (final2 && !final2.resultPublished) {
    for (const sched of final2.schedules) {
      const existing = await prisma.cuExamMark.count({ where: { scheduleId: sched.id } });
      if (existing > 0) continue;
      const j = final2.schedules.indexOf(sched);
      for (const [i, st] of students.entries()) {
        const { marks, absent } = marksFor(i, j + 5, 40); // offset so term-2 marks differ
        await prisma.cuExamMark.create({
          data: { institutionId: inst.id, scheduleId: sched.id, studentId: st.id, marks, absent },
        });
      }
    }
    await prisma.cuExam.update({
      where: { id: final2.id },
      data: { status: "FINISHED", resultPublished: true, resultPublishedAt: iso("2025-07-05") },
    });
    console.log("  ✔ University: 2nd semester final finished + published (transcript = 2 terms, cross-term CGPA)");
  }

  /* --- 3rd term with courses + offerings + editable QUIZ exam --- */
  const term3 = await prisma.cuTerm.findFirst({
    where: { institutionId: inst.id, programId: cse.id, sequence: 3 },
  });
  if (!term3) {
    const created = await prisma.cuTerm.create({
      data: {
        institutionId: inst.id, programId: cse.id,
        name: "2nd Year 1st Semester", nameBn: "২য় বর্ষ ১ম সেমিস্টার", sequence: 3,
        startDate: iso("2025-07-10"), endDate: iso("2025-12-20"),
      },
    });
    await createTerm3Data(prisma, inst.id, cse.id, created.id, students.map((s) => s.id));
    console.log("  ✔ University: 3rd term (courses, offerings, QUIZ exam with editable routine, RETAKE/DROPPED enrollments)");
  } else {
    await createTerm3Data(prisma, inst.id, cse.id, term3.id, students.map((s) => s.id));
  }

  /* --- RETAKE: Mehnaz failed CSE-101L in the 1st semester final --- */
  const mehnaz = students.find((s) => s.studentIdNo === "CSE-2024-004");
  if (mehnaz) {
    const labOffering = await prisma.cuOffering.findFirst({
      where: { institutionId: inst.id, sessionYear: "2024-25", course: { code: "CSE-101L" } },
      include: { _count: { select: { enrollments: true } } },
    });
    const enroll = labOffering
      ? await prisma.cuEnrollment.findFirst({
          where: { studentId: mehnaz.id, offeringId: labOffering.id, status: "ENROLLED" },
        })
      : null;
    if (enroll) {
      await prisma.cuEnrollment.update({ where: { id: enroll.id }, data: { status: "RETAKE" } });
      console.log("  ✔ University: CSE-2024-004 → RETAKE status on CSE-101L");
    }
  }
}

async function createTerm3Data(
  prisma: PrismaClient,
  institutionId: number,
  programId: number,
  termId: number,
  studentIds: number[]
) {
  const courses = [
    { code: "CSE-301", name: "Data Structures", nameBn: "ডেটা স্ট্রাকচার", credits: 3, type: "THEORY" },
    { code: "CSE-301L", name: "Data Structures Lab", nameBn: "ডেটা স্ট্রাকচার ল্যাব", credits: 1.5, type: "LAB" },
    { code: "MAT-301", name: "Linear Algebra", nameBn: "রৈখিক বীজগণিত", credits: 3, type: "THEORY" },
  ];
  const teachers = await prisma.staff.findMany({ where: { institutionId }, select: { id: true } });
  const courseIds: number[] = [];
  for (const c of courses) {
    let row = await prisma.cuCourse.findFirst({ where: { institutionId, code: c.code } });
    if (!row) {
      row = await prisma.cuCourse.create({
        data: {
          institutionId, programId, termId, code: c.code, name: c.name, nameBn: c.nameBn,
          credits: c.credits, courseType: c.type, fullMarks: 100, passMarks: 40,
        },
      });
    }
    courseIds.push(row.id);

    let off = await prisma.cuOffering.findFirst({
      where: { institutionId, courseId: row.id, sessionYear: "2024-25" },
    });
    if (!off) {
      off = await prisma.cuOffering.create({
        data: {
          institutionId, courseId: row.id, sessionYear: "2024-25", section: "A",
          staffId: teachers.length ? teachers[courseIds.length % teachers.length].id : null,
          maxSeats: 40,
        },
      });
      // enroll everyone except: Zubair (dropped out of the cohort mid-year)
      const dropped = "CSE-2024-009";
      for (const sid of studentIds) {
        await prisma.cuEnrollment.create({
          data: { institutionId, studentId: sid, offeringId: off.id },
        }).catch(() => null);
      }
      const zubair = await prisma.cuStudent.findFirst({ where: { institutionId, studentIdNo: dropped } });
      if (zubair) {
        await prisma.cuEnrollment.updateMany({
          where: { studentId: zubair.id, offering: { courseId: row.id } },
          data: { status: "DROPPED" },
        });
      }
    }
  }

  // QUIZ exam — upcoming, routine NOT published (papers stay editable)
  let quiz = await prisma.cuExam.findFirst({
    where: { institutionId, name: "2nd Year 1st Semester Quiz 2025" },
  });
  if (!quiz) {
    quiz = await prisma.cuExam.create({
      data: {
        institutionId, programId, termId,
        name: "2nd Year 1st Semester Quiz 2025",
        examType: "QUIZ", sessionYear: "2024-25",
        startDate: iso("2025-09-15"), endDate: iso("2025-09-16"),
        status: "UPCOMING",
      },
    });
    for (const [j, courseId] of courseIds.slice(0, 2).entries()) {
      await prisma.cuExamSchedule.create({
        data: {
          institutionId, examId: quiz.id, courseId,
          examDate: iso(`2025-09-1${5 + j}`), startTime: "10:00", endTime: "10:30",
          room: "Room 601", fullMarks: 20, passMarks: 8,
        },
      });
    }
  }
}

/* --------------------------- college extras --------------------------- */

async function extraCollege(prisma: PrismaClient) {
  const inst = await prisma.institution.findUnique({ where: { code: "CL-2002" } });
  if (!inst) return;

  /* ---- HSC: running half-yearly with an EDITABLE (unpublished) routine ---- */
  const hsc = await prisma.cuProgram.findFirst({ where: { institutionId: inst.id, code: "HSC-SCI" } });
  if (hsc) {
    const term1 = await prisma.cuTerm.findFirst({ where: { programId: hsc.id, sequence: 1 } });
    const hscCourses = await prisma.cuCourse.findMany({
      where: { programId: hsc.id },
      orderBy: { code: "asc" },
    });
    let halfYearly = await prisma.cuExam.findFirst({
      where: { institutionId: inst.id, name: "Half-Yearly Examination 2025" },
    });
    if (!halfYearly && term1 && hscCourses.length > 0) {
      halfYearly = await prisma.cuExam.create({
        data: {
          institutionId: inst.id, programId: hsc.id, termId: term1.id,
          name: "Half-Yearly Examination 2025", nameBn: "অর্ধ-বার্ষিক পরীক্ষা ২০২৫",
          examType: "TEST", sessionYear: "2025-26",
          startDate: iso("2026-03-02"), endDate: iso("2026-03-09"),
          status: "RUNNING",
        },
      });
      for (const [j, c] of hscCourses.slice(0, 3).entries()) {
        await prisma.cuExamSchedule.create({
          data: {
            institutionId: inst.id, examId: halfYearly.id, courseId: c.id,
            examDate: iso(`2026-03-0${2 + j}`), startTime: "10:00", endTime: "12:00",
            room: `Room ${301 + j}`, fullMarks: 50, passMarks: 17,
          },
        });
      }
      console.log("  ✔ College HSC: RUNNING half-yearly exam, routine NOT published (papers editable)");
    }

    /* ---- older 2024-25 HSC cohort: lifecycle statuses + board final ---- */
    const cohort = [
      { no: "HSC-2024-01", name: "Aminul Islam", gender: "MALE", status: "GRADUATED" },
      { no: "HSC-2024-02", name: "Sheikh Farhana", gender: "FEMALE", status: "DROPPED" },
      { no: "HSC-2024-03", name: "Rony Chowdhury", gender: "MALE", status: "SUSPENDED" },
    ];
    const term2 = await prisma.cuTerm.findFirst({ where: { programId: hsc.id, sequence: 2 } });
    for (const [i, c] of cohort.entries()) {
      const existing = await prisma.cuStudent.findFirst({ where: { institutionId: inst.id, studentIdNo: c.no } });
      if (existing) continue;
      const st = await prisma.cuStudent.create({
        data: {
          institutionId: inst.id, studentIdNo: c.no, name: c.name, gender: c.gender,
          guardianName: "Md. Guardian " + c.name.split(" ")[0],
          guardianPhone: "+88018110006" + String(10 + i),
          programId: hsc.id, sessionYear: "2024-25",
          currentTermId: term2?.id ?? null,
          boardRollNo: `DH-2025-${220000 + i}`,
          admissionDate: iso("2024-07-10"),
          status: c.status,
          note: c.status === "SUSPENDED" ? "Disciplinary hold — semester frozen" : null,
        },
      });
      // older-cohort offerings (no teacher → shows "not assigned") + enrollments
      for (const course of hscCourses) {
        let off = await prisma.cuOffering.findFirst({
          where: { institutionId: inst.id, courseId: course.id, sessionYear: "2024-25" },
        });
        if (!off) {
          off = await prisma.cuOffering.create({
            data: { institutionId: inst.id, courseId: course.id, sessionYear: "2024-25", maxSeats: 50 },
          });
        }
        await prisma.cuEnrollment.create({
          data: { institutionId: inst.id, studentId: st.id, offeringId: off.id },
        }).catch(() => null);
      }
    }

    // published board FINAL for the older cohort → GPA-5 transcript for the graduate
    let boardFinal = await prisma.cuExam.findFirst({
      where: { institutionId: inst.id, name: "HSC Board Final Examination 2025" },
    });
    const graduate = await prisma.cuStudent.findFirst({
      where: { institutionId: inst.id, studentIdNo: "HSC-2024-01" },
    });
    if (!boardFinal && term2 && graduate && hscCourses.length > 0) {
      boardFinal = await prisma.cuExam.create({
        data: {
          institutionId: inst.id, programId: hsc.id, termId: term2.id,
          name: "HSC Board Final Examination 2025", nameBn: "এইচএসসি বোর্ড ফাইনাল পরীক্ষা ২০২৫",
          examType: "FINAL", sessionYear: "2024-25",
          startDate: iso("2025-06-01"), endDate: iso("2025-06-20"),
          status: "FINISHED", schedulePublished: true, schedulePublishedAt: iso("2025-05-10"),
          resultPublished: true, resultPublishedAt: iso("2025-08-15"),
        },
      });
      for (const [j, course] of hscCourses.entries()) {
        const sched = await prisma.cuExamSchedule.create({
          data: {
            institutionId: inst.id, examId: boardFinal.id, courseId: course.id,
            examDate: iso(`2025-06-0${(j % 9) + 1}`), startTime: "10:00", endTime: "13:00",
            room: `Room ${301 + (j % 3)}`, fullMarks: 100, passMarks: 33,
          },
        });
        // marks only for the graduate — the other two never sat the boards
        const { marks, absent } = marksFor(0, j + 2, 33);
        await prisma.cuExamMark.create({
          data: { institutionId: inst.id, scheduleId: sched.id, studentId: graduate.id, marks, absent },
        });
      }
      console.log("  ✔ College HSC: 2024-25 cohort (GRADUATED/DROPPED/SUSPENDED) + published board FINAL (GPA-5 transcript)");
    }
  }

  /* ---- BBA: mid-term with PARTIAL marks (INCOMPLETE result demo) ---- */
  const bba = await prisma.cuProgram.findFirst({ where: { institutionId: inst.id, code: "BBA-HONS" } });
  if (bba) {
    const term1 = await prisma.cuTerm.findFirst({ where: { programId: bba.id, sequence: 1 } });
    const bbaCourses = await prisma.cuCourse.findMany({
      where: { programId: bba.id },
      orderBy: { code: "asc" },
    });
    const bbaStudents = await prisma.cuStudent.findMany({
      where: { institutionId: inst.id, programId: bba.id },
      orderBy: { studentIdNo: "asc" },
    });
    let midterm = await prisma.cuExam.findFirst({
      where: { institutionId: inst.id, name: "BBA 1st Semester Mid-Term 2025" },
    });
    if (!midterm && term1 && bbaCourses.length > 0 && bbaStudents.length > 0) {
      midterm = await prisma.cuExam.create({
        data: {
          institutionId: inst.id, programId: bba.id, termId: term1.id,
          name: "BBA 1st Semester Mid-Term 2025",
          examType: "MIDTERM", sessionYear: "2024-25",
          startDate: iso("2025-02-10"), endDate: iso("2025-02-14"),
          status: "FINISHED", schedulePublished: true, schedulePublishedAt: iso("2025-02-01"),
        },
      });
      for (const [j, course] of bbaCourses.slice(0, 3).entries()) {
        const sched = await prisma.cuExamSchedule.create({
          data: {
            institutionId: inst.id, examId: midterm.id, courseId: course.id,
            examDate: iso(`2025-02-1${j}`), startTime: "09:00", endTime: "11:00",
            room: `Room ${401 + (j % 2)}`, fullMarks: 30, passMarks: 12,
          },
        });
        // marks for the FIRST 5 students only — the rest stay pending, so the
        // computed result shows INCOMPLETE until an admin enters them
        for (const [i, st] of bbaStudents.slice(0, 5).entries()) {
          const v = 15 + ((i * 5 + j * 3) % 13); // 15–27 of 30
          await prisma.cuExamMark.create({
            data: { institutionId: inst.id, scheduleId: sched.id, studentId: st.id, marks: v, absent: false },
          });
        }
      }
      console.log("  ✔ College BBA: mid-term with partial marks (result stays INCOMPLETE; result unpublished → marks editable)");
    }
  }
}

// Standalone execution: npx tsx prisma/seed-campus-extra.ts
const invokedDirectly = process.argv[1] ? process.argv[1].split("\\").pop()?.includes("seed-campus-extra") : false;
if (invokedDirectly) {
  const prisma = new PrismaClient();
  seedCampusExtra(prisma)
    .then(() => {
      console.log("🌱 Campus extra seed complete.");
    })
    .catch((e) => {
      console.error(e);
      process.exitCode = 1;
    })
    .finally(() => prisma.$disconnect());
}
