/* Supplemental seeder for the central monitoring feature:
 *  1. assigns district / sub-district to the core demo institutions,
 *  2. creates satellite demo institutions across districts with light
 *     operational data (students, teachers, attendance, an exam with marks,
 *     fee collections, notice, event, complaint).
 *
 * Idempotent — safe to run against an existing database (skips what exists).
 * Runs standalone (`npx tsx prisma/seed-monitoring.ts`) and is also called
 * by the main seed.
 */
import { PrismaClient } from "@prisma/client";
import bcrypt from "bcryptjs";

type Prisma = PrismaClient;

const CORE_DISTRICTS: Record<string, { district: string; subDistrict: string }> = {
  "HS-1001": { district: "Dhaka", subDistrict: "Dhaka Metropolitan" },
  "KG-1002": { district: "Dhaka", subDistrict: "Dhaka Metropolitan" },
  "CO-1003": { district: "Chattogram", subDistrict: "Chattogram Sadar" },
  "PS-1004": { district: "Dhaka", subDistrict: "Dhaka Metropolitan" },
};

const firstNames = ["Arif", "Sumaiya", "Tanvir", "Nabila", "Rakib", "Mim", "Sajid", "Rupa", "Naeem", "Tisha"];
const lastNames = ["Hossain", "Akter", "Chowdhury", "Islam", "Rahman", "Sultana", "Khan", "Begum"];

const bd = (n: number) => {
  const d = new Date();
  d.setDate(d.getDate() - n);
  return new Date(d.toISOString().slice(0, 10));
};

export async function seedMonitoring(prisma: Prisma) {
  // ---- 1. districts for the core demo institutions (only when unset) ----
  for (const [code, loc] of Object.entries(CORE_DISTRICTS)) {
    await prisma.institution.updateMany({
      where: { code, district: null },
      data: loc,
    });
  }

  // ---- 2. satellite institutions across districts ----
  const passwordHash = await bcrypt.hash("Demo@123", 10);
  const subjectByName = new Map(
    (await prisma.academicItem.findMany({ where: { category: "SUBJECT" }, select: { name: true, id: true } })).map((s) => [s.name, s.id] as const)
  );

  const satelliteSeed: {
    name: string; code: string; type: string; email: string; district: string; subDistrict: string;
    status: string; active: boolean; students: number; feeTotal: number;
  }[] = [
    { name: "Gazipur Model High School", code: "HS-2001", type: "HIGH_SCHOOL", email: "gazipur@demo.com", district: "Gazipur", subDistrict: "Gazipur Sadar", status: "ACTIVE", active: true, students: 9, feeTotal: 52000 },
    { name: "Padma Primary School", code: "PR-2002", type: "PRIMARY", email: "padma@demo.com", district: "Rajshahi", subDistrict: "Puthia", status: "ACTIVE", active: true, students: 7, feeTotal: 28000 },
    { name: "Sylhet Grammar College", code: "CO-2003", type: "COLLEGE", email: "sylhet@demo.com", district: "Sylhet", subDistrict: "Sylhet Sadar", status: "ACTIVE", active: true, students: 8, feeTotal: 64000 },
    { name: "Khulna Public High School", code: "HS-2004", type: "HIGH_SCHOOL", email: "khulna@demo.com", district: "Khulna", subDistrict: "Khulna Sadar", status: "ACTIVE", active: true, students: 8, feeTotal: 41000 },
    { name: "Cumilla Zilla School", code: "HS-2006", type: "HIGH_SCHOOL", email: "cumilla@demo.com", district: "Cumilla", subDistrict: "Cumilla Adarsha Sadar", status: "ACTIVE", active: true, students: 8, feeTotal: 47000 },
    { name: "Barishal Sun College", code: "CO-2005", type: "COLLEGE", email: "barishal@demo.com", district: "Barishal", subDistrict: "Barishal Sadar", status: "PENDING", active: false, students: 5, feeTotal: 0 },
  ];

  let satInvoice = 0;
  const existing = await prisma.institution.findMany({ where: { code: { in: satelliteSeed.map((s) => s.code) } }, select: { code: true } });
  const existingCodes = new Set(existing.map((e) => e.code));
  satInvoice = await prisma.feeCollection.count({ where: { invoiceNo: { startsWith: "MTR-" } } });

  let satRoll = (await prisma.institution.count() + 1) * 1000 + 2000;

  for (const [si, sat] of satelliteSeed.entries()) {
    if (existingCodes.has(sat.code)) continue;

    const inst = await prisma.institution.create({
      data: {
        name: sat.name,
        code: sat.code,
        type: sat.type as never,
        email: sat.email,
        phone: `+880 17${String(11000000 + si * 111111)}`,
        address: `${sat.subDistrict}, ${sat.district}`,
        district: sat.district,
        subDistrict: sat.subDistrict,
        status: sat.status as never,
        createdAt: new Date(2026, si % 6, 5 + si),
        users: {
          create: {
            name: `${sat.name.split(" ")[0]} Admin`,
            email: sat.email,
            passwordHash,
            role: "INSTITUTION_ADMIN",
          },
        },
      },
    });

    // students
    const satStudents: number[] = [];
    for (let i = 0; i < sat.students; i++) {
      satRoll += 1;
      const st = await prisma.student.create({
        data: {
          institutionId: inst.id,
          roll: String(satRoll),
          name: `${firstNames[(si + i) % firstNames.length]} ${lastNames[(si * 3 + i) % lastNames.length]}`,
          gender: i % 2 === 0 ? "MALE" : "FEMALE",
          dob: new Date(2010, (i * 3) % 12, 8 + i),
          guardianName: `Guardian of ${satRoll}`,
          guardianPhone: `+880 18${String(10000000 + satRoll)}`,
          address: `${sat.subDistrict}, ${sat.district}`,
          createdAt: new Date(2026, 0, 20 + (i % 8)),
        },
      });
      satStudents.push(st.id);
    }

    // staff — 3 teachers + 1 librarian (teachers feed the teacher-attendance stats)
    const teacherStaff: number[] = [];
    for (const [ti, code] of ["EMP-T1", "EMP-T2", "EMP-T3", "EMP-L1"].entries()) {
      const st = await prisma.staff.create({
        data: {
          institutionId: inst.id,
          employeeCode: code,
          name: `${firstNames[(si * 2 + ti + 3) % firstNames.length]} ${lastNames[(si + ti + 2) % lastNames.length]}`,
          gender: ti % 2 === 0 ? "MALE" : "FEMALE",
          phone: `+880 19${String(20000000 + si * 10000 + ti)}`,
          designation: ti === 3 ? "LIBRARIAN" : ti === 0 ? "HEAD_TEACHER" : "TEACHER",
          department: ti === 3 ? "LIBRARY" : "ACADEMIC",
          joinDate: new Date(2020, (si + ti) % 12, 1),
          monthlySalary: 22000 + ti * 2000,
          status: "ACTIVE",
        },
      });
      if (ti < 3) teacherStaff.push(st.id);
    }

    if (!sat.active) continue; // PENDING institution — no operations yet

    // daily attendance for the last 28 days (deterministic, Fridays off)
    for (let di = 27; di >= 0; di--) {
      const date = bd(di);
      if (date.getUTCDay() === 5) continue;
      for (const [stu, studentId] of satStudents.entries()) {
        const marker = (stu * 7 + di * 3 + si) % 20;
        const status = marker === 0 ? "ABSENT" : marker === 11 ? "LEAVE" : "PRESENT";
        await prisma.studentAttendance.create({
          data: { institutionId: inst.id, studentId, date, status: status as never },
        });
      }
      for (const [te, staffId] of teacherStaff.entries()) {
        const marker = (te * 5 + di * 2 + si) % 17;
        const status = marker === 0 ? "LEAVE" : marker === 9 ? "ABSENT" : "PRESENT";
        await prisma.staffAttendance.create({
          data: { institutionId: inst.id, staffId, date, status: status as never },
        });
      }
    }

    // one finished exam with 3 papers + entered marks
    const exam = await prisma.exam.create({
      data: {
        institutionId: inst.id,
        name: "Half-Yearly Examination 2026",
        startDate: bd(20),
        endDate: bd(16),
        status: "FINISHED",
        resultPublished: si % 2 === 0,
        schedulePublished: true,
      },
    });
    for (const [pi, paper] of ["Bangla", "English", "Mathematics"].entries()) {
      const schedule = await prisma.examSchedule.create({
        data: {
          institutionId: inst.id,
          examId: exam.id,
          subjectItemId: subjectByName.get(paper) ?? null,
          date: bd(20 - pi * 2),
          startTime: "10:00",
          endTime: "13:00",
          fullMarks: 100,
          totalPassMarks: 33,
        },
      });
      for (const [stu, studentId] of satStudents.entries()) {
        const total = 40 + ((stu * 13 + pi * 17 + si * 7) % 55);
        const mcq = Math.min(30, Math.round(total * 0.3));
        await prisma.examMark.create({
          data: {
            institutionId: inst.id,
            examScheduleId: schedule.id,
            studentId,
            cq: total - mcq,
            mcq,
            total,
          },
        });
      }
    }

    // fee collections spread over the last 3 months
    let remaining = sat.feeTotal;
    const methods = ["BKASH", "NAGAD", "CASH", "ROCKET"];
    for (let mi = 0; mi < 4 && remaining > 0; mi++) {
      const amount = mi === 3 ? remaining : Math.round(remaining / (4 - mi));
      remaining -= amount;
      satInvoice += 1;
      await prisma.feeCollection.create({
        data: {
          invoiceNo: `MTR-${String(satInvoice).padStart(6, "0")}`,
          institutionId: inst.id,
          studentId: satStudents[mi % satStudents.length],
          amount,
          method: methods[mi % methods.length] as never,
          paidAt: new Date(bd(80 - mi * 22).getTime() + 10 * 3600 * 1000),
        },
      });
    }

    // notice + upcoming event + complaint
    await prisma.notice.create({
      data: {
        institutionId: inst.id,
        title: "Guardians' meeting — monthly progress",
        body: "All guardians are requested to attend the monthly progress meeting on the school premises.",
        audience: "ALL",
        publishDate: bd(si + 1),
        isPinned: si === 0,
        isActive: true,
      },
    });
    await prisma.eventItem.create({
      data: {
        institutionId: inst.id,
        title: "Annual Science Fair 2026",
        description: "Students present their science projects; guardians are welcome.",
        venue: "Main Auditorium",
        category: "ACADEMIC",
        startDate: new Date(new Date().getTime() + (si + 2) * 86400000),
        isActive: true,
      },
    });
    await prisma.complaint.create({
      data: {
        institutionId: inst.id,
        complainantType: "PARENT",
        complainantName: "Guardian",
        category: si % 2 === 0 ? "TRANSPORT" : "GENERAL",
        subject: si % 2 === 0 ? "Bus arrives late in the morning" : "Request for more ICT classes",
        description: "Requesting the authority to look into this matter at the earliest.",
        status: (["PENDING", "IN_REVIEW", "RESOLVED", "REJECTED"] as const)[si % 4],
        createdAt: new Date(new Date().getTime() - (si + 1) * 2 * 86400000),
      },
    });
  }
}

// Standalone execution: npx tsx prisma/seed-monitoring.ts
if (process.argv[1] && process.argv[1].replace(/\\/g, "/").includes("seed-monitoring")) {
  const prisma = new PrismaClient();
  seedMonitoring(prisma)
    .then(() => {
      console.log("🌱 Monitoring seed complete (districts + satellite institutions).");
    })
    .catch((e) => {
      console.error(e);
      process.exitCode = 1;
    })
    .finally(() => prisma.$disconnect());
}
