// screen_dashboard.jsx — Overview / threat landscape (self-fetches /api/dashboard)
function Dashboard({ onOpen, onNav, statusMap }) {
  const { data, loading, error, refetch } = useApi((signal) => window.VCApi.dashboard(signal));
  // The catalog backs the client-side triage overlay below (remediation status lives
  // only in localStorage, so the server can't know it). Loads progressively — the
  // page paints from /api/dashboard first, then refines once the catalog arrives.
  const catalog = useApi(() => window.VC.ensureCatalog());
  const SEG = [["7 days", 7], ["30 days", 30], ["Quarter", 90]];
  const [winDays, setWinDays] = useState(90);

  if (loading) return <PageLoading label="Loading threat landscape…" />;
  if (error) return <PageError message={error} onRetry={refetch} />;

  // Server-computed aggregates (status-independent): trend, top ECUs, coverage, and
  // the severity distribution / base KPI counts.
  const TREND = (data && data.trend) || [];
  const TOP_ECUS = (data && data.topEcus) || [];
  const COVERAGE = Object.assign(
    { vsNvd: 0, sources: 0, classified: 0, freshnessHrs: 0, lastSync: "—" },
    (data && data.coverage) || {},
  );
  const baseCounts = (data && data.kpis) || { total: 0, new7d: 0, critOpen: 0, remediated: 0 };
  const windows = (data && data.windows) || [];
  const win = windows.find(w => w.days === winDays) || windows[0] || { severity: {}, priority: [] };
  // How many of the customer's matches were published within the selected window.
  const newInWindow = Object.values(win.severity || {}).reduce((a, b) => a + b, 0);

  // ---- the customer's OWN SBOM/HBOM match set --------------------------------
  // `cat` is this tenant's matches (GET /api/ledger, scoped to their components), so
  // every number on this page reflects what THEY uploaded — it is empty until they add
  // an SBOM/HBOM. Loads progressively: the page paints from /api/dashboard first, then
  // refines once cat arrives (which also carries the localStorage triage overlay).
  const cat = catalog.data || [];
  const statusOf = (v) => (statusMap && statusMap[v.id]) || "new";
  const isOpen = (v) => { const s = statusOf(v); return s !== "remediated" && s !== "accepted"; };

  const counts = cat.length ? {
    total: cat.length,
    newWin: newInWindow,
    critOpen: cat.reduce((n, v) => (v.severity === "Critical" && isOpen(v)) ? n + 1 : n, 0),
    remediated: cat.reduce((n, v) => statusOf(v) === "remediated" ? n + 1 : n, 0),
  } : { total: baseCounts.total, newWin: newInWindow, critOpen: baseCounts.critOpen, remediated: baseCounts.remediated };

  // Severity distribution + priority queue are computed over the FULL match set so the
  // donut total matches "Total tracked"; falls back to the server window until cat loads.
  const SEV_ORDER = { Critical: 0, High: 1, Medium: 2, Low: 3 };
  const sevSource = cat.length
    ? cat.reduce((m, v) => (m[v.severity] = (m[v.severity] || 0) + 1, m), {})
    : (win.severity || {});
  const priority = (cat.length ? cat.filter(isOpen) : (win.priority || []).filter(isOpen))
    .slice()
    .sort((a, b) => (SEV_ORDER[a.severity] - SEV_ORDER[b.severity]) || (b.cvss - a.cvss))
    .slice(0, 6);

  const sevData = [
    { label: "Critical", value: sevSource.Critical || 0, color: "var(--sev-critical)" },
    { label: "High", value: sevSource.High || 0, color: "var(--sev-high)" },
    { label: "Medium", value: sevSource.Medium || 0, color: "var(--sev-medium)" },
    { label: "Low", value: sevSource.Low || 0, color: "var(--sev-low)" },
  ];
  const totalSev = sevData.reduce((a, b) => a + b.value, 0);

  // Export pulls the full catalog on demand (the dashboard itself doesn't hold it),
  // then narrows it to the selected 7/30/90-day window so the file matches what the
  // page is showing. Anchor the window on the most recent publication in the data —
  // same convention as the ledger — and drop items with empty/unparseable dates.
  function exportCatalog(kind) {
    window.VC.ensureCatalog()
      .then(items => {
        let max = 0;
        items.forEach(v => { const t = v.published ? Date.parse(v.published) : NaN; if (!isNaN(t) && t > max) max = t; });
        const now = max || Date.now();
        const inWindow = items.filter(v => {
          const t = v.published ? Date.parse(v.published) : NaN;
          if (isNaN(t)) return false;
          const days = (now - t) / 8.64e7;
          return days >= 0 && days <= winDays;
        });
        const label = SEG.find(([, d]) => d === winDays);
        const tag = (label ? label[1] : winDays) + "d";
        if (kind === "report") window.VCExport.report(inWindow, { target: "Threat landscape — last " + tag, statusOf, filename: "vulnerability-report-" + tag });
        else window.VCExport.vulns(inWindow, "vulnerabilities-" + tag);
      })
      .catch(() => {});
  }

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <span className="eyebrow">Overview</span>
          <h1 className="page-title">Threat landscape</h1>
          <p className="page-desc">Automotive and IoT vulnerabilities found in the SBOM / HBOM you upload.</p>
        </div>
        <div className="page-head-aside">
          <div className="seg">
            {SEG.map(([label, days]) => (
              <button key={label} className={"seg-btn" + (winDays === days ? " is-on" : "")} onClick={() => setWinDays(days)}>{label}</button>
            ))}
          </div>
          <button className="btn btn-ghost" onClick={() => exportCatalog("report")}><Icon name="download" size={15} />Report</button>
          <button className="btn btn-ghost" onClick={() => exportCatalog("csv")}><Icon name="download" size={15} />Export</button>
        </div>
      </div>

      {/* catalog status — factual metadata, no vanity headline stat */}
      <div className="cov-strip">
        <div className="cov-item"><span className="cov-val">{COVERAGE.classified.toLocaleString()}</span><span className="cov-lab">classified</span></div>
        <div className="cov-sep" />
        <div className="cov-item"><span className="cov-val">{COVERAGE.sources}</span><span className="cov-lab">active feeds</span></div>
        <div className="cov-sep" />
        <div className="cov-item"><span className="cov-val">~{COVERAGE.freshnessHrs}h</span><span className="cov-lab">median enrich time</span></div>
        <div className="cov-sep" />
        <div className="cov-item"><span className="cov-val">{COVERAGE.lastSync}</span><span className="cov-lab">last sync</span></div>
      </div>

      {/* KPI row — all derived from the customer's uploaded SBOM/HBOM matches */}
      <div className="kpi-row">
        <KpiCard label="Critical · open" value={counts.critOpen} icon="bolt" tone="critical"
          foot="needs triage" onClick={() => onNav("components")} />
        <KpiCard label={"New · last " + winDays + " days"} value={counts.newWin} icon="clock" tone="accent"
          foot="newly published" />
        <KpiCard label="Remediated" value={counts.remediated} icon="check" tone="ok"
          foot="closed this period" />
        <KpiCard label="Total tracked" value={counts.total.toLocaleString()} icon="layers" tone="muted"
          foot="in your SBOM / HBOM" onClick={() => onNav("components")} />
      </div>

      {/* charts grid */}
      <div className="chart-grid">
        <section className="card chart-card">
          <div className="card-head">
            <h3>Severity distribution</h3>
            <span className="card-sub">your SBOM / HBOM</span>
          </div>
          <div className="sev-split">
            <Donut data={sevData} total={totalSev} />
            <div className="sev-legend">
              {sevData.map(d => (
                <div className="sev-leg-row" key={d.label}>
                  <span className="sev-leg-dot" style={{ background: d.color }} />
                  <span className="sev-leg-lab">{d.label}</span>
                  <span className="sev-leg-bar"><span style={{ width: (d.value / totalSev * 100) + "%", background: d.color }} /></span>
                  <span className="sev-leg-val">{d.value}</span>
                </div>
              ))}
            </div>
          </div>
        </section>

        <section className="card chart-card chart-trend">
          <div className="card-head">
            <h3>Ingestion trend</h3>
            <div className="trend-key">
              <span className="tk"><span className="tk-dot" style={{ background: "var(--trend-line)" }} />Vulnerabilities ingested</span>
              <span className="card-sub">12 months</span>
            </div>
          </div>
          <TrendChart trend={TREND} />
        </section>

        <section className="card chart-card">
          <div className="card-head">
            <h3>Top affected ECUs</h3>
            <span className="card-sub">your components</span>
          </div>
          <BarChart data={TOP_ECUS} />
        </section>
      </div>

      {/* priority triage */}
      <section className="card">
        <div className="card-head card-head-row">
          <div>
            <h3>Priority triage queue</h3>
            <span className="card-sub">highest-severity open items, surfaced for fast action</span>
          </div>
          <button className="btn btn-ghost btn-sm" onClick={() => onNav("components")}>
            View components <Icon name="arrowR" size={14} />
          </button>
        </div>
        <div className="triage">
          {priority.length === 0 && (
            <div className="card-empty">
              <Icon name="check" size={22} />
              <span className="card-empty-title">Nothing to triage</span>
              <span className="card-empty-sub">Open, high-severity vulnerabilities from your SBOM appear here.</span>
            </div>
          )}
          {priority.map(v => (
            <button className="triage-row" key={v.id} onClick={() => onOpen(v)}>
              <SeverityTag s={v.severity} cvss={v.cvss} size="sm" />
              <div className="triage-main">
                <div className="triage-top">
                  <span className="triage-id mono">{v.id}</span>
                </div>
                <span className="triage-desc">{v.description}</span>
              </div>
              <div className="triage-meta">
                <span className="triage-ecu">{v.kind === "automotive" ? v.ecu : v.product_name}</span>
                <StatusPill status={statusOf(v)} />
              </div>
              <Icon name="chevR" size={16} className="triage-chev" />
            </button>
          ))}
        </div>
      </section>
    </div>
  );
}

function KpiCard({ label, value, icon, tone, foot, onClick }) {
  return (
    <button className={"kpi kpi-" + tone + (onClick ? " kpi-click" : "")} onClick={onClick} type="button">
      <div className="kpi-top">
        <span className="kpi-ic"><Icon name={icon} size={16} /></span>
        <span className="kpi-label">{label}</span>
      </div>
      <div className="kpi-mid">
        <span className="kpi-value">{value}</span>
      </div>
      <span className="kpi-foot">{foot}</span>
    </button>
  );
}
window.Dashboard = Dashboard;
