import { auth } from "@/auth";
import { redirect } from "next/navigation";
import Link from "next/link";
import type { Metadata } from "next";
import { ChevronRight, BarChart3 } from "lucide-react";
import { hasPermission } from "@/lib/permissions";
import { formatCurrency, formatCompactINR } from "@/lib/utils";
import {
  getReportDataset,
  buildAccountIndex,
  accountLevelRows,
  accountNodeSpend,
  accountNodeWeekly,
  applyScope,
  parseScope,
  parseGranularity,
  resolveFy,
  resolveMonth,
  parseSel,
  toggleSel,
  fyLabel,
  FY_MONTHS,
  WEEK_LABELS,
  SCOPE_LABELS,
  type NodeSpend,
} from "@/lib/reports";
import { ReportsToolbar } from "@/components/reports/reports-toolbar";
import { ComparisonChart, Sparkline, type Series } from "@/components/reports/charts";
import { SERIES_COLORS } from "@/lib/report-colors";
import { Kpi, KpiStrip } from "@/components/reports/kpi";
import { ReportBreadcrumb, ReportTitle, SelectCheckbox, CompareBar } from "@/components/reports/report-header";

export const metadata: Metadata = { title: "Accounting Codes — Reports" };

const sum = (a: number[]) => a.reduce((x, y) => x + y, 0);
const tierBadgeCls: Record<string, string> = {
  Heading: "bg-primary-50 text-primary-700",
  "Sub-heading": "bg-violet-50 text-violet-700",
  Leaf: "bg-neutral-100 text-neutral-600",
};

export default async function AccountingCodesReport({
  searchParams,
}: {
  searchParams: Promise<{ fy?: string; gran?: string; scope?: string; month?: string; parent?: string; sel?: string; cmp?: string }>;
}) {
  const session = await auth();
  if (!session?.user) return null;
  if (!hasPermission(session.user.role, "view_analytics")) redirect("/dashboard");

  const sp = await searchParams;
  const ds = await getReportDataset();
  const idx = buildAccountIndex(ds.accounts);
  const gran = parseGranularity(sp.gran);
  const scope = parseScope(sp.scope);
  const fy = resolveFy(ds, sp.fy);
  const yearly = gran === "yearly";
  const weekly = gran === "weekly";
  const month = resolveMonth(ds, fy, sp.month);
  const sel = parseSel(sp.sel);
  const cmp = sp.cmp === "1" && sel.length > 0;

  const parent = sp.parent && idx.byId.has(sp.parent) ? sp.parent : null;
  const parentNode = parent ? idx.byId.get(parent)! : null;

  const rankOf = (r: NodeSpend) => (yearly ? sum(r.fyTotals) : weekly ? r.months[month] : r.total);
  const sparkOf = (r: NodeSpend) => (yearly ? r.fyTotals : weekly ? accountNodeWeekly(ds, idx, r.node.id, fy, month) : r.months);

  const ranked = cmp
    ? sel.filter((id) => idx.byId.has(id)).map((id) => ({ node: idx.byId.get(id)!, ...accountNodeSpend(ds, idx, id, fy) }))
    : accountLevelRows(ds, idx, parent, fy);
  ranked.sort((a, b) => rankOf(b) - rankOf(a));
  const shown = cmp ? ranked : applyScope(ranked, scope);
  const grand = shown.reduce((s, r) => s + rankOf(r), 0);
  const childTier = shown[0]?.node.tier ?? "Heading";
  const top = shown[0];

  const nf = ds.fys.length;
  const curT = nf >= 1 ? shown.reduce((s, r) => s + r.fyTotals[nf - 1], 0) : 0;
  const prevT = nf >= 2 ? shown.reduce((s, r) => s + r.fyTotals[nf - 2], 0) : 0;
  const yoy = prevT ? ((curT - prevT) / prevT) * 100 : 0;

  // One distinct colour per accounting code (series) in every granularity; the
  // x-axis is months / weeks / financial years.
  const colored = (i: number) => SERIES_COLORS[i % SERIES_COLORS.length];
  const chartLabels = yearly ? ds.fys.map(fyLabel) : weekly ? [...WEEK_LABELS] : [...FY_MONTHS];
  const chartData: Record<string, string | number>[] = chartLabels.map((lab, i) => {
    const row: Record<string, string | number> = { x: lab };
    shown.forEach((r) => (row[r.node.code] = sparkOf(r)[i]));
    return row;
  });
  const series: Series[] = shown.map((r, i) => ({ key: r.node.code, color: colored(i) }));

  const monthLabel = (i: number) => `${FY_MONTHS[i]} '${String((fy + (i >= 9 ? 1 : 0)) % 100).padStart(2, "0")}`;
  const periodLabel = yearly ? ds.fys.map(fyLabel).join(" · ") : weekly ? `${monthLabel(month)} · ${fyLabel(fy)}` : fyLabel(fy);

  const base: Record<string, string | undefined> = {
    fy: String(fy),
    gran: gran === "monthly" ? undefined : gran,
    scope: scope === "top5" ? undefined : scope,
    month: weekly ? String(month) : undefined,
  };
  const qs = (extra: Record<string, string | undefined>) => {
    const p = new URLSearchParams();
    for (const [k, v] of Object.entries({ ...base, ...extra })) if (v) p.set(k, v);
    const s = p.toString();
    return s ? `?${s}` : "";
  };
  const linkWith = (parentId: string | null) => `/reports/accounting-codes${qs({ parent: parentId ?? undefined, sel: sel.join(",") || undefined })}`;
  const detailHref = (id: string) => `/reports/accounting-codes/${id}${qs({ scope: undefined, parent: undefined })}`;
  const selHref = (id: string) => {
    const next = toggleSel(sel, id);
    return `/reports/accounting-codes${qs({ parent: cmp ? undefined : parent ?? undefined, sel: next.join(",") || undefined, cmp: cmp && next.length ? "1" : undefined })}`;
  };
  const rowHref = (r: NodeSpend) => (idx.isLeaf(r.node.id) ? detailHref(r.node.id) : linkWith(r.node.id));
  const exportHref = `/api/reports/spend?dim=accounting-code&fy=${fy}&gran=${gran}&scope=${scope}${parent && !cmp ? `&parent=${parent}` : ""}${cmp ? `&sel=${sel.join(",")}` : ""}`;

  const trail = [{ label: "Accounting Codes", href: parent || cmp ? linkWith(null) : undefined }];
  if (parentNode && !cmp) {
    idx.pathTo(parentNode.id).forEach((a, i, arr) => trail.push({ label: `${a.code} · ${a.name}`, href: i < arr.length - 1 ? linkWith(a.id) : undefined }));
  }

  return (
    <div>
      <ReportBreadcrumb trail={trail} />
      <ReportsToolbar
        fys={ds.fys}
        fy={fy}
        gran={gran}
        scope={cmp ? undefined : scope}
        month={month}
        monthOptions={FY_MONTHS.map((_, i) => ({ value: i, label: monthLabel(i) }))}
        exportHref={exportHref}
      />

      {cmp ? (
        <Link href={qs({ sel: sel.join(",") })} className="mb-4 inline-flex items-center gap-1.5 text-sm font-medium text-primary-600 hover:text-primary-700">
          ← Back to browse
        </Link>
      ) : (
        <>
          {parentNode && (
            <Link
              href={linkWith(parentNode.parentId ?? null)}
              className="mb-4 inline-flex items-center gap-1.5 text-sm font-medium text-primary-600 hover:text-primary-700"
            >
              ← Back to {parentNode.parentId ? idx.byId.get(parentNode.parentId)!.name : "Accounting Codes"}
            </Link>
          )}
          {sel.length > 0 && <CompareBar count={sel.length} compareHref={qs({ sel: sel.join(","), cmp: "1" })} clearHref={qs({ parent: parent ?? undefined })} />}
        </>
      )}

      <ReportTitle
        title={cmp ? "Custom comparison" : parentNode ? `${parentNode.code} · ${parentNode.name}` : "Accounting Codes"}
        subtitle={
          cmp
            ? `Comparing ${shown.length} selected accounting codes. Untick a row to remove it.`
            : parentNode
              ? `Comparing the ${childTier.toLowerCase()}s of ${parentNode.name}. Tick to graph, or click to ${childTier === "Leaf" ? "open its report" : "drill deeper"}.`
              : "Comparing top-level headings. Tick to graph, or click a heading to drill in."
        }
      />

      {grand === 0 ? (
        <div className="rounded-lg border border-dashed border-neutral-300 bg-white p-10 text-center text-sm text-neutral-500">
          No approved spend recorded for {periodLabel} yet.
        </div>
      ) : (
        <>
          <KpiStrip>
            <Kpi label="Total spend" value={formatCompactINR(grand)} sub={periodLabel} />
            <Kpi label={cmp ? "Selected" : `${childTier}s`} value={String(shown.length)} sub={cmp ? "in this graph" : `${SCOPE_LABELS[scope]} shown`} />
            <Kpi label="Highest spender" value={top ? top.node.code : "—"} sub={top ? formatCompactINR(rankOf(top)) : ""} />
            <Kpi label="YoY change" value={`${yoy >= 0 ? "+" : ""}${yoy.toFixed(1)}%`} sub="vs prior FY" delta={yoy} />
          </KpiStrip>

          <div className="mb-6 rounded-lg border border-neutral-200 bg-white p-5">
            <div className="mb-4 flex items-center justify-between">
              <p className="text-sm font-semibold text-neutral-900">
                {yearly ? `Spend by ${childTier.toLowerCase()} — year over year` : weekly ? `Weekly spend by ${childTier.toLowerCase()}` : `Monthly spend by ${childTier.toLowerCase()}`}
              </p>
              <span className="text-xs text-neutral-400">{periodLabel}</span>
            </div>
            <ComparisonChart kind={yearly ? "bars" : "lines"} data={chartData} xKey="x" series={series} />
          </div>

          <div className="overflow-hidden rounded-lg border border-neutral-200 bg-white">
            {shown.map((r) => {
              const value = rankOf(r);
              const pct = grand ? (value / grand) * 100 : 0;
              const leaf = idx.isLeaf(r.node.id);
              const inner = (
                <>
                  <span className="w-14 shrink-0 font-mono text-xs text-neutral-500">{r.node.code}</span>
                  <span className="flex-1 truncate text-sm font-medium text-neutral-900 group-hover:text-primary-700">{r.node.name}</span>
                  <span className={`rounded-full px-2 py-0.5 text-xs font-medium ${tierBadgeCls[r.node.tier]}`}>{r.node.tier}</span>
                  <Sparkline values={sparkOf(r)} width={80} height={24} />
                  <span className="w-28 text-right font-medium tabular-nums text-sm">{formatCurrency(value)}</span>
                  <div className="hidden w-12 text-right tabular-nums text-xs text-neutral-500 md:block">{pct.toFixed(0)}%</div>
                  {!cmp && (leaf ? <BarChart3 className="h-4 w-4 shrink-0 text-neutral-300 group-hover:text-primary-500" /> : <ChevronRight className="h-4 w-4 shrink-0 text-neutral-300 group-hover:text-primary-500" />)}
                </>
              );
              return (
                <div key={r.node.id} className="group flex items-center gap-3 border-b border-neutral-100 px-5 py-3 last:border-0 hover:bg-primary-50/40">
                  <SelectCheckbox checked={sel.includes(r.node.id)} href={selHref(r.node.id)} />
                  {cmp ? (
                    <div className="flex flex-1 items-center gap-3 min-w-0">{inner}</div>
                  ) : (
                    <Link href={rowHref(r)} className="flex flex-1 items-center gap-3 min-w-0">{inner}</Link>
                  )}
                </div>
              );
            })}
          </div>
        </>
      )}
    </div>
  );
}
