import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireAnyRole, MEMBER_ROLES } from "@/lib/auth";
import { getMemberStudentId } from "@/lib/member";

/** Attendance history of the caller's own (child's) student record —
    or, for teacher/staff logins, of their own staff attendance.
    ?month=YYYY-MM (default: current month) → summary + records + subject-wise.
    ?year=YYYY → per-month breakdown + whole-year summary. */

const rateOf = (present: number, marked: number) =>
  marked > 0 ? Math.round((present / marked) * 1000) / 10 : null;

function countRows(rows: { status: string }[]) {
  const counts = { PRESENT: 0, ABSENT: 0, LEAVE: 0 } as Record<string, number>;
  for (const r of rows) counts[r.status] = (counts[r.status] ?? 0) + 1;
  return counts;
}

export async function GET(req: Request) {
  const session = await requireAnyRole(MEMBER_ROLES);
  if (!session) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const url = new URL(req.url);
  const now = new Date();
  const yearParam = url.searchParams.get("year");

  // ---------- yearly report mode ----------
  if (/^\d{4}$/.test(yearParam ?? "")) {
    const year = Number(yearParam);
    const from = new Date(year, 0, 1);
    const to = new Date(year + 1, 0, 1);

    if (session.role === "STUDENT" || session.role === "PARENT") {
      const studentId = await getMemberStudentId(session.userId);
      if (!studentId) {
        return NextResponse.json({ error: "NO_LINKED_STUDENT" }, { status: 409 });
      }
      const [records, student] = await Promise.all([
        prisma.studentAttendance.findMany({
          where: { studentId, date: { gte: from, lt: to } },
          select: { date: true, status: true },
        }),
        prisma.student.findUnique({
          where: { id: studentId },
          select: { name: true, roll: true, classItem: { select: { name: true, nameBn: true } } },
        }),
      ]);
      const monthly = buildMonthly(records, year);
      return NextResponse.json({
        kind: "YEAR",
        year,
        studentName: student?.name ?? null,
        roll: student?.roll ?? null,
        className: student?.classItem?.name ?? null,
        classNameBn: student?.classItem?.nameBn ?? null,
        summary: yearSummary(monthly),
        months: monthly,
      });
    }

    // teacher / staff — own staff attendance
    const me = await prisma.user.findUnique({
      where: { id: session.userId },
      select: { staffId: true, staff: { select: { name: true, employeeCode: true } } },
    });
    const records = me?.staffId
      ? await prisma.staffAttendance.findMany({
          where: { staffId: me.staffId, date: { gte: from, lt: to } },
          select: { date: true, status: true },
        })
      : [];
    const monthly = buildMonthly(records, year);
    return NextResponse.json({
      kind: "YEAR",
      year,
      studentName: me?.staff?.name ?? null,
      roll: me?.staff?.employeeCode ?? null,
      className: null,
      classNameBn: null,
      summary: yearSummary(monthly),
      months: monthly,
    });
  }

  // ---------- monthly dashboard mode ----------
  const month = /^\d{4}-\d{2}$/.test(url.searchParams.get("month") ?? "")
    ? url.searchParams.get("month")!
    : `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}`;
  const from = new Date(`${month}-01T00:00:00`);
  const to = new Date(from);
  to.setMonth(to.getMonth() + 1);

  if (session.role === "STUDENT" || session.role === "PARENT") {
    const studentId = await getMemberStudentId(session.userId);
    if (!studentId) {
      return NextResponse.json({ error: "NO_LINKED_STUDENT" }, { status: 409 });
    }

    const [records, student] = await Promise.all([
      prisma.studentAttendance.findMany({
        where: { studentId, date: { gte: from, lt: to } },
        orderBy: [{ date: "asc" }, { subjectItemId: "asc" }],
        select: {
          id: true,
          date: true,
          status: true,
          note: true,
          inTime: true,
          outTime: true,
          source: true,
          subjectItem: { select: { name: true, nameBn: true } },
        },
      }),
      prisma.student.findUnique({
        where: { id: studentId },
        select: { name: true, roll: true, classItem: { select: { name: true, nameBn: true } } },
      }),
    ]);

    const counts = countRows(records);
    const marked = records.length;

    // subject-wise rollup (per-subject rows only; the daily record has no subject)
    const bySubject = new Map<string, { subject: string | null; subjectBn: string | null; counts: Record<string, number> }>();
    for (const r of records) {
      if (!r.subjectItem) continue;
      const key = String(r.subjectItem.name ?? r.subjectItem.nameBn ?? "?");
      const entry = bySubject.get(key) ?? { subject: r.subjectItem.name, subjectBn: r.subjectItem.nameBn, counts: { PRESENT: 0, ABSENT: 0, LEAVE: 0 } };
      entry.counts[r.status] = (entry.counts[r.status] ?? 0) + 1;
      bySubject.set(key, entry);
    }
    const subjectWise = [...bySubject.values()]
      .map((s) => {
        const total = s.counts.PRESENT + s.counts.ABSENT + s.counts.LEAVE;
        return {
          subject: s.subject,
          subjectBn: s.subjectBn,
          present: s.counts.PRESENT,
          absent: s.counts.ABSENT,
          leave: s.counts.LEAVE,
          marked: total,
          rate: rateOf(s.counts.PRESENT, total),
        };
      })
      .sort((a, b) => (a.subject ?? "").localeCompare(b.subject ?? ""));

    return NextResponse.json({
      month,
      kind: "STUDENT",
      studentName: student?.name ?? null,
      roll: student?.roll ?? null,
      className: student?.classItem?.name ?? null,
      classNameBn: student?.classItem?.nameBn ?? null,
      summary: {
        marked,
        present: counts.PRESENT,
        absent: counts.ABSENT,
        leave: counts.LEAVE,
        rate: rateOf(counts.PRESENT, marked),
      },
      subjectWise,
      records: records.map((r) => ({
        id: r.id,
        date: r.date,
        status: r.status,
        note: r.note,
        inTime: r.inTime?.toISOString() ?? null,
        outTime: r.outTime?.toISOString() ?? null,
        source: r.source ?? null,
        subject: r.subjectItem?.name ?? null,
        subjectBn: r.subjectItem?.nameBn ?? null,
      })),
    });
  }

  // teacher / staff — own staff attendance (one record per day)
  const me = await prisma.user.findUnique({
    where: { id: session.userId },
    select: { staffId: true, staff: { select: { name: true, employeeCode: true } } },
  });
  if (!me?.staffId) {
    return NextResponse.json({
      month,
      kind: "STAFF",
      studentName: me?.staff?.name ?? null,
      roll: me?.staff?.employeeCode ?? null,
      className: null,
      classNameBn: null,
      summary: { marked: 0, present: 0, absent: 0, leave: 0, rate: null },
      subjectWise: [],
      records: [],
    });
  }

  const records = await prisma.staffAttendance.findMany({
    where: { staffId: me.staffId, date: { gte: from, lt: to } },
    orderBy: { date: "asc" },
    select: { id: true, date: true, status: true, note: true, inTime: true, outTime: true, source: true },
  });

  const counts = countRows(records);
  const marked = records.length;

  return NextResponse.json({
    month,
    kind: "STAFF",
    studentName: me.staff?.name ?? null,
    roll: me.staff?.employeeCode ?? null,
    className: null,
    classNameBn: null,
    summary: {
      marked,
      present: counts.PRESENT,
      absent: counts.ABSENT,
      leave: counts.LEAVE,
      rate: rateOf(counts.PRESENT, marked),
    },
    subjectWise: [],
    records: records.map((r) => ({
      id: r.id,
      date: r.date,
      status: r.status,
      note: r.note,
      inTime: r.inTime?.toISOString() ?? null,
      outTime: r.outTime?.toISOString() ?? null,
      source: r.source ?? null,
      subject: null,
      subjectBn: null,
    })),
  });
}

/** per-month rolls for a calendar year */
function buildMonthly(rows: { date: Date; status: string }[], year: number) {
  const months: { month: string; present: number; absent: number; leave: number; marked: number; rate: number | null }[] = [];
  for (let m = 0; m < 12; m++) {
    const month = `${year}-${String(m + 1).padStart(2, "0")}`;
    months.push({ month, present: 0, absent: 0, leave: 0, marked: 0, rate: null });
  }
  for (const r of rows) {
    const idx = r.date.getUTCMonth();
    const entry = months[idx];
    if (r.status === "PRESENT") entry.present++;
    else if (r.status === "ABSENT") entry.absent++;
    else if (r.status === "LEAVE") entry.leave++;
    entry.marked++;
  }
  for (const entry of months) entry.rate = rateOf(entry.present, entry.marked);
  return months;
}

function yearSummary(monthly: { present: number; absent: number; leave: number; marked: number }[]) {
  const present = monthly.reduce((s, m) => s + m.present, 0);
  const absent = monthly.reduce((s, m) => s + m.absent, 0);
  const leave = monthly.reduce((s, m) => s + m.leave, 0);
  const marked = monthly.reduce((s, m) => s + m.marked, 0);
  return { marked, present, absent, leave, rate: rateOf(present, marked) };
}
