// screen_components.jsx — Components inventory (list) + component detail page.
function catMeta(id) { return window.VC.COMPONENT_CATEGORIES.find(c => c.id === id) || { label: id, icon: "package" }; }

function ComponentsScreen({ components, loading, onNew, onOpen }) {
  if (loading && (!components || components.length === 0))
    return <PageLoading label="Loading components…" />;
  return (
    <div className="page">
      <div className="page-head">
        <div>
          <span className="eyebrow">Inventory</span>
          <h1 className="page-title">Components</h1>
          <p className="page-desc">Monitored vehicle components with an uploaded SBOM. VulnerabilityCore correlates each inventory against the live CVE ledger.</p>
        </div>
        <div className="page-head-aside">
          <button className="btn btn-accent" onClick={onNew}><Icon name="plus" size={15} />New component</button>
        </div>
      </div>

      {components.length === 0 ? (
        <div className="card empty-card">
          <div className="empty">
            <Icon name="package" size={26} />
            <p>No components yet</p>
            <span className="empty-sub">Upload an SBOM and VulnerabilityCore will correlate each component against the live CVE ledger.</span>
            <button className="btn btn-accent" onClick={onNew}><Icon name="plus" size={15} />New component</button>
          </div>
        </div>
      ) : (
      <div className="ent-grid">
        {components.map(c => {
          const cat = catMeta(c.category);
          // Prefer the backend's real, precomputed matches; fall back to the
          // client-side correlation engine (used for not-yet-saved components).
          const matches = Array.isArray(c.matches) ? c.matches : window.VC.correlateSbom(c.libs);
          const sev = window.VC.matchSeverity(matches);
          const maxCvss = matches.length ? Math.max(...matches.map(m => m.vuln.cvss)) : 0;
          return (
            <button key={c.id} className="entcard compcard" onClick={() => onOpen(c)}>
              <div className="entcard-top">
                <span className="entcard-avatar"><Icon name={cat.icon} size={18} /></span>
                <div className="entcard-id">
                  <span className="entcard-name">{c.name}</span>
                  <span className="entcard-meta">{cat.label} · {c.supplier}</span>
                </div>
                <span className="entcard-arrow"><Icon name="chevR" size={16} /></span>
              </div>
              <div className="entcard-stats">
                <div className="entcard-stat"><b>{c.libs.length}</b><span>components</span></div>
                <div className="entcard-stat"><b className={matches.length ? "is-warn" : ""}>{matches.length}</b><span>CVE matches</span></div>
                <div className="entcard-stat"><b className="mono">{maxCvss ? maxCvss.toFixed(1) : "—"}</b><span>max CVSS</span></div>
              </div>
              {matches.length > 0 ? (
                <>
                  <div className="entcard-bar">
                    {SEV_ORDER.map(s => sev[s] > 0 && (
                      <span key={s} className={"entcard-seg " + sevClass(s)} style={{ flex: sev[s] }} title={`${sev[s]} ${s}`} />
                    ))}
                  </div>
                  <div className="entcard-legend">
                    {SEV_ORDER.filter(s => sev[s] > 0).map(s => (
                      <span key={s} className="entcard-leg"><span className={"chip-dot " + sevClass(s)} />{sev[s]} {s}</span>
                    ))}
                  </div>
                </>
              ) : (
                <div className="compcard-clean"><Icon name="check" size={14} />No matching CVEs</div>
              )}
              <div className="compcard-foot">
                <span className="mono">{c.sbomName}</span>
                <span>{c.brands.length} OEM{c.brands.length !== 1 ? "s" : ""}</span>
              </div>
            </button>
          );
        })}
      </div>
      )}
    </div>
  );
}

function ComponentDetail({ comp, statusOf, onBack, onOpenVuln, onUpdateSbom }) {
  const cat = catMeta(comp.category);
  const matches = Array.isArray(comp.matches) ? comp.matches : window.VC.correlateSbom(comp.libs);
  const sev = window.VC.matchSeverity(matches);
  const maxCvss = matches.length ? Math.max(...matches.map(m => m.vuln.cvss)) : 0;
  const st = statusOf || ((v) => v.status);
  const remediated = (comp.remediatedIds || []).map(id => window.VC.VULNS.find(v => v.id === id)).filter(Boolean);

  // Styled HTML report scoped to this component's SBOM matches (the same
  // masthead design used by the ledger/dashboard reports).
  function exportComponentReport() {
    const list = matches.map(({ vuln, lib }) => ({
      ...vuln,
      library_name: lib.name + (lib.version ? "@" + lib.version : ""),
    }));
    window.VCExport.report(list, {
      target: comp.name + " · " + comp.supplier + " · " + comp.sbomName,
      statusOf: st,
      filename: (comp.name || "component").toLowerCase().replace(/[^a-z0-9]+/g, "-") + "-report",
    });
  }

  return (
    <div className="page detail">
      <button className="back" onClick={onBack}><Icon name="arrowL" size={16} />Components</button>

      <div className="detail-head-main">
        <div className="detail-id-row">
          <span className="kindtag kindtag-auto"><Icon name={cat.icon} size={12} />{cat.label}</span>
          <span className="detail-src">{comp.spec} · added {comp.createdAt}</span>
        </div>
        <h1 className="detail-id">{comp.name}</h1>
        <div className="detail-tags">
          <span className="dtag"><Icon name="layers" size={13} />{comp.supplier}</span>
          {comp.brands.map(b => <span className="dtag" key={b}><Icon name="car" size={13} />{b}</span>)}
          <span className="dtag"><Icon name="doc" size={13} />{comp.sbomName}</span>
          {comp.lastUpdated && <span className="dtag"><Icon name="refresh" size={13} />updated {comp.lastUpdated}</span>}
        </div>
      </div>

      <div className="detail-grid">
        <div className="detail-main">
          <section className="dsec">
            <div className="dsec-head">
              <span className="dsec-ic"><Icon name="sparkle" size={16} /></span>
              <h3>Matched vulnerabilities</h3>
              <div className="dsec-head-aside">
                <span className="dsec-kick">{matches.length} found</span>
                <button className="btn btn-sm" onClick={exportComponentReport}><Icon name="download" size={14} />Report</button>
              </div>
            </div>
            {matches.length === 0 ? (
              <div className="empty"><Icon name="check" size={22} /><p>No tracked CVEs match this SBOM yet.</p></div>
            ) : (
              <div className="ent-list comp-matchlist">
                {matches.map(({ vuln, lib }) => (
                  <button className="ent-row" key={vuln.id} onClick={() => onOpenVuln(vuln)}>
                    <SeverityTag s={vuln.severity} cvss={vuln.cvss} size="sm" />
                    <span className="ent-row-id mono">{vuln.id}</span>
                    <span className="ent-row-desc">{vuln.description}</span>
                    <span className="ent-row-comp mono">via {lib.name}@{lib.version}</span>
                    <StatusPill status={st(vuln)} />
                    <Icon name="chevR" size={15} className="ent-row-chev" />
                  </button>
                ))}
              </div>
            )}
          </section>

          {remediated.length > 0 && (
            <section className="dsec">
              <div className="dsec-head">
                <span className="dsec-ic dsec-ic-ok"><Icon name="check" size={16} /></span>
                <h3>Remediated via SBOM update</h3>
                <span className="dsec-kick">{remediated.length} resolved</span>
              </div>
              <div className="ent-list comp-matchlist">
                {remediated.map(v => (
                  <button className="ent-row ent-row-rem" key={v.id} onClick={() => onOpenVuln(v)}>
                    <SeverityTag s={v.severity} cvss={v.cvss} size="sm" />
                    <span className="ent-row-id mono">{v.id}</span>
                    <span className="ent-row-desc">{v.description}</span>
                    <span className="ent-row-comp">fixed in current SBOM</span>
                    <StatusPill status="remediated" />
                    <Icon name="chevR" size={15} className="ent-row-chev" />
                  </button>
                ))}
              </div>
            </section>
          )}

          <section className="dsec">
            <div className="dsec-head">
              <span className="dsec-ic"><Icon name="doc" size={16} /></span>
              <h3>SBOM inventory</h3>
              <div className="dsec-head-aside">
                <span className="dsec-kick">{comp.libs.length} components</span>
                <button className="btn btn-sm" onClick={() => onUpdateSbom(comp)}><Icon name="refresh" size={14} />Update SBOM</button>
              </div>
            </div>
            <div className="liblist liblist-flat">
              {comp.libs.map((l, i) => {
                const cves = window.VC.libVulnCount(l);
                return (
                  <div className={"librow" + (cves ? " is-flagged" : "")} key={i}>
                    <span className="librow-name mono">{l.name}<span className="librow-ver"> @{l.version}</span></span>
                    <span className="librow-sup">{l.supplier}</span>
                    <span className="librow-type">{l.type}</span>
                    {cves > 0
                      ? <span className="librow-cve"><Icon name="alert" size={12} />{cves}</span>
                      : <span className="librow-ok"><Icon name="check" size={12} /></span>}
                  </div>
                );
              })}
            </div>
          </section>
        </div>

        <div className="detail-side">
          <section className="dsec side-card">
            <span className="side-title">Risk summary</span>
            <div className="comp-risk">
              <div className="comp-risk-big"><b>{matches.length}</b><span>matched CVEs</span></div>
              <div className="comp-risk-big"><b className="mono">{maxCvss ? maxCvss.toFixed(1) : "—"}</b><span>max CVSS</span></div>
            </div>
            {matches.length > 0 && (
              <div className="comp-sevrows">
                {SEV_ORDER.filter(s => sev[s] > 0).map(s => (
                  <div className="comp-sevrow" key={s}>
                    <span className={"chip-dot " + sevClass(s)} /><span className="comp-sevrow-lab">{s}</span><b className="mono">{sev[s]}</b>
                  </div>
                ))}
              </div>
            )}
          </section>

          <section className="dsec side-card">
            <span className="side-title">Attribution</span>
            <div className="metaline"><span>Supplier</span><b>{comp.supplier}</b></div>
            <div className="metaline"><span>Category</span><b>{cat.label}</b></div>
            <div className="metaline"><span>SBOM format</span><b>{comp.spec}</b></div>
            <div className="rev-brands-lab">OEM</div>
            <div className="reglist">{comp.brands.map(b => <span className="reg" key={b}>{b}</span>)}</div>
          </section>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ComponentsScreen, ComponentDetail });
