/* global React, I, FINDINGS */
const { useState: useStateT, useMemo: useMemoT } = React;

function Triage({ openFinding, scanRunning }) {
  const [filter, setFilter] = useStateT('live');
  const [selected, setSelected] = useStateT(new Set(['F-0042']));
  const [query, setQuery] = useStateT('');

  const items = useMemoT(() => {
    return FINDINGS.map(f => {
      let cat = 'live';
      if (f.sev === 'low' || f.sev === 'info') cat = 'noise';
      else if (f.conf < 0.8) cat = 'suspect';
      if (['F-0033', 'F-0032'].includes(f.id)) cat = 'dup';
      return { ...f, cat };
    });
  }, []);

  const filtered = items.filter(f => {
    if (filter !== 'all' && f.cat !== filter) return false;
    if (query && !(f.title + f.target + f.id).toLowerCase().includes(query.toLowerCase())) return false;
    return true;
  });

  const toggle = (id) => {
    const n = new Set(selected);
    if (n.has(id)) n.delete(id); else n.add(id);
    setSelected(n);
  };

  const counts = {
    all: items.length,
    live: items.filter(i => i.cat === 'live').length,
    suspect: items.filter(i => i.cat === 'suspect').length,
    dup: items.filter(i => i.cat === 'dup').length,
    noise: items.filter(i => i.cat === 'noise').length,
  };

  const reasonFor = (f) => {
    if (f.cat === 'live') {
      if (f.logic) return 'business-logic candidate · matches prior eng pattern · not in noise corpus';
      return 'high-confidence vuln · cross-validated by 2 tools · not deduped';
    }
    if (f.cat === 'suspect') return 'low-confidence signal · needs Track B reviewer eyes';
    if (f.cat === 'dup')     return 'collapsed: 38 burp + 14 zap → 1 unique · same root cause';
    return `customer-stack baseline · suppressed at category=${f.cwe?.toLowerCase()}`;
  };

  return (
    <>
      <div className="section-head">
        <div>
          <h1>
            <span className="tag">CIPHER · WEB</span>
            Triage queue
          </h1>
          <div className="sub">AI classification over Burp · Caido · ZAP · Nuclei output · suppressing customer-stack noise</div>
        </div>
        <div className="actions">
          <button className="btn ghost"><I.refresh/> Re-classify</button>
          <button className="btn"><I.download/> Export queue</button>
          <button className="btn primary" disabled={!selected.size}>
            <I.check/> Promote {selected.size || ''} to Track B
          </button>
        </div>
      </div>

      <div className="list-toolbar">
        <input type="text" placeholder="filter by title, target, CWE…" value={query} onChange={e => setQuery(e.target.value)}/>
        <div className="seg-group">
          {[
            ['live', `live (${counts.live})`],
            ['suspect', `suspect (${counts.suspect})`],
            ['dup', `dups (${counts.dup})`],
            ['noise', `noise (${counts.noise})`],
            ['all', `all (${counts.all})`],
          ].map(([k, l]) => (
            <button key={k} className={filter === k ? 'on' : ''} onClick={() => setFilter(k)}>{l}</button>
          ))}
        </div>
        <div className="spacer"/>
        <span style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-2)' }}>
          {scanRunning ? <span style={{ color: 'var(--accent)' }}>● live</span> : '○ paused'} · model cipher-web-2026.04.r3 · learned from 312 prior eng
        </span>
      </div>

      <div className="content" style={{ padding: 0, display: 'grid', gridTemplateColumns: '1fr 380px' }}>
        <div style={{ borderRight: '1px solid var(--line)' }}>
          {filtered.map(f => (
            <div key={f.id} className="cipher-row" style={{ cursor: 'pointer', background: selected.has(f.id) ? 'var(--bg-2)' : '' }}>
              <span className="check" onClick={() => toggle(f.id)} style={{
                width: 14, height: 14,
                border: `1px solid ${selected.has(f.id) ? 'var(--accent)' : 'var(--line-2)'}`,
                borderRadius: 3,
                background: selected.has(f.id) ? 'var(--accent)' : 'transparent',
                color: '#1a0008',
                display: 'flex', alignItems: 'center', justifyContent: 'center',
                flexShrink: 0,
              }}>
                {selected.has(f.id) && <I.check/>}
              </span>
              <span className={`badge ${f.cat}`}>
                {f.cat === 'live' ? 'LIVE' : f.cat === 'suspect' ? 'SUSPECT' : f.cat === 'dup' ? 'DUPLICATE' : 'NOISE'}
              </span>
              <div className="body" onClick={() => openFinding(f.id)}>
                <div className="h">
                  {f.logic && <span style={{ color: 'var(--accent)', marginRight: 6, fontSize: 10, border: '1px solid var(--accent-line)', padding: '0 4px', borderRadius: 2, letterSpacing: '0.06em' }}>LOGIC</span>}
                  {f.title}
                </div>
                <div className="reason">
                  <span style={{ color: 'var(--text-1)' }}>{f.id}</span>
                  &nbsp;· {f.target} · {f.src} · {f.cwe} · CVSS {f.cvss || '—'} · conf {(f.conf*100).toFixed(0)}% · {f.age}
                </div>
                <div className="reason" style={{ color: 'var(--text-1)', marginTop: 6, paddingTop: 6, borderTop: '1px dashed var(--line)' }}>
                  <span style={{ color: 'var(--accent)' }}>cipher:</span> {reasonFor(f)}
                </div>
              </div>
              <div className="actions">
                <button className="iconbtn acc" title="Promote"><I.check/></button>
                <button className="iconbtn" title="Suppress"><I.x/></button>
                <button className="iconbtn" title="More"><I.more/></button>
              </div>
            </div>
          ))}
          {!filtered.length && <div className="empty">no items in this bucket</div>}
        </div>

        <aside style={{ padding: 14, display: 'flex', flexDirection: 'column', gap: 12, overflowY: 'auto', background: 'var(--bg-1)' }}>
          <div className="cipher-narr" style={{ border: '1px solid var(--accent-line)' }}>
            <div className="head"><span className="dot"/>CIPHER · QUEUE BRIEF</div>
            <p>Pass <code>2026.04.r3</code> over <b>1,184 raw events</b> in the last 24h.</p>
            <p>Suppressed <b>812</b> as customer-stack baseline (HSTS preload, X-Powered-By, framework defaults).</p>
            <p>Collapsed <b>38 Burp + 14 ZAP</b> entries into <b>12 unique</b> findings via request-fingerprint dedup.</p>
            <p>Promoted <code style={{ color: 'var(--accent)' }}>17</code> as live, surfaced <code>9</code> business-logic candidates that scanner heuristics deprioritised — these need a human eye on Track B.</p>
            <div className="conf-row"><span>queue health</span><div className="bar"><i style={{ width: '88%' }}/></div><span style={{ color: 'var(--accent)' }}>0.88</span></div>
          </div>

          <div className="panel">
            <div className="panel-head"><div className="title">SOURCES</div></div>
            <div className="panel-body">
              <SrcRow name="Burp Suite Pro" raw={428} promoted={6}/>
              <SrcRow name="Caido"           raw={211} promoted={3}/>
              <SrcRow name="OWASP ZAP"       raw={297} promoted={2}/>
              <SrcRow name="Nuclei"          raw={184} promoted={4}/>
              <SrcRow name="ffuf / ferox"    raw={32}  promoted={1}/>
              <SrcRow name="sqlmap"          raw={4}   promoted={1}/>
              <SrcRow name="jwt_tool"        raw={2}   promoted={1}/>
              <SrcRow name="InQL"            raw={26}  promoted={0}/>
            </div>
          </div>

          <div className="panel">
            <div className="panel-head"><div className="title">ESCALATION TIPS</div></div>
            <div className="panel-body" style={{ fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-1)', lineHeight: 1.6 }}>
              <div style={{ paddingBottom: 8, borderBottom: '1px dashed var(--line)' }}>
                <b style={{ color: 'var(--accent)' }}>F-0042</b> — auth bypass via header trust. Two-tester chain. Cross-checks Caido replay collection <code>admin-bypass-v2</code>.
              </div>
              <div style={{ padding: '8px 0', borderBottom: '1px dashed var(--line)' }}>
                <b style={{ color: 'var(--accent)' }}>F-0040</b> — IDOR likely also affects <code>/invoices/{`{id}`}</code>; not yet probed.
              </div>
              <div style={{ paddingTop: 8 }}>
                <b style={{ color: 'var(--accent)' }}>F-0035</b> — mass assignment may cascade to <code>role</code> field; test with non-admin token.
              </div>
            </div>
          </div>
        </aside>
      </div>
    </>
  );
}

function SrcRow({ name, raw, promoted }) {
  const ratio = promoted / raw;
  return (
    <div style={{ display: 'grid', gridTemplateColumns: '1fr 60px 60px', gap: 8, padding: '5px 0', fontFamily: 'var(--font-mono)', fontSize: 11, color: 'var(--text-1)', borderBottom: '1px dashed var(--line)', alignItems: 'center' }}>
      <span style={{ color: 'var(--text-0)' }}>{name}</span>
      <span style={{ color: 'var(--text-2)', textAlign: 'right' }}>{raw} raw</span>
      <span style={{ color: promoted ? 'var(--accent)' : 'var(--text-3)', textAlign: 'right' }}>
        {promoted ? `${promoted} live` : '—'}
      </span>
    </div>
  );
}

window.Triage = Triage;
