import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireAnyRole, STAFF_SIDE_ROLES } from "@/lib/auth";

interface WeekInput {
  id?: number;
  weekNo?: number;
  topic?: string;
  homework?: string | null;
  isDone?: boolean;
}

function deriveStatus(completed: number, total: number): string {
  if (total > 0 && completed >= total) return "COMPLETED";
  if (completed > 0) return "IN_PROGRESS";
  return "PLANNED";
}

/** The caller's own lesson plans — full self-service: teachers build and
    maintain the plans assigned to them (staffId = self), with the same
    fields and weekly breakdown the admin form offers. The response also
    carries the (class, section, subject) pairs from their teaching schedule
    so the form can offer their own classes/subjects. */

/** names via the per-institution selections, falling back to the global
    academic item when a schedule references an item outside the selection set */
async function resolveItemNames(institutionId: number, ids: (number | null)[]) {
  const wanted = [...new Set(ids.filter((x): x is number => x != null))];
  const map = new Map<number, { name: string; nameBn: string | null }>();
  if (wanted.length === 0) return map;
  const selections = await prisma.academicSelection.findMany({
    where: { institutionId, academicItemId: { in: wanted } },
    select: { academicItem: { select: { id: true, name: true, nameBn: true } } },
  });
  for (const s of selections) {
    map.set(s.academicItem.id, { name: s.academicItem.name, nameBn: s.academicItem.nameBn });
  }
  const missing = wanted.filter((id) => !map.has(id));
  if (missing.length > 0) {
    const items = await prisma.academicItem.findMany({
      where: { id: { in: missing } },
      select: { id: true, name: true, nameBn: true },
    });
    for (const item of items) {
      map.set(item.id, { name: item.name, nameBn: item.nameBn });
    }
  }
  return map;
}

export async function GET() {
  const session = await requireAnyRole([...STAFF_SIDE_ROLES]);
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const me = await prisma.user.findUnique({
    where: { id: session.userId },
    select: { staffId: true },
  });
  if (!me?.staffId) {
    return NextResponse.json({ plans: [], schedule: [] });
  }

  const [plans, schedule] = await Promise.all([
    prisma.lessonPlan.findMany({
      where: { staffId: me.staffId },
      orderBy: [{ startDate: "desc" }, { id: "desc" }],
      include: {
        classItem: { select: { name: true, nameBn: true } },
        sectionItem: { select: { name: true, nameBn: true } },
        subjectItem: { select: { name: true, nameBn: true } },
        weeks: { orderBy: { weekNo: "asc" } },
      },
    }),
    prisma.classSchedule.findMany({
      where: { institutionId: session.institutionId, staffId: me.staffId, isActive: true },
      select: { classItemId: true, sectionItemId: true, subjectItemId: true },
    }),
  ]);

  const names = await resolveItemNames(
    session.institutionId,
    schedule.flatMap((r) => [r.classItemId, r.sectionItemId, r.subjectItemId])
  );

  // distinct (class, section, subject) pairs the teacher actually teaches
  const seen = new Set<string>();
  const mine: {
    classItemId: number | null;
    sectionItemId: number | null;
    subjectItemId: number | null;
    className: string | null;
    sectionName: string | null;
    subjectName: string | null;
  }[] = [];
  for (const row of schedule) {
    const key = `${row.classItemId}:${row.sectionItemId}:${row.subjectItemId}`;
    if (seen.has(key)) continue;
    seen.add(key);
    mine.push({
      classItemId: row.classItemId,
      sectionItemId: row.sectionItemId,
      subjectItemId: row.subjectItemId,
      className: row.classItemId ? names.get(row.classItemId)?.name ?? null : null,
      sectionName: row.sectionItemId ? names.get(row.sectionItemId)?.name ?? null : null,
      subjectName: row.subjectItemId ? names.get(row.subjectItemId)?.name ?? null : null,
    });
  }

  return NextResponse.json({
    plans: plans.map((p) => ({
      id: p.id,
      staffId: p.staffId,
      classItemId: p.classItemId,
      className: p.classItem?.name ?? null,
      classNameBn: p.classItem?.nameBn ?? null,
      sectionItemId: p.sectionItemId,
      sectionName: p.sectionItem?.name ?? null,
      subjectItemId: p.subjectItemId,
      subjectName: p.subjectItem?.name ?? null,
      subjectNameBn: p.subjectItem?.nameBn ?? null,
      chapter: p.chapter,
      topics: p.topics,
      startDate: p.startDate.toISOString().slice(0, 10),
      endDate: p.endDate ? p.endDate.toISOString().slice(0, 10) : null,
      totalPeriods: p.totalPeriods,
      completedPeriods: p.completedPeriods,
      status: p.status,
      weeks: p.weeks.map((w) => ({
        id: w.id,
        weekNo: w.weekNo,
        topic: w.topic,
        homework: w.homework,
        isDone: w.isDone,
      })),
    })),
    schedule: mine,
  });
}

/** Create a lesson plan assigned to the caller (staffId = self). */
export async function POST(req: Request) {
  const session = await requireAnyRole([...STAFF_SIDE_ROLES]);
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const me = await prisma.user.findUnique({
    where: { id: session.userId },
    select: { staffId: true },
  });
  if (!me?.staffId) return NextResponse.json({ error: "FORBIDDEN" }, { status: 403 });

  try {
    const body = await req.json();
    const chapter = String(body.chapter ?? "").trim();
    const startDate = String(body.startDate ?? "");
    if (!chapter || !/^\d{4}-\d{2}-\d{2}$/.test(startDate)) {
      return NextResponse.json({ error: "Missing fields" }, { status: 400 });
    }
    const totalPeriods = Math.max(0, Number(body.totalPeriods) || 0);
    const completedPeriods = Math.max(0, Number(body.completedPeriods) || 0);
    const weeks: WeekInput[] = Array.isArray(body.weeks) ? body.weeks : [];

    const plan = await prisma.lessonPlan.create({
      data: {
        institutionId: session.institutionId,
        staffId: me.staffId,
        classItemId: body.classItemId ? Number(body.classItemId) : null,
        sectionItemId: body.sectionItemId ? Number(body.sectionItemId) : null,
        subjectItemId: body.subjectItemId ? Number(body.subjectItemId) : null,
        chapter,
        topics: String(body.topics ?? "").trim() || null,
        startDate: new Date(startDate),
        endDate: body.endDate ? new Date(String(body.endDate)) : null,
        totalPeriods,
        completedPeriods,
        status: deriveStatus(completedPeriods, totalPeriods),
        weeks: {
          create: weeks
            .filter((w) => String(w.topic ?? "").trim())
            .map((w, i) => ({
              institutionId: session.institutionId!,
              weekNo: Number(w.weekNo) || i + 1,
              topic: String(w.topic).trim(),
              homework: String(w.homework ?? "").trim() || null,
              isDone: !!w.isDone,
            })),
        },
      },
    });
    return NextResponse.json({ plan });
  } catch {
    return NextResponse.json({ error: "Could not create lesson plan" }, { status: 500 });
  }
}
