import { renderToBuffer } from "@react-pdf/renderer";
import { createElement } from "react";
import { NextResponse } from "next/server";
import { buildSplitAllocationReadModel } from "@capakraken/application";
import { anonymizeResource, getAnonymizationDirectory } from "@capakraken/api";
import { prisma } from "@capakraken/db";
import type { AllocationLike } from "@capakraken/shared";
import { auth } from "~/server/auth.js";
import { AllocationReport } from "~/components/reports/AllocationReport.js";
import { createWorkbookArrayBuffer } from "~/lib/workbook-export.js";

const ALLOWED_ROLES = new Set(["ADMIN", "MANAGER", "CONTROLLER"]);

export async function GET(request: Request) {
  const session = await auth();
  if (!session?.user) {
    return new NextResponse("Unauthorized", { status: 401 });
  }

  const userRole = (session.user as { role?: string }).role;
  if (!userRole || !ALLOWED_ROLES.has(userRole)) {
    return new NextResponse("Forbidden", { status: 403 });
  }

  const { searchParams } = new URL(request.url);
  const startDate = searchParams.get("startDate") ? new Date(searchParams.get("startDate")!) : new Date();
  const endDate = searchParams.get("endDate") ? new Date(searchParams.get("endDate")!) : new Date(Date.now() + 90 * 24 * 60 * 60 * 1000);
  const format = searchParams.get("format") ?? "pdf";

  const [demandRequirements, assignments] = await Promise.all([
    prisma.demandRequirement.findMany({
      where: {
        status: { not: "CANCELLED" },
        startDate: { lte: endDate },
        endDate: { gte: startDate },
      },
      include: {
        project: { select: { id: true, name: true, shortCode: true } },
      },
      orderBy: [{ project: { name: "asc" } }, { startDate: "asc" }],
      take: 1000,
    }),
    prisma.assignment.findMany({
      where: {
        status: { not: "CANCELLED" },
        startDate: { lte: endDate },
        endDate: { gte: startDate },
      },
      include: {
        resource: { select: { id: true, displayName: true, eid: true, lcrCents: true } },
        project: { select: { id: true, name: true, shortCode: true } },
      },
      orderBy: [{ project: { name: "asc" } }, { startDate: "asc" }],
      take: 1000,
    }),
  ]);

  const allocationView = buildSplitAllocationReadModel({
    demandRequirements,
    assignments,
  });
  const assignmentRows = allocationView.assignments.slice(0, 500);
  const directory = await getAnonymizationDirectory(prisma);

  const rows = assignmentRows.map((a: AllocationLike & {
    resource?: { id: string; displayName?: string | null } | null;
    project?: { shortCode: string; name: string } | null;
  }) => {
    const resource = a.resource ? anonymizeResource(a.resource, directory) : null;
    return {
      resourceName: resource?.displayName ?? "Unknown",
      projectName: a.project ? `${a.project.shortCode} — ${a.project.name}` : "Unknown project",
      role: a.role ?? "",
      startDate: new Date(a.startDate).toLocaleDateString("en-GB"),
      endDate: new Date(a.endDate).toLocaleDateString("en-GB"),
      hoursPerDay: a.hoursPerDay,
      dailyCostCents: a.dailyCostCents,
    };
  });

  const ts = Date.now();

  if (format === "xlsx") {
    const workbookRows = [
      ["Resource", "Project", "Role", "Start Date", "End Date", "Hours/Day", "Daily Cost (ct)"],
      ...rows.map((row) => [
        row.resourceName,
        row.projectName,
        row.role,
        row.startDate,
        row.endDate,
        row.hoursPerDay,
        row.dailyCostCents,
      ]),
    ];
    const buffer = Buffer.from(await createWorkbookArrayBuffer("Allocations", workbookRows));
    return new NextResponse(buffer as unknown as BodyInit, {
      headers: {
        "Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        "Content-Disposition": `attachment; filename="allocations-${ts}.xlsx"`,
      },
    });
  }

  const title = `Allocation Report ${startDate.toLocaleDateString("en-GB")} – ${endDate.toLocaleDateString("en-GB")}`;
  const generatedAt = new Date().toLocaleString("en-GB");
  const doc = createElement(AllocationReport, { title, generatedAt, rows });
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const buffer = await renderToBuffer(doc as any);

  return new NextResponse(buffer as unknown as BodyInit, {
    headers: {
      "Content-Type": "application/pdf",
      "Content-Disposition": `attachment; filename="allocations-${ts}.pdf"`,
    },
  });
}
