import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireRole } from "@/lib/auth";

type Params = { params: Promise<{ id: string }> };

export async function PATCH(req: Request, { params }: Params) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { id } = await params;
  const exam = await prisma.exam.findFirst({
    where: { id: Number(id), OR: [{ institutionId: session.institutionId }, { branchId: session.institutionId }] },
  });
  if (!exam) return NextResponse.json({ error: "Not found" }, { status: 404 });

  try {
    const body = await req.json();
    const data: {
      name?: string;
      nameBn?: string | null;
      branchId?: number | null;
      classItemId?: number | null;
      sectionItemId?: number | null;
      groupItemId?: number | null;
      departmentItemId?: number | null;
      shiftItemId?: number | null;
      startDate?: Date;
      endDate?: Date | null;
      status?: "UPCOMING" | "RUNNING" | "FINISHED";
      format?: "SINGLE" | "PERIODICAL" | "FINAL";
      schedulePublished?: boolean;
      schedulePublishedAt?: Date | null;
      resultPublished?: boolean;
      resultPublishedAt?: Date | null;
      note?: string | null;
    } = {};

    if (body.name !== undefined) {
      const name = String(body.name).trim();
      if (!name) return NextResponse.json({ error: "Name is required" }, { status: 400 });
      data.name = name;
    }
    if (body.nameBn !== undefined) data.nameBn = String(body.nameBn).trim() || null;
    if (body.format !== undefined && ["SINGLE", "PERIODICAL", "FINAL"].includes(body.format)) {
      data.format = body.format;
    }
    if (body.branchId !== undefined) {
      const n = Number(body.branchId);
      const branchId = Number.isFinite(n) && n > 0 ? n : null;
      // reassignment is only allowed to one of the institution's own branches
      // (keeping the current branch is always allowed)
      if (branchId !== null && branchId !== exam.branchId) {
        const branch = await prisma.institution.findFirst({
          where: { id: branchId, parentId: session.institutionId },
          select: { id: true },
        });
        if (!branch) return NextResponse.json({ error: "Invalid branch" }, { status: 400 });
      }
      data.branchId = branchId;
    }
    if (body.classItemId !== undefined) {
      const n = Number(body.classItemId);
      data.classItemId = Number.isFinite(n) && n > 0 ? n : null;
    }
    if (body.sectionItemId !== undefined) {
      const n = Number(body.sectionItemId);
      data.sectionItemId = Number.isFinite(n) && n > 0 ? n : null;
    }
    if (body.groupItemId !== undefined) {
      const n = Number(body.groupItemId);
      data.groupItemId = Number.isFinite(n) && n > 0 ? n : null;
    }
    if (body.departmentItemId !== undefined) {
      const n = Number(body.departmentItemId);
      data.departmentItemId = Number.isFinite(n) && n > 0 ? n : null;
    }
    if (body.shiftItemId !== undefined) {
      const n = Number(body.shiftItemId);
      data.shiftItemId = Number.isFinite(n) && n > 0 ? n : null;
    }
    if (body.startDate !== undefined && /^\d{4}-\d{2}-\d{2}$/.test(String(body.startDate).slice(0, 10))) {
      data.startDate = new Date(`${String(body.startDate).slice(0, 10)}T00:00:00Z`);
    }
    if (body.endDate !== undefined) {
      const endStr = String(body.endDate).slice(0, 10);
      data.endDate = endStr && /^\d{4}-\d{2}-\d{2}$/.test(endStr) ? new Date(`${endStr}T00:00:00Z`) : null;
    }
    if (body.status !== undefined && ["UPCOMING", "RUNNING", "FINISHED"].includes(String(body.status))) {
      data.status = body.status as never;
    }
    // publish the routine (locks papers) or allow edit again (unpublish)
    if (body.schedulePublished !== undefined) {
      const publish = !!body.schedulePublished;
      data.schedulePublished = publish;
      data.schedulePublishedAt = publish ? new Date() : null;
    }
    // publish the result (locks marks input) or unlock it again.
    // Publishing also finishes the exam — a published result must never sit
    // on a RUNNING exam (students would see a "running" result sheet).
    if (body.resultPublished !== undefined) {
      const publish = !!body.resultPublished;
      data.resultPublished = publish;
      data.resultPublishedAt = publish ? new Date() : null;
      if (publish) data.status = "FINISHED";
    }
    if (body.note !== undefined) data.note = String(body.note).trim() || null;

    const updated = await prisma.exam.update({ where: { id: exam.id }, data });
    return NextResponse.json({ exam: updated });
  } catch {
    return NextResponse.json({ error: "Could not update exam" }, { status: 500 });
  }
}

export async function DELETE(_req: Request, { params }: Params) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const { id } = await params;
  const exam = await prisma.exam.findFirst({
    where: { id: Number(id), OR: [{ institutionId: session.institutionId }, { branchId: session.institutionId }] },
  });
  if (!exam) return NextResponse.json({ error: "Not found" }, { status: 404 });

  try {
    await prisma.exam.delete({ where: { id: exam.id } }); // papers cascade
    return NextResponse.json({ ok: true });
  } catch {
    return NextResponse.json({ error: "Could not delete exam" }, { status: 500 });
  }
}
