import { auth } from "@/auth";
import { hasPermission } from "@/lib/permissions";
import { NextRequest, NextResponse } from "next/server";
import {
  getReportDataset,
  buildAccountIndex,
  costCentreRows,
  accountLevelRows,
  topAccountsForCostCentre,
  costCentresForAccount,
  childBreakdown,
  accountNodeSpend,
  applyScope,
  parseScope,
  parseGranularity,
  parseSel,
  resolveFy,
  fyLabel,
  type Tier,
} from "@/lib/reports";

const sum = (a: number[]) => a.reduce((x, y) => x + y, 0);
const cell = (v: string | number) => {
  const s = String(v);
  return /[",\n]/.test(s) ? `"${s.replace(/"/g, '""')}"` : s;
};
function csv(headers: string[], rows: (string | number)[][]): string {
  return [headers, ...rows].map((r) => r.map(cell).join(",")).join("\n");
}
function file(name: string, body: string) {
  return new NextResponse(body, {
    headers: {
      "Content-Type": "text/csv; charset=utf-8",
      "Content-Disposition": `attachment; filename="${name}-${Date.now()}.csv"`,
    },
  });
}

// CSV export for the Reports → Purchasing views. The `dim` query param mirrors
// the page the user is on, so the download matches what's on screen.
export async function GET(req: NextRequest) {
  const session = await auth();
  if (!session?.user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  if (!hasPermission(session.user.role, "view_analytics")) return NextResponse.json({ error: "Forbidden" }, { status: 403 });

  const sp = req.nextUrl.searchParams;
  const dim = sp.get("dim") ?? "cost-centre";
  const ds = await getReportDataset();
  const idx = buildAccountIndex(ds.accounts);
  const gran = parseGranularity(sp.get("gran") ?? undefined);
  const scope = parseScope(sp.get("scope") ?? undefined);
  const fy = resolveFy(ds, sp.get("fy") ?? undefined);
  const yearly = gran === "yearly";
  const fyCols = ds.fys.map(fyLabel);

  const sel = parseSel(sp.get("sel") ?? undefined);

  if (dim === "cost-centre") {
    const ranked = costCentreRows(ds, fy).sort((a, b) => (yearly ? sum(b.fyTotals) - sum(a.fyTotals) : b.total - a.total));
    const picked = sel.length ? ranked.filter((r) => sel.includes(r.id)) : applyScope(ranked, scope);
    const rows = picked.map((r) => [r.code, r.name, ...r.fyTotals, r.total, r.poCount]);
    return file("pelagia-cost-centre-spend", csv(["Code", "Cost Centre", ...fyCols, `${fyLabel(fy)} Total`, "POs"], rows));
  }

  if (dim === "accounting-code") {
    let ranked;
    if (sel.length) {
      ranked = sel.filter((id) => idx.byId.has(id)).map((id) => ({ node: idx.byId.get(id)!, ...accountNodeSpend(ds, idx, id, fy) }));
    } else {
      const parent = sp.get("parent");
      const parentId = parent && idx.byId.has(parent) ? parent : null;
      ranked = accountLevelRows(ds, idx, parentId, fy);
    }
    ranked.sort((a, b) => (yearly ? sum(b.fyTotals) - sum(a.fyTotals) : b.total - a.total));
    const picked = sel.length ? ranked : applyScope(ranked, scope);
    const rows = picked.map((r) => [r.node.code, r.node.name, r.node.tier, ...r.fyTotals, r.total, r.poCount]);
    return file("pelagia-accounting-code-spend", csv(["Code", "Name", "Tier", ...fyCols, `${fyLabel(fy)} Total`, "POs"], rows));
  }

  if (dim === "cost-centre-detail") {
    const id = sp.get("id") ?? "";
    const tier = (["Heading", "Sub-heading", "Leaf"] as Tier[]).includes(sp.get("tier") as Tier) ? (sp.get("tier") as Tier) : "Leaf";
    const rows = topAccountsForCostCentre(ds, idx, id, fy, tier).map((b) => [b.label, b.value]);
    return file("pelagia-cost-centre-detail", csv([tier, `Spend (${fyLabel(fy)})`], rows));
  }

  if (dim === "accounting-code-detail") {
    const id = sp.get("id") ?? "";
    const leaf = idx.isLeaf(id);
    const mode = leaf || sp.get("break") === "cc" ? "cc" : "children";
    const bd = mode === "cc" ? costCentresForAccount(ds, idx, id, fy) : childBreakdown(ds, idx, id, fy);
    const rows = bd.map((b) => [b.label, b.value]);
    return file("pelagia-accounting-code-detail", csv([mode === "cc" ? "Cost centre" : "Sub-account", `Spend (${fyLabel(fy)})`], rows));
  }

  return NextResponse.json({ error: "Unknown report dimension" }, { status: 400 });
}
