"use client";

import { Suspense, use, useState } from "react";
import { useQuery, useIsFetching } from "@tanstack/react-query";
import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { ArrowPathIcon } from "@heroicons/react/24/outline";
import { formatNumber, sapToEpc } from "@/app/utils";
import {
  parseReportingViewState,
  serializeReportingViewState,
  serializeTagFilter,
  tagFiltersEqual,
  type ReportingViewState,
  type TagFilter,
} from "@/lib/reporting/viewState";
import {
  selectGoalCallout,
  shapeKpiDelta,
  toBandCounts,
} from "@/lib/reporting/model";
import {
  ScenarioCombobox,
  type ReportView,
} from "./components/ScenarioCombobox";
import { KpiBand, type Kpi } from "./components/KpiBand";
import { EpcChip, Panel } from "./components/primitives";
import { EpcLadder } from "./components/EpcLadder";
import { GoalCallout } from "./components/GoalCallout";
import {
  InvestmentLedger,
  type LedgerView,
} from "./components/InvestmentLedger";
import { FilterChips, type ScenarioFilters } from "./components/FilterChips";
import { COST_HELP } from "./components/costHelp";
import { DrillDownShelf, type DrillTarget } from "./components/DrillDownShelf";
import { StockBreakdown } from "./components/StockBreakdown";
import { MeasureAllocation } from "./components/MeasureAllocation";
import { TagFilterControl } from "./components/TagFilterControl";

import type {
  BaselineMetrics,
  PropertyTypeCount,
  ScenarioSummary,
} from "./types";

interface Props {
  baselinePromise: Promise<BaselineMetrics>;
  propertyTypesPromise: Promise<PropertyTypeCount[]>;
  scenariosPromise: Promise<ScenarioSummary[]>;
  portfolioGoalPromise: Promise<string>;
  portfolioId: number;
}

/** Maps the combobox view onto the scenario metrics route's id segment. */
function scenarioIdSegment(view: ReportView): number | "default" | null {
  if (view === "current-stock") return null;
  if (view === "recommended") return "default";
  return view;
}

async function fetchScenarioMetrics(
  portfolioId: number,
  segment: number | "default",
  filters: ScenarioFilters,
  tags: TagFilter,
) {
  const p = new URLSearchParams({
    hideNonCompliant: String(filters.hideNonCompliant),
    useLodgedBaseline: String(filters.useLodgedBaseline),
  });
  if (filters.complianceWindow) {
    p.set("complianceDate", filters.complianceWindow.date);
    p.set("complianceBand", filters.complianceWindow.band);
  }
  // View-wide tag filter — the overlay must reflect the same subset as the
  // baseline it's compared against.
  serializeTagFilter(tags, p);
  const res = await fetch(
    `/api/portfolio/${portfolioId}/scenario/${segment}/metrics?${p.toString()}`,
  );
  if (!res.ok) throw new Error("Failed to load scenario report");
  return res.json();
}

/**
 * Orchestrator. The entire reporting view — selected scenario `view`, the
 * scenario `filters`, and the `tags` filter — lives in the URL, so it survives
 * a refresh and browser back/forward. This reads that state from
 * `useSearchParams` (single source of truth) and renders the static header
 * immediately. The scenario picker and the metrics body each live behind their
 * own Suspense boundary, so they stream in independently as their server data
 * resolves (`use()` on the promises handed down from the page). Nothing here
 * awaits, so the shell paints on first byte.
 */
export function ReportingClientArea({
  baselinePromise,
  propertyTypesPromise,
  scenariosPromise,
  portfolioGoalPromise,
  portfolioId,
}: Props) {
  const router = useRouter();
  const pathname = usePathname();
  const searchParams = useSearchParams();

  const state = parseReportingViewState(searchParams);
  const view = state.view as ReportView;
  const tags = state.tags;
  const filters: ScenarioFilters = {
    hideNonCompliant: state.hideNonCompliant,
    useLodgedBaseline: state.useLodgedBaseline,
    complianceWindow: state.complianceWindow,
  };

  const isScenario = scenarioIdSegment(view) !== null;

  // Single writer for the whole view state. A changed *tag* filter must
  // re-render the server (the baseline is filtered server-side) → `router.replace`,
  // and a brief metrics Suspense skeleton is appropriate there (the data genuinely
  // changes). A `view` or scenario-`filter` change only affects the client-fetched
  // overlay, so it goes through the History API — no server round-trip, so the
  // baseline Suspense never re-flashes. Next 15 syncs push/replaceState with
  // `useSearchParams`, so this component re-renders from the new URL either way.
  const applyViewState = (next: ReportingViewState) => {
    const qs = serializeReportingViewState(next).toString();
    const url = qs ? `${pathname}?${qs}` : pathname;
    if (!tagFiltersEqual(next.tags, tags)) {
      router.replace(url, { scroll: false });
      return;
    }
    // A scenario switch is a distinct destination — leave a Back entry. Filter
    // toggles just tweak the current view, so replace (Back shouldn't have to
    // unwind each toggle one at a time).
    if (next.view !== view) {
      window.history.pushState(null, "", url);
    } else {
      window.history.replaceState(null, "", url);
    }
  };

  const onView = (v: ReportView) => applyViewState({ ...state, view: v });
  const onFilters = (f: ScenarioFilters) => applyViewState({ ...state, ...f });
  const onTagsChange = (next: TagFilter) =>
    applyViewState({ ...state, tags: next });

  return (
    <div className="space-y-4" data-reporting>
      {/* Header — static, paints on first byte */}
      <div className="flex items-end justify-between gap-4">
        <div>
          <div className="text-[0.74rem] text-gray-600">Portfolios</div>
          <h1 className="mt-0.5 text-[1.35rem] font-semibold tracking-tight text-brandblue">
            Reporting
          </h1>
        </div>
        <div className="flex gap-2">
          <TagFilterControl
            portfolioId={portfolioId}
            value={tags}
            onChange={onTagsChange}
          />
          {isScenario && (
            <a
              href={`/portfolio/${portfolioId}/reporting/compare`}
              className="inline-flex h-8 items-center rounded-lg border border-gray-200 bg-white px-3.5 text-sm font-medium"
            >
              Compare scenarios
            </a>
          )}
          <a
            href={(() => {
              // Carry the full on-screen view state (view + filters + tags) so
              // the report matches exactly what's being viewed — any view, not
              // just a numeric scenario.
              const qs = serializeReportingViewState(state).toString();
              return `/portfolio/${portfolioId}/reporting/pdf${qs ? `?${qs}` : ""}`;
            })()}
            target="_blank"
            className="inline-flex h-8 items-center rounded-lg border border-brandblue bg-brandblue px-3.5 text-sm font-medium text-white"
          >
            Download report
          </a>
        </div>
      </div>

      {/* Scenario picker — streams as soon as the (fast) scenarios query lands */}
      <Suspense fallback={<ScenarioRowSkeleton />}>
        <ScenarioRow
          scenariosPromise={scenariosPromise}
          baselinePromise={baselinePromise}
          view={view}
          onView={onView}
          filters={filters}
          onFilters={onFilters}
        />
      </Suspense>

      {/* Metrics — streams once the baseline aggregate lands */}
      <Suspense fallback={<MetricsSkeleton />}>
        <MetricsBody
          baselinePromise={baselinePromise}
          propertyTypesPromise={propertyTypesPromise}
          scenariosPromise={scenariosPromise}
          portfolioGoalPromise={portfolioGoalPromise}
          portfolioId={portfolioId}
          view={view}
          filters={filters}
          tags={tags}
        />
      </Suspense>
    </div>
  );
}

// ── Scenario picker row ──────────────────────────────────────────────────────

function ScenarioRow({
  scenariosPromise,
  baselinePromise,
  view,
  onView,
  filters,
  onFilters,
}: {
  scenariosPromise: Promise<ScenarioSummary[]>;
  baselinePromise: Promise<BaselineMetrics>;
  view: ReportView;
  onView: (v: ReportView) => void;
  filters: ScenarioFilters;
  onFilters: (f: ScenarioFilters) => void;
}) {
  const scenarios = use(scenariosPromise);
  const isScenario = scenarioIdSegment(view) !== null;
  const selectedScenario =
    typeof view === "number" ? scenarios.find((s) => s.id === view) : undefined;
  const showEpcFilters = selectedScenario?.goal === "Increasing EPC";

  // Subscribe to the scenario overlay fetch (owned by MetricsBody) without
  // lifting it — so applying a filter shows immediate feedback right here at
  // the controls, not only down in the figures.
  const fetchingCount = useIsFetching({ queryKey: ["scenario-report"] });
  const busy = isScenario && fetchingCount > 0;

  return (
    <div className="flex flex-wrap items-center gap-3">
      <ScenarioCombobox scenarios={scenarios} value={view} onChange={onView} />
      {!isScenario ? (
        // The count needs the baseline; keep it out of the combobox's critical
        // path with its own boundary so the picker isn't held back by it.
        <Suspense
          fallback={
            <span className="text-[0.76rem] text-gray-400">… homes</span>
          }
        >
          <HomesCount baselinePromise={baselinePromise} />
        </Suspense>
      ) : (
        selectedScenario && (
          <span className="text-[0.76rem] text-gray-500">
            {selectedScenario.goal === "Increasing EPC" && (
              <>
                Target{" "}
                <b className="text-gray-900">
                  EPC {selectedScenario.goalValue}
                </b>{" "}
                ·{" "}
              </>
            )}
            {selectedScenario.budget != null && (
              <>
                Budget{" "}
                <b className="text-gray-900">
                  £{selectedScenario.budget.toLocaleString("en-GB")}/home
                </b>
              </>
            )}
          </span>
        )
      )}
      {isScenario && (
        <div className="ml-auto flex items-center gap-2">
          {busy && (
            <span
              className="flex items-center gap-1 text-[0.72rem] text-gray-500"
              role="status"
              aria-live="polite"
            >
              <ArrowPathIcon className="h-3.5 w-3.5 animate-spin text-gray-400" />
              Updating…
            </span>
          )}
          <FilterChips
            filters={filters}
            onChange={onFilters}
            showEpcFilters={!!showEpcFilters}
          />
        </div>
      )}
    </div>
  );
}

function HomesCount({
  baselinePromise,
}: {
  baselinePromise: Promise<BaselineMetrics>;
}) {
  const baseline = use(baselinePromise);
  return (
    <span className="text-[0.76rem] text-gray-500">{baseline.total} homes</span>
  );
}

// ── Metrics body ─────────────────────────────────────────────────────────────

function MetricsBody({
  baselinePromise,
  propertyTypesPromise,
  scenariosPromise,
  portfolioGoalPromise,
  portfolioId,
  view,
  filters,
  tags,
}: {
  baselinePromise: Promise<BaselineMetrics>;
  propertyTypesPromise: Promise<PropertyTypeCount[]>;
  scenariosPromise: Promise<ScenarioSummary[]>;
  portfolioGoalPromise: Promise<string>;
  portfolioId: number;
  view: ReportView;
  filters: ScenarioFilters;
  tags: TagFilter;
}) {
  const baseline = use(baselinePromise);
  const propertyTypes = use(propertyTypesPromise);
  const scenarios = use(scenariosPromise);
  const portfolioGoal = use(portfolioGoalPromise);

  const [drill, setDrill] = useState<DrillTarget | null>(null);
  const [drillPage, setDrillPage] = useState(1);

  const segment = scenarioIdSegment(view);
  const isScenario = segment !== null;
  const selectedScenario =
    typeof view === "number" ? scenarios.find((s) => s.id === view) : undefined;

  const { data: scenarioData, isFetching } = useQuery({
    // `tags` is in the key so the overlay refetches when the tag filter changes.
    queryKey: ["scenario-report", portfolioId, segment, filters, tags],
    queryFn: () => fetchScenarioMetrics(portfolioId, segment!, filters, tags),
    enabled: isScenario,
    keepPreviousData: true,
    refetchOnWindowFocus: false,
    staleTime: 5 * 60 * 1000,
    cacheTime: 30 * 60 * 1000,
  });

  const total = baseline.total;
  const avg = baseline.averages;

  function openDrill(t: DrillTarget) {
    setDrill(t);
    setDrillPage(1);
    // Bring the shelf into view so a click below the fold doesn't look inert.
    // Done in the handler (not an effect) per project convention.
    if (typeof window !== "undefined") {
      const reduce = window.matchMedia(
        "(prefers-reduced-motion: reduce)",
      ).matches;
      requestAnimationFrame(() =>
        document.getElementById("reporting-drill-shelf")?.scrollIntoView({
          behavior: reduce ? "auto" : "smooth",
          block: "nearest",
        }),
      );
    }
  }

  // ── KPI band ───────────────────────────────────────────────────────────
  const currentStockKpis: Kpi[] = [
    {
      label: "Homes",
      value: total,
      sub: (
        <button
          onClick={() => openDrill({ filter: "estimated", title: "All homes" })}
          className="font-semibold text-midblue"
        >
          View all →
        </button>
      ),
    },
    {
      label: "Average EPC",
      value: (
        <span className="flex items-center gap-1.5">
          <EpcChip band={sapToEpc(avg.avg_sap ?? 0)} />
          {Math.round(avg.avg_sap ?? 0)}
        </span>
      ),
      unit: "SAP",
    },
    {
      label: "Energy bills",
      value: `£${formatNumber(avg.avg_bills ?? 0)}`,
      unit: "/home/yr",
      sub: `£${formatNumber(baseline.totals.total_bills ?? 0)} across the portfolio`,
    },
    {
      label: "Carbon",
      value: formatNumber(avg.avg_carbon ?? 0),
      unit: "tCO₂e/home",
      sub: `${formatNumber(baseline.totals.total_carbon ?? 0)} t total`,
    },
    {
      label: "Energy use",
      value: formatNumber(avg.avg_energy_consumption ?? 0),
      unit: "kWh/home",
    },
  ];

  const scenarioKpis: Kpi[] = scenarioData
    ? [
        {
          label: "Homes upgraded",
          value: scenarioData.n_units_upgraded,
          unit: `of ${total}`,
          sub: (
            <a
              href={`/portfolio/${portfolioId}`}
              className="font-semibold text-midblue"
            >
              View upgraded homes →
            </a>
          ),
        },
        (() => {
          const d = shapeKpiDelta({
            current: avg.avg_sap ?? 0,
            after: Number(scenarioData.avg_sap),
            improvesWhenLower: false,
          });
          return {
            label: "Average EPC",
            value: (
              <span className="flex items-center gap-1.5">
                <EpcChip band={sapToEpc(Number(scenarioData.avg_sap))} />
                {Math.round(Number(scenarioData.avg_sap))}
              </span>
            ),
            delta: {
              text: `${d.delta > 0 ? "+" : ""}${d.delta.toFixed(0)} SAP`,
              improved: d.improved,
            },
            sub: (
              <span className="flex items-center gap-1">
                was <EpcChip band={sapToEpc(avg.avg_sap ?? 0)} size="sm" />{" "}
                {Math.round(avg.avg_sap ?? 0)}
              </span>
            ),
          };
        })(),
        (() => {
          const d = shapeKpiDelta({
            current: avg.avg_bills ?? 0,
            after: Number(scenarioData.avg_bills),
            improvesWhenLower: true,
          });
          return {
            label: "Energy bills",
            value: `£${formatNumber(Number(scenarioData.avg_bills))}`,
            delta: {
              text: `−£${formatNumber(Math.abs(d.delta))}`,
              improved: d.improved,
            },
            sub: `was £${formatNumber(avg.avg_bills ?? 0)}`,
          };
        })(),
        (() => {
          const d = shapeKpiDelta({
            current: avg.avg_carbon ?? 0,
            after: Number(scenarioData.avg_carbon),
            improvesWhenLower: true,
          });
          return {
            label: "Carbon",
            value: formatNumber(Number(scenarioData.avg_carbon)),
            unit: "tCO₂e/home",
            delta: {
              text: `−${formatNumber(Math.abs(d.delta))} t`,
              improved: d.improved,
            },
            sub: `was ${formatNumber(avg.avg_carbon ?? 0)}`,
          };
        })(),
        {
          label: "Gross cost /home",
          value: `£${formatNumber(scenarioData.gross_per_unit ?? 0)}`,
          sub: `${scenarioData.n_units_upgraded} homes`,
          tip: COST_HELP.grossPerHome,
        },
      ]
    : [];

  // ── EPC ladder overlay + goal callout ──────────────────────────────────
  const scenarioBands: Record<string, number> | undefined =
    scenarioData?.scenario_epc_counts;

  const bandCounts = toBandCounts(baseline.epcBands);
  const callout = isScenario
    ? selectGoalCallout({
        view: "scenario",
        goal: selectedScenario?.goal ?? portfolioGoal,
        goalValue: selectedScenario?.goalValue ?? null,
        bandCounts,
        scenarioBandCounts: scenarioBands ?? {},
      })
    : selectGoalCallout({
        view: "current-stock",
        goal: portfolioGoal,
        bandCounts,
      });

  // ── Investment ledger ──────────────────────────────────────────────────
  const ledger: LedgerView | null = scenarioData
    ? (() => {
        const carbonSaved =
          (baseline.totals.total_carbon ?? 0) -
          Number(scenarioData.total_carbon);
        const billSaved =
          (baseline.totals.total_bills ?? 0) - Number(scenarioData.total_bills);
        const n = scenarioData.n_units_upgraded || 1;
        const capital = scenarioData.construction_cost + scenarioData.pc_cost;
        return {
          constructionCost: scenarioData.construction_cost,
          projectDelivery: scenarioData.pc_cost,
          contingency: scenarioData.contingency,
          funding: scenarioData.total_funding,
          grossCost: scenarioData.gross_cost,
          netCost: scenarioData.net_cost,
          grossPerHome: scenarioData.gross_per_unit,
          billSavings: billSaved,
          billSavingsPerHome: billSaved / n,
          carbonSaved,
          costPerSap:
            scenarioData.total_sap_uplift > 0
              ? capital / scenarioData.total_sap_uplift
              : 0,
          costPerCarbon: carbonSaved > 0 ? capital / carbonSaved : 0,
        };
      })()
    : null;

  const scenarioBusy = isScenario && isFetching;
  // First entry into a scenario from Current stock: there's no previous overlay
  // to keep, so the scenario KPIs are momentarily empty. Skeleton that band
  // (the "no data yet" case → same pattern as first page load) rather than
  // flashing an empty bar. A scenario→scenario switch keeps the old figures, so
  // it stays on the dim+spinner path below instead.
  const scenarioLoadingFirst = scenarioBusy && !scenarioData;

  return (
    <div className="space-y-4">
      {/* Refetch-with-data only: the figures stay on screen and dim, so a label
          clarifies the dim means "updating". First load speaks via its skeleton. */}
      {scenarioBusy && scenarioData && (
        <div
          className="flex items-center gap-1.5 text-[0.8rem] text-gray-600"
          role="status"
          aria-live="polite"
        >
          <ArrowPathIcon className="h-3.5 w-3.5 animate-spin text-gray-400" />
          Updating figures…
        </div>
      )}

      {/* Scenario figures dim while the overlay refetches — keepPreviousData
          leaves the old numbers on screen, so this signals they're being
          recalculated rather than letting them look silently up to date. */}
      <div
        className={`space-y-4 transition-opacity duration-200 ${
          scenarioBusy && scenarioData ? "opacity-50" : ""
        }`}
        aria-busy={scenarioBusy}
      >
        {/* KPI band */}
        {scenarioLoadingFirst ? (
          <KpiBandSkeleton />
        ) : (
          <KpiBand kpis={isScenario ? scenarioKpis : currentStockKpis} />
        )}

        {/* Charts + ledger */}
        <div className="grid grid-cols-1 items-stretch gap-4 lg:grid-cols-[1.55fr_1fr]">
          <Panel
            title="EPC distribution"
            meta={
              isScenario
                ? "Current vs scenario · click a band for its homes"
                : "Effective performance · click a band for its homes"
            }
          >
            <div className="mb-4">
              <EpcLadder
                bands={baseline.epcBands}
                scenarioBands={scenarioBands}
                selectedBand={drill?.filter === "band" ? drill.band : null}
                onSelectBand={(band) =>
                  openDrill({
                    filter: "band",
                    band,
                    chipBand: band,
                    title: `Band ${band}`,
                  })
                }
              />
            </div>
            <GoalCallout
              callout={callout}
              total={total}
              dimensionTotals={{ carbon: baseline.totals.total_carbon ?? 0 }}
              onDrill={
                callout.kind === "below-band"
                  ? () =>
                      openDrill({
                        filter: "band",
                        band: callout.band,
                        chipBand: callout.band,
                        title: `Below EPC ${callout.band}`,
                      })
                  : undefined
              }
            />
          </Panel>

          {isScenario && ledger ? (
            <InvestmentLedger v={ledger} />
          ) : (
            <StockBreakdown
              propertyTypes={propertyTypes}
              ageBands={baseline.ageBands}
            />
          )}
        </div>
      </div>

      {/* Where the money goes (scenario only) */}
      {isScenario && segment !== null && (
        <MeasureAllocation
          portfolioId={portfolioId}
          scenarioId={segment}
          tags={tags}
          onDrillMeasure={
            typeof view === "number"
              ? (t) => openDrill({ ...t, scenarioId: view })
              : undefined
          }
        />
      )}

      {/* Data confidence strip */}
      <ConfidenceStrip
        baseline={baseline}
        portfolioId={portfolioId}
        onDrill={openDrill}
      />

      {/* Drill-down shelf */}
      {drill && (
        <DrillDownShelf
          portfolioId={portfolioId}
          target={drill}
          page={drillPage}
          onPage={setDrillPage}
          onClose={() => setDrill(null)}
          tags={tags}
        />
      )}
    </div>
  );
}

// ── Streaming skeletons ──────────────────────────────────────────────────────

function ScenarioRowSkeleton() {
  return (
    <div className="flex flex-wrap items-center gap-3" aria-hidden>
      <div className="h-9 w-60 animate-pulse rounded-lg border border-gray-200 bg-gray-100" />
      <div className="h-3 w-24 animate-pulse rounded bg-gray-100" />
    </div>
  );
}

/**
 * The five-cell KPI band in its loading shape. Shared by the initial page-load
 * skeleton and the first Current-stock → scenario switch, so both "no data yet"
 * moments read identically.
 */
function KpiBandSkeleton() {
  return (
    <div
      className="grid grid-cols-2 rounded-lg border border-gray-200 bg-white sm:grid-cols-3 lg:grid-cols-5"
      aria-hidden
    >
      {Array.from({ length: 5 }).map((_, i) => (
        <div
          key={i}
          className={`space-y-2 px-5 py-4 ${i > 0 ? "border-l border-gray-100" : ""}`}
        >
          <div className="h-2.5 w-16 animate-pulse rounded bg-gray-100" />
          <div className="h-6 w-20 animate-pulse rounded bg-gray-100" />
        </div>
      ))}
    </div>
  );
}

function MetricsSkeleton() {
  return (
    <div className="space-y-4" aria-hidden>
      <KpiBandSkeleton />
      {/* Charts + side panel */}
      <div className="grid grid-cols-1 items-stretch gap-4 lg:grid-cols-[1.55fr_1fr]">
        <div className="h-64 animate-pulse rounded-lg border border-gray-200 bg-white" />
        <div className="h-64 animate-pulse rounded-lg border border-gray-200 bg-white" />
      </div>
      {/* Confidence strip */}
      <div className="h-12 animate-pulse rounded-lg border border-gray-200 bg-white" />
    </div>
  );
}

function ConfidenceStrip({
  baseline,
  portfolioId,
  onDrill,
}: {
  baseline: BaselineMetrics;
  portfolioId: number;
  onDrill: (t: DrillTarget) => void;
}) {
  const total = baseline.total;
  const estimated = baseline.estimatedCounts.estimated;
  const lodgedPct =
    total > 0 ? Math.round(((total - estimated) / total) * 100) : 0;

  const Item = ({
    label,
    value,
    onClick,
  }: {
    label: string;
    value: React.ReactNode;
    onClick?: () => void;
  }) => (
    <button
      onClick={onClick}
      disabled={!onClick}
      className={`tabular-nums ${onClick ? "hover:text-brandblue" : ""}`}
    >
      <b className="font-semibold text-gray-900">{value}</b>{" "}
      <span className="text-gray-500">{label}</span>
    </button>
  );

  return (
    <div className="flex flex-wrap items-center gap-x-6 gap-y-2 rounded-lg border border-gray-200 bg-white px-5 py-3 text-[0.8rem]">
      <span className="text-[0.78rem] font-semibold text-brandblue">
        Data confidence
      </span>
      <Item label="lodged EPCs" value={`${lodgedPct}%`} />
      <Item
        label="estimated"
        value={estimated}
        onClick={() =>
          onDrill({ filter: "estimated", title: "Estimated EPCs" })
        }
      />
      <Item
        label="expired"
        value={baseline.expiredEpcs}
        onClick={() => onDrill({ filter: "expired", title: "Expired EPCs" })}
      />
      <Item
        label="likely downgrades"
        value={baseline.likelyDowngrades}
        onClick={() =>
          onDrill({ filter: "likely-downgrade", title: "Likely downgrades" })
        }
      />
      <button
        onClick={() =>
          onDrill({ filter: "likely-upgrade", title: "Likely upgrades" })
        }
        className="text-[#0c6b4a] hover:underline"
      >
        Likely upgrades →
      </button>
      <a
        href={`/portfolio/${portfolioId}/reporting/data-quality`}
        className="ml-auto font-semibold text-midblue"
      >
        Review data quality →
      </a>
    </div>
  );
}
