/* global React, I */
const { useState: useStateD, useEffect: useEffectD, useRef: useRefD, useMemo: useMemoD } = React;

// ============= Mock data =============
const TARGET = 'shop.meridian.example.com';

const TOOLS = [
{ name: 'Burp Suite Pro', state: 'run', track: 'A', cls: 'burp', progress: 0.62 },
{ name: 'Caido', state: 'run', track: 'A', cls: 'burp', progress: 0.41 },
{ name: 'OWASP ZAP', state: 'run', track: 'A', cls: 'zap', progress: 0.78 },
{ name: 'Nuclei', state: 'run', track: 'A', cls: 'nuclei', progress: 0.55 },
{ name: 'ffuf', state: 'done', track: 'A', cls: 'ffuf', progress: 1.0 },
{ name: 'feroxbuster', state: 'run', track: 'A', cls: 'ffuf', progress: 0.34 },
{ name: 'sqlmap', state: 'run', track: 'B', cls: 'burp', progress: 0.22 },
{ name: 'InQL', state: 'run', track: 'A', cls: 'nuclei', progress: 0.66 },
{ name: 'jwt_tool', state: 'idle', track: 'B', cls: 'burp', progress: 0 },
{ name: 'CIPHER / Web', state: 'run', track: 'AI', cls: 'cipher', progress: 0.71 },
{ name: 'ATLAS Recon', state: 'done', track: 'A', cls: 'recon', progress: 1.0 }];


const FINDINGS = [
{ id: 'F-0042', sev: 'crit', title: 'Auth bypass via header trust on /admin/* routes', target: '/admin/users', src: 'Burp+CIPHER', conf: 0.96, age: '4m', logic: true,
  desc: 'X-Forwarded-For with internal RFC1918 source skips the auth middleware on the admin sub-router.',
  method: 'GET', cwe: 'CWE-287', cvss: 9.1, cipher: true },
{ id: 'F-0041', sev: 'crit', title: 'Blind SQLi in /api/v2/orders search filter', target: '/api/v2/orders', src: 'sqlmap', conf: 0.92, age: '11m',
  method: 'POST', cwe: 'CWE-89', cvss: 9.8 },
{ id: 'F-0040', sev: 'high', title: 'IDOR — order detail readable cross-tenant', target: '/api/v2/orders/{id}', src: 'CIPHER', conf: 0.88, age: '14m', logic: true,
  method: 'GET', cwe: 'CWE-639', cvss: 7.5 },
{ id: 'F-0039', sev: 'high', title: 'JWT alg=none accepted on staging issuer', target: '/auth/token/verify', src: 'jwt_tool', conf: 0.97, age: '22m',
  method: 'POST', cwe: 'CWE-347', cvss: 8.1 },
{ id: 'F-0038', sev: 'high', title: 'Reflected XSS in search?q via DOM sink', target: '/search', src: 'Burp', conf: 0.84, age: '31m',
  method: 'GET', cwe: 'CWE-79', cvss: 7.4 },
{ id: 'F-0037', sev: 'high', title: 'GraphQL introspection enabled in prod', target: '/graphql', src: 'InQL', conf: 0.99, age: '38m',
  method: 'POST', cwe: 'CWE-200', cvss: 7.0 },
{ id: 'F-0036', sev: 'med', title: 'Server-side request forgery — image proxy', target: '/api/img/proxy', src: 'Nuclei', conf: 0.74, age: '44m',
  method: 'GET', cwe: 'CWE-918', cvss: 6.5 },
{ id: 'F-0035', sev: 'med', title: 'Mass assignment on user profile PATCH', target: '/api/v2/me', src: 'CIPHER', conf: 0.69, age: '52m', logic: true,
  method: 'PATCH', cwe: 'CWE-915', cvss: 6.1 },
{ id: 'F-0034', sev: 'med', title: 'Open redirect in /auth/return?to', target: '/auth/return', src: 'ffuf', conf: 0.81, age: '1h',
  method: 'GET', cwe: 'CWE-601', cvss: 5.4 },
{ id: 'F-0033', sev: 'low', title: 'Cookie missing HttpOnly on session_id', target: '/login', src: 'ZAP', conf: 0.99, age: '1h',
  method: 'POST', cwe: 'CWE-1004', cvss: 3.7 },
{ id: 'F-0032', sev: 'low', title: 'Information disclosure: X-Powered-By', target: 'global', src: 'ZAP', conf: 0.99, age: '1h',
  method: '*', cwe: 'CWE-200', cvss: 3.1 },
{ id: 'F-0031', sev: 'info', title: 'TLS 1.0/1.1 advertised on edge', target: 'edge.merid…', src: 'Nuclei', conf: 0.99, age: '2h',
  method: '*', cwe: 'CWE-326', cvss: 0 }];


const SURFACE = [
{ url: 'https://shop.merid.../admin/users', m: 'GET', s: 200, tag: 'pre-auth' },
{ url: 'https://shop.merid.../admin/users/{id}/role', m: 'PUT', s: 401, tag: 'admin' },
{ url: 'https://shop.merid.../api/v2/orders', m: 'POST', s: 200, tag: 'auth' },
{ url: 'https://shop.merid.../api/v2/orders/{id}', m: 'GET', s: 200, tag: 'auth' },
{ url: 'https://shop.merid.../api/v2/me', m: 'PATCH', s: 200, tag: 'auth' },
{ url: 'https://shop.merid.../auth/token/verify', m: 'POST', s: 200, tag: 'auth' },
{ url: 'https://shop.merid.../auth/return', m: 'GET', s: 302, tag: 'redirect' },
{ url: 'https://shop.merid.../graphql', m: 'POST', s: 200, tag: 'graphql' },
{ url: 'https://shop.merid.../search', m: 'GET', s: 200, tag: 'public' },
{ url: 'https://shop.merid.../api/img/proxy', m: 'GET', s: 200, tag: 'proxy' },
{ url: 'https://shop.merid.../debug/healthz', m: 'GET', s: 200, tag: 'leaked' },
{ url: 'https://shop.merid.../legacy/v1/login', m: 'POST', s: 200, tag: 'legacy' }];


// ============= Stream generator =============
const STREAM_TEMPLATES = [
['recon', 'ok', 'subdomain resolved', 'staging.shop.merid.example.com → 10.42.18.7'],
['ffuf', 'ok', 'directory hit', '/admin/  status=302 size=421 redir=/login'],
['ffuf', 'high', 'leaked artefact', '/.env.bak  status=200 size=1.2kb'],
['burp', 'ok', 'crawl', 'sitemap +47 endpoints  hosts=2'],
['nuclei', 'high', 'CVE match', 'CVE-2024-1597  pgbouncer  /api/_diag'],
['nuclei', 'crit', 'exposed panel', 'jenkins  /ci  noauth=true'],
['zap', 'ok', 'passive scan', 'header.csp  weak  /search'],
['burp', 'high', 'sqli candidate', 'param=q  boolean-blind  /search'],
['cipher', 'crit', 'logic candidate', 'F-0042  promoted  conf=0.96'],
['cipher', 'ok', 'noise suppressed', '142 events → category=baseline-tls'],
['cipher', 'ok', 'dedup', '38 burp + 14 zap collapsed → 12 unique'],
['atlas', 'ok', 'session capture', 'macro authflow.macro  ok'],
['recon', 'ok', 'js artefact', '/static/main.7c1f.js  3 endpoints'],
['burp', 'high', 'idor candidate', '/api/v2/orders/{id}  cross-tenant=200'],
['nuclei', 'warn', 'tls drift', 'edge.merid… TLS1.0 advertised'],
['burp', 'ok', 'auth macro', 'login replayed  cookies refreshed'],
['ffuf', 'ok', 'param fuzz', '/search?debug=1 → 200  reflective'],
['cipher', 'ok', 'classified', '/login HttpOnly missing  → low  conf=0.99'],
['atlas', 'ok', 'evidence stored', 'F-0040  req+resp+chain  vault']];


function pickStream() {
  const t = STREAM_TEMPLATES[Math.floor(Math.random() * STREAM_TEMPLATES.length)];
  const ts = new Date();
  const time = ts.toTimeString().slice(0, 8);
  return { time, src: t[0], lvl: t[1], event: t[2], detail: t[3], k: Math.random().toString(36).slice(2) };
}

// ============= Top bar =============
function TopBar({ view, scanRunning, theme, toggleTheme }) {
  const crumbsByView = {
    dashboard: ['ATLAS / Web', 'Engagement'],
    triage: ['CIPHER / Web', 'Triage queue'],
    findings: ['ATLAS / Web', 'Findings'],
    surface: ['ATLAS / Recon', 'Surface map']
  };
  const c = crumbsByView[view] || crumbsByView.dashboard;

  return (
    <div className="topbar">
      <div className="brand">
        <span className="mark" />
        AUTHIFY · ATLAS
      </div>
      <div className="crumbs">
        <span>{c[0]}</span>
        <span className="sep">›</span>
        <span className="cur">{c[1]}</span>
      </div>
      <div className="spacer" />
      <div className="meta">
        <span className="pill">VAULT · sealed</span>
        <span className="pill">{scanRunning ? <><span className="dot" style={{ background: 'var(--accent)' }} />Track A live</> : <><span className="dot" style={{ background: 'var(--text-3)' }} />Track A paused</>}</span>
        <span className={`pill ${scanRunning ? 'live' : ''}`}><span className="dot" />CIPHER {scanRunning ? 'classifying' : 'standby'}</span>
        <span className="pill">ROE · expires 11d</span>
        <button className="theme-toggle" onClick={toggleTheme} title={theme === 'dark' ? 'Switch to light' : 'Switch to dark'} aria-label="toggle theme">
          {theme === 'dark' ?
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="4" /><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" /></svg> :

          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /></svg>
          }
        </button>
      </div>
    </div>);

}

// ============= Status bar =============
function StatusBar({ scanRunning, eventCount, findingsCount }) {
  return (
    <div className="statusbar">
      <span className="seg"><span className="dot" />VPN · sg-edge-03</span>
      <span className="seg"><span className="dot" />proxy · burp:8080 · caido:9090</span>
      <span className={`seg ${scanRunning ? '' : 'warn'}`}><span className="dot" />{scanRunning ? 'engagement live' : 'engagement paused'}</span>
      <span className="seg crit"><span className="dot" />{findingsCount} findings · {eventCount} events</span>
      <span className="spacer" />
      <span>main · clean</span>
      <span>UTC+09:00</span>
      <span><span className="kbd">⌘K</span> command</span>
    </div>);

}

// ============= Dashboard =============
function Dashboard({ scanRunning, toggleScan, stream, openTriage, openFinding }) {
  const streamRef = useRefD(null);
  useEffectD(() => {
    if (streamRef.current) streamRef.current.scrollTop = 0;
  }, [stream.length]);

  const sevCounts = useMemoD(() => {
    const c = { crit: 0, high: 0, med: 0, low: 0, info: 0 };
    FINDINGS.forEach((f) => c[f.sev]++);
    return c;
  }, []);

  const heatBars = useMemoD(() => {
    return Array.from({ length: 24 }).map((_, i) => ({
      crit: Math.max(0, Math.round(20 + Math.sin(i * 0.6) * 14 + Math.random() * 10)),
      high: Math.max(0, Math.round(28 + Math.cos(i * 0.4) * 12 + Math.random() * 12)),
      med: Math.max(0, Math.round(36 + Math.sin(i * 0.8) * 18 + Math.random() * 14))
    }));
  }, []);

  return (
    <>
      <div className="section-head">
        <div>
          <h1>
            <span className="tag">VAPT.WEB</span>
            ENG-2026-0418 · merid commerce platform
          </h1>
          <div className="sub">scope: shop.merid.example.com · 47 hosts · 2,841 endpoints · day 03 / 14</div>
        </div>
        <div className="actions">
          <button className="btn ghost"><I.refresh /> Re-scope</button>
          <button className="btn ghost"><I.download /> Export</button>
          <button className={`btn ${scanRunning ? 'danger' : 'primary'}`} onClick={toggleScan}>
            {scanRunning ? <><I.pause /> Pause Track A</> : <><I.play /> Resume Track A</>}
          </button>
        </div>
      </div>

      <div className="content">
        {/* Metrics */}
        <div className="metrics">
          <div className="metric crit">
            <div className="label">CRITICAL</div>
            <div className="value">{sevCounts.crit}</div>
            <div className="delta up">+1 in last 4m</div>
          </div>
          <div className="metric">
            <div className="label">HIGH</div>
            <div className="value">{sevCounts.high}</div>
            <div className="delta">+2 in last 30m</div>
          </div>
          <div className="metric">
            <div className="label">MEDIUM</div>
            <div className="value">{sevCounts.med}</div>
            <div className="delta">+1 in last hour</div>
          </div>
          <div className="metric">
            <div className="label">CIPHER QUEUE</div>
            <div className="value" style={{ color: 'var(--accent)' }}>17</div>
            <div className="delta">awaiting reviewer</div>
          </div>
          <div className="metric">
            <div className="label">SURFACE / ENDPOINTS</div>
            <div className="value">2,841</div>
            <div className="delta ok">+312 since Mon</div>
          </div>
        </div>

        {/* Toolchain row */}
        <div className="panel" style={{ marginBottom: 12 }}>
          <div className="panel-head">
            <div className="title"><I.bolt /> TOOLCHAIN · {scanRunning ? 'ACTIVE' : 'PAUSED'}</div>
            <div className="actions"><span className="lnk">configure</span></div>
          </div>
          <div className="panel-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            <div className="chips">
              {TOOLS.map((t) =>
              <span key={t.name} className={`chip ${scanRunning && t.state === 'run' ? 'run' : t.state}`}>
                  <span className="dot" />{t.name}
                  <span style={{ color: 'var(--text-3)' }}>· {t.track}</span>
                </span>
              )}
            </div>
            <div className="progress">
              <span>active scan</span>
              <div className="bar"><i style={{ width: scanRunning ? '63%' : '63%' }} /></div>
              <span>63% · 1,792 / 2,841 endpoints · ETA 2h 14m</span>
            </div>
          </div>
        </div>

        {/* Two columns: stream + side */}
        <div className="grid-2" style={{ marginBottom: 12 }}>
          <div className="panel">
            <div className="panel-head">
              <div className="title"><I.list /> LIVE EVENT STREAM</div>
              <div className="actions">
                <span className="lnk">Burp</span>
                <span className="lnk">ZAP</span>
                <span className="lnk">Nuclei</span>
                <span className="lnk">CIPHER</span>
                <span className="lnk" style={{ color: 'var(--text-0)' }}>all ✓</span>
              </div>
            </div>
            <div className="stream" ref={streamRef}>
              {stream.map((e, i) =>
              <div key={e.k} className={`ln ${e.lvl} ${i === 0 ? 'entry' : ''}`}>
                  <span className="t">{e.time}</span>
                  <span className={`src ${e.src}`}>[{e.src.toUpperCase()}]</span>
                  <span><b style={{ fontWeight: 500 }}>{e.event}</b> <span style={{ color: 'var(--text-2)' }}>· {e.detail}</span></span>
                </div>
              )}
            </div>
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            <div className="panel">
              <div className="panel-head">
                <div className="title"><I.brain /> CIPHER · TRIAGE LOAD</div>
                <div className="actions"><span className="lnk" onClick={openTriage}>open queue ↗</span></div>
              </div>
              <div className="panel-body">
                <div className="donut-wrap">
                  <Donut data={[
                  { v: 17, c: '#ff5577', l: 'live' },
                  { v: 9, c: '#fbbf24', l: 'suspect' },
                  { v: 24, c: '#7aa2ff', l: 'duplicates' },
                  { v: 812, c: '#3a3f48', l: 'noise' }]
                  } />
                  <div className="donut-legend" style={{ flex: 1 }}>
                    <div className="row"><span className="sw" style={{ background: '#ff5577' }} />live (escalate) <span className="v">17</span></div>
                    <div className="row"><span className="sw" style={{ background: '#fbbf24' }} />suspect <span className="v">9</span></div>
                    <div className="row"><span className="sw" style={{ background: '#7aa2ff' }} />duplicates <span className="v">24</span></div>
                    <div className="row"><span className="sw" style={{ background: '#3a3f48' }} />suppressed <span className="v">812</span></div>
                  </div>
                </div>
              </div>
            </div>

            <div className="panel">
              <div className="panel-head">
                <div className="title"><I.target /> ATTACK SURFACE</div>
                <div className="actions"><span className="lnk">map ↗</span></div>
              </div>
              <div className="panel-body" style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
                <SurfaceStat k="subdomains" v="47" />
                <SurfaceStat k="endpoints" v="2,841" />
                <SurfaceStat k="parameters" v="184" />
                <SurfaceStat k="js bundles" v="312" />
                <SurfaceStat k="archived" v="2,840" />
                <SurfaceStat k="hidden routes" v="29" hi />
              </div>
            </div>
          </div>
        </div>

        {/* Findings activity */}
        <div className="grid-2">
          <div className="panel">
            <div className="panel-head">
              <div className="title"><I.bug /> FINDINGS · LAST 24H</div>
              <div className="actions"><span className="lnk">view all ↗</span></div>
            </div>
            <div className="panel-body" style={{ borderWidth: "0px", borderStyle: "solid", padding: "90px 12px 12px" }}>
              <div className="barchart" style={{ padding: "90px 0px 8px" }}>
                {heatBars.map((b, i) =>
                <div key={i} className="col" title={`${i}:00`}>
                    <div className="b crit" style={{ height: b.crit + 'px' }} />
                    <div className="b high" style={{ height: b.high + 'px' }} />
                    <div className="b med" style={{ height: b.med + 'px' }} />
                    <span className="l">{i % 4 === 0 ? `${i.toString().padStart(2, '0')}` : ''}</span>
                  </div>
                )}
              </div>
              <div className="donut-legend" style={{ display: 'flex', gap: 14, marginTop: 6 }}>
                <span><span className="sw" style={{ background: '#ff5577', display: 'inline-block', width: 8, height: 8, marginRight: 6 }} />critical</span>
                <span><span className="sw" style={{ background: '#ff8a4c', display: 'inline-block', width: 8, height: 8, marginRight: 6 }} />high</span>
                <span><span className="sw" style={{ background: '#fbbf24', display: 'inline-block', width: 8, height: 8, marginRight: 6 }} />medium</span>
              </div>
            </div>
          </div>

          <div className="panel">
            <div className="panel-head">
              <div className="title"><I.flag /> TOP CIPHER ESCALATIONS</div>
              <div className="actions"><span className="lnk" onClick={openTriage}>queue ↗</span></div>
            </div>
            <div className="panel-body flush">
              {FINDINGS.filter((f) => f.cipher || f.logic).slice(0, 4).map((f) =>
              <div key={f.id} className="cipher-row" style={{ cursor: 'pointer' }} onClick={() => openFinding(f.id)}>
                  <span className={`badge ${f.sev === 'crit' ? 'live' : 'suspect'}`}>{f.sev.toUpperCase()}</span>
                  <div className="body">
                    <div className="h">{f.title}</div>
                    <div className="reason">{f.id} · {f.target} · src {f.src} · conf {(f.conf * 100).toFixed(0)}%</div>
                  </div>
                  <span style={{ color: 'var(--text-3)' }}><I.chevR /></span>
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </>);

}

function SurfaceStat({ k, v, hi }) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '6px 0', borderBottom: '1px dashed var(--line)', fontFamily: 'var(--font-mono)', fontSize: 11 }}>
      <span style={{ color: 'var(--text-2)', textTransform: 'uppercase', fontSize: 10, letterSpacing: '0.08em' }}>{k}</span>
      <span style={{ color: hi ? 'var(--accent)' : 'var(--text-0)', fontSize: 16, fontWeight: 600 }}>{v}</span>
    </div>);

}

function Donut({ data }) {
  const total = data.reduce((a, b) => a + b.v, 0);
  let acc = 0;
  const r = 32,c = 44,stroke = 12;
  return (
    <svg className="donut" viewBox="0 0 88 88">
      <circle cx={c} cy={c} r={r} fill="none" stroke="#1b1f26" strokeWidth={stroke} />
      {data.map((d, i) => {
        const frac = d.v / total;
        const dash = 2 * Math.PI * r * frac;
        const gap = 2 * Math.PI * r - dash;
        const rot = acc / total * 360 - 90;
        acc += d.v;
        return (
          <circle key={i} cx={c} cy={c} r={r} fill="none" stroke={d.c} strokeWidth={stroke}
          strokeDasharray={`${dash} ${gap}`} transform={`rotate(${rot} ${c} ${c})`} />);

      })}
      <text x="44" y="42" textAnchor="middle" fill="#e8eaed" fontFamily="var(--font-mono)" fontSize="14" fontWeight="600">{total}</text>
      <text x="44" y="55" textAnchor="middle" fill="#6b7280" fontFamily="var(--font-mono)" fontSize="8" letterSpacing="0.1em">EVENTS</text>
    </svg>);

}

window.Dashboard = Dashboard;
window.TopBar = TopBar;
window.StatusBar = StatusBar;
window.FINDINGS = FINDINGS;
window.SURFACE = SURFACE;
window.pickStream = pickStream;