/* global React, I, FINDINGS */
const { useState: useStateV } = React;
const CodeV = ({ html, style }) => (
  <pre className="code" style={style} dangerouslySetInnerHTML={{ __html: html }}/>
);

// ============ Vulnerabilities filtered by category ============
function VulnCategory({ kind }) {
  const map = {
    'vulns.injection': { tag:'INJECTION', sub:'sqlmap · ffuf · Burp · time-based + boolean-blind', filter: f => /SQLi|injection|sqli/i.test(f.title) },
    'vulns.xss':       { tag:'XSS / DOM', sub:'reflected · stored · DOM-based · CSP-aware', filter: f => /XSS|DOM/i.test(f.title) },
    'vulns.ssrf':      { tag:'SSRF / RCE', sub:'image proxy · webhook · OOB exfil patterns', filter: f => /SSRF|RCE|forgery/i.test(f.title) },
    'vulns.idor':      { tag:'IDOR', sub:'cross-tenant · sequential ID · UUID guessing', filter: f => /IDOR|tenant|cross-tenant/i.test(f.title) },
    'vulns.cve':       { tag:'KNOWN CVES', sub:'Nuclei templates · vendor advisories · pinned CVE database', filter: f => /CVE|introspection|TLS/i.test(f.title) },
  };
  const m = map[kind] || map['vulns.injection'];
  const items = FINDINGS.filter(m.filter);
  return (
    <>
      <div className="section-head">
        <div><h1><span className="tag">VAPT.WEB</span>{m.tag}</h1>
          <div className="sub">{m.sub}</div></div>
        <div className="actions">
          <button className="btn ghost"><I.refresh/> Re-run</button>
          <button className="btn primary"><I.play/> Replay payloads</button>
        </div>
      </div>
      <div className="content" style={{padding:0}}>
        <div className="findings-head">
          <span></span><span>SEV</span><span>FINDING</span><span>TARGET</span><span>SOURCE</span><span>CONF</span><span>AGE</span>
        </div>
        <div className="findings">
          {items.length ? items.map(f => (
            <div key={f.id} className="finding">
              <span className="check"/>
              <span className={`sev ${f.sev}`}>{f.sev}</span>
              <span className="title">{f.cipher && <span className="badge">CIPHER</span>}{f.title}</span>
              <span className="target">{f.target}</span>
              <span className="src">{f.src}</span>
              <span className="conf"><div className="bar"><i style={{width:`${f.conf*100}%`}}/></div>{(f.conf*100).toFixed(0)}%</span>
              <span className="age">{f.age}</span>
            </div>
          )) : <div className="empty">no findings in this category yet — Track A still scanning</div>}
        </div>
      </div>
    </>
  );
}

// ============ Auth & Logic ============
function AuthView({ kind }) {
  const titles = {
    'auth.bypass':   ['Auth bypass', 'header-trust · IP allowlist drift · stage cookie reuse'],
    'auth.authz':    ['Authorization / IDOR', 'object-level + function-level access control'],
    'auth.session':  ['Session flaws', 'cookie scope · fixation · idle timeout · concurrent session'],
    'auth.jwt':      ['JWT analysis', 'alg confusion · key confusion · kid injection · weak HMAC'],
    'auth.workflow': ['Workflow logic', 'multi-step abuse · race conditions · price tampering'],
  };
  const [t, sub] = titles[kind] || titles['auth.bypass'];

  if (kind === 'auth.jwt') return <JwtView/>;

  return (
    <>
      <div className="section-head">
        <div><h1><span className="tag">VAPT.WEB</span>{t}</h1><div className="sub">{sub}</div></div>
        <div className="actions"><button className="btn primary"><I.play/> Run probe set</button></div>
      </div>
      <div className="content">
        <div className="grid-2">
          <div className="panel">
            <div className="panel-head"><div className="title">PROBE MATRIX</div></div>
            <div className="panel-body" style={{padding:0}}>
              {[
                ['header-trust', 'X-Forwarded-For RFC1918', 'positive · F-0042', 'crit'],
                ['IP allowlist',  'edge bypass via Host', 'no-signal', 'ok'],
                ['stage cookie',  'staging cookie on prod',  'no-signal', 'ok'],
                ['session reuse', 'pre-logout token replay', 'positive · drift', 'high'],
                ['CSRF token',    'token rotation on PATCH', 'no-signal', 'ok'],
                ['MFA enrolment', 'force-skip via X-Skip-MFA','no-signal', 'ok'],
              ].map((r,i)=>(
                <div key={i} style={{display:'grid',gridTemplateColumns:'1fr 1.4fr 1fr',padding:'8px 12px',borderBottom:'1px solid var(--line)',fontFamily:'var(--font-mono)',fontSize:11}}>
                  <span style={{color:'var(--text-0)'}}>{r[0]}</span>
                  <span style={{color:'var(--text-2)'}}>{r[1]}</span>
                  <span style={{color:r[3]==='crit'?'var(--accent)':r[3]==='high'?'var(--high)':'var(--ok)',textAlign:'right'}}>{r[2]}</span>
                </div>
              ))}
            </div>
          </div>
          <div className="panel">
            <div className="panel-head"><div className="title">CIPHER · LOGIC CANDIDATES</div></div>
            <div className="panel-body flush">
              {FINDINGS.filter(f => f.logic).map(f => (
                <div key={f.id} className="cipher-row">
                  <span className={`badge live`}>{f.sev.toUpperCase()}</span>
                  <div className="body">
                    <div className="h">{f.title}</div>
                    <div className="reason">{f.id} · {f.target} · conf {(f.conf*100).toFixed(0)}%</div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>
    </>
  );
}

function JwtView() {
  return (
    <>
      <div className="section-head">
        <div><h1><span className="tag">VAPT.WEB</span>JWT analysis</h1>
          <div className="sub">jwt_tool · alg confusion · key confusion · kid injection · weak HMAC cracking</div></div>
        <div className="actions"><button className="btn primary"><I.play/> Re-run jwt_tool</button></div>
      </div>
      <div className="content">
        <div className="panel" style={{marginBottom:12}}>
          <div className="panel-head"><div className="title">CAPTURED TOKEN · /auth/token/verify</div></div>
          <CodeV style={{maxHeight:200}} html={`<span class="c">// header (decoded)</span>
{ <span class="h">"alg"</span>: <span class="s">"RS256"</span>, <span class="h">"typ"</span>: <span class="s">"JWT"</span>, <span class="h">"kid"</span>: <span class="s">"prod-2025-08"</span> }

<span class="c">// payload (decoded)</span>
{
  <span class="h">"sub"</span>: <span class="s">"u_28814"</span>,
  <span class="h">"role"</span>: <span class="s">"member"</span>,
  <span class="h">"iss"</span>: <span class="s">"https://auth.merid.example.com"</span>,
  <span class="h">"aud"</span>: <span class="s">"shop-prod"</span>,
  <span class="h">"exp"</span>: <span class="n">1746201600</span>
}`}/>
        </div>

        <div className="panel">
          <div className="panel-head"><div className="title">ATTACK MATRIX</div></div>
          <div className="panel-body" style={{padding:0}}>
            {[
              ['alg=none',           'force unsigned token', 'POSITIVE · staging issuer accepts',  'crit', 'F-0039'],
              ['alg confusion',      'RS256 → HS256 with pubkey', 'no-signal · pubkey unreachable', 'ok',   ''],
              ['kid injection',      'kid=../../etc/passwd', 'no-signal · kid sanitised',           'ok',   ''],
              ['weak HMAC crack',    'rockyou + 100k rules', 'not applicable · RS256',              'na',   ''],
              ['expired token',      'iat/exp drift ±300s',  'no-signal · strict validation',       'ok',   ''],
              ['cross-aud reuse',    'aud=admin-prod',       'SUSPECT · 200 on shop-prod',          'high', ''],
            ].map((r,i)=>(
              <div key={i} style={{display:'grid',gridTemplateColumns:'1fr 1.4fr 1.4fr 90px',padding:'8px 12px',borderBottom:'1px solid var(--line)',fontFamily:'var(--font-mono)',fontSize:11}}>
                <span style={{color:'var(--text-0)'}}>{r[0]}</span>
                <span style={{color:'var(--text-2)'}}>{r[1]}</span>
                <span style={{color:r[3]==='crit'?'var(--accent)':r[3]==='high'?'var(--high)':r[3]==='na'?'var(--text-3)':'var(--ok)'}}>{r[2]}</span>
                <span style={{color:'var(--accent)',textAlign:'right'}}>{r[4]}</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </>
  );
}

// ============ API & GraphQL ============
function ApiView({ kind }) {
  if (kind === 'api.gql') return <GraphQLView/>;
  const titles = {
    'api.rest': ['REST surface', '412 endpoints across /api/v1 (legacy) and /api/v2 (current)'],
    'api.ws':   ['WebSockets', 'realtime channels — order updates, chat, presence'],
    'api.spec': ['OpenAPI diff', 'declared spec vs observed traffic — surfaces undocumented routes'],
  };
  const [t,s] = titles[kind] || titles['api.rest'];

  if (kind === 'api.spec') return <SpecDiff/>;

  return (
    <>
      <div className="section-head"><div><h1><span className="tag">VAPT.WEB</span>{t}</h1><div className="sub">{s}</div></div></div>
      <div className="content">
        <div className="panel">
          <div className="panel-head"><div className="title">{kind==='api.rest'?'NAMESPACE COVERAGE':'CHANNELS'}</div></div>
          <div className="panel-body" style={{padding:0}}>
            {(kind==='api.rest'? [
              ['/api/v2/orders',     412, 8,  '88%'],
              ['/api/v2/users',      188, 4,  '92%'],
              ['/api/v2/me',         62,  2,  '100%'],
              ['/api/v2/checkout',   144, 1,  '74%'],
              ['/api/v2/inventory',  88,  0,  '61%'],
              ['/api/v1/* (legacy)', 47,  3,  '14%'],
            ] : [
              ['/ws/orders',     'auth · jwt',   'observed · 412 frames'],
              ['/ws/chat',       'auth · cookie','observed · 88 frames'],
              ['/ws/presence',   'public',       'observed · ratelimited'],
              ['/ws/admin',      'admin · jwt',  'auth-required · not yet probed'],
            ]).map((r,i)=>(
              <div key={i} style={{display:'grid',gridTemplateColumns:kind==='api.rest'?'1.4fr 80px 80px 80px':'1fr 1fr 1.4fr',padding:'8px 12px',borderBottom:'1px solid var(--line)',fontFamily:'var(--font-mono)',fontSize:11}}>
                <span style={{color:'var(--text-0)'}}>{r[0]}</span>
                <span style={{color:'var(--text-1)'}}>{r[1]}{kind==='api.rest'?' calls':''}</span>
                <span style={{color:r[2]?'var(--accent)':'var(--text-2)'}}>{kind==='api.rest'? `${r[2]} flagged` : r[2]}</span>
                {kind==='api.rest' && <span style={{color:'var(--text-2)',textAlign:'right'}}>{r[3]}</span>}
              </div>
            ))}
          </div>
        </div>
      </div>
    </>
  );
}

function GraphQLView() {
  return (
    <>
      <div className="section-head">
        <div><h1><span className="tag">VAPT.WEB</span>GraphQL</h1>
        <div className="sub">InQL · 38 queries · 14 mutations · introspection enabled in prod (F-0037)</div></div>
        <div className="actions"><button className="btn"><I.download/> SDL</button><button className="btn primary"><I.play/> Batch attack</button></div>
      </div>
      <div className="content" style={{padding:0,display:'grid',gridTemplateColumns:'1fr 1fr',gap:0}}>
        <div style={{borderRight:'1px solid var(--line)',background:'#06070a'}}>
          <div className="panel-head" style={{background:'var(--bg-1)'}}><div className="title">SCHEMA</div></div>
          <CodeV style={{padding:'12px 16px',height:'calc(100vh - 200px)'}} html={`<span class="c">"""Order placed by a tenant"""</span>
<span class="k">type</span> <span class="url">Order</span> {
  <span class="h">id</span>: ID!
  <span class="h">tenantId</span>: ID!
  <span class="h">items</span>: [<span class="url">LineItem</span>!]!
  <span class="h">total</span>: <span class="n">Money</span>!
  <span class="h">customer</span>: <span class="url">User</span> <span class="hi">@auth(scope: "order.read")</span>
}

<span class="k">type</span> <span class="url">Query</span> {
  <span class="h">order</span>(<span class="h">id</span>: ID!): <span class="url">Order</span>
  <span class="h">orders</span>(<span class="h">tenantId</span>: ID): [<span class="url">Order</span>!]!  <span class="hi"># tenantId NULL → all tenants</span>
  <span class="h">me</span>: <span class="url">User</span>
  <span class="h">__schema</span>: <span class="url">__Schema</span>!  <span class="hi"># introspection enabled</span>
}

<span class="k">type</span> <span class="url">Mutation</span> {
  <span class="h">updateUserRole</span>(<span class="h">id</span>: ID!, <span class="h">role</span>: <span class="url">Role</span>!): <span class="url">User</span>
  <span class="h">refundOrder</span>(<span class="h">id</span>: ID!, <span class="h">amount</span>: <span class="n">Money</span>!): <span class="url">Order</span>
}`}/>
        </div>
        <div>
          <div className="panel-head" style={{background:'var(--bg-1)'}}><div className="title">FINDINGS</div></div>
          <div className="findings">
            {[
              ['high','Introspection enabled in prod','/graphql','InQL',0.99],
              ['high','Batched query bypasses rate-limit','/graphql','InQL',0.84],
              ['med','tenantId nullable → cross-tenant read','orders()','CIPHER',0.77],
              ['med','updateUserRole accepts unauth member token','mutation','Burp',0.69],
              ['low','Verbose error exposes resolver path','/graphql','ZAP',0.99],
            ].map((f,i)=>(
              <div key={i} className="finding" style={{gridTemplateColumns:'24px 60px 1fr 100px 70px'}}>
                <span className="check"/>
                <span className={`sev ${f[0]}`}>{f[0]}</span>
                <span className="title">{f[1]}</span>
                <span className="src">{f[3]}</span>
                <span className="age">{(f[4]*100).toFixed(0)}%</span>
              </div>
            ))}
          </div>
        </div>
      </div>
    </>
  );
}

function SpecDiff() {
  return (
    <>
      <div className="section-head">
        <div><h1><span className="tag">VAPT.WEB</span>OpenAPI diff</h1>
        <div className="sub">declared spec (3.1) ↔ observed traffic — surfaces undocumented routes & shadow params</div></div>
      </div>
      <div className="content">
        <CodeV style={{borderRadius:6,border:'1px solid var(--line)'}} html={`<span class="c">+ undocumented endpoints (8)</span>
<span class="add">  + GET    /admin/users                 status=200  hits=41   risk=CRIT</span>
<span class="add">  + POST   /admin/tokens                status=201  hits=2    risk=HIGH</span>
<span class="add">  + GET    /debug/healthz              status=200  hits=14   risk=MED</span>
<span class="add">  + POST   /legacy/v1/login            status=200  hits=7    risk=MED</span>
<span class="add">  + GET    /api/img/proxy              status=200  hits=48   risk=MED  flag=SSRF</span>
<span class="add">  + GET    /__internal/metrics         status=401  hits=2</span>
<span class="add">  + POST   /api/v2/orders/{id}/refund  status=200  hits=12   undocumented</span>
<span class="add">  + GET    /api/v2/internal/audit      status=403  hits=4</span>

<span class="c">- declared but never observed (3)</span>
<span class="del">  - DELETE /api/v2/orders/{id}          last seen never  → likely retired</span>
<span class="del">  - PUT    /api/v2/users/{id}/avatar    last seen never</span>
<span class="del">  - POST   /api/v2/feedback             last seen never</span>

<span class="c">! parameter drift (5)</span>
  /api/v2/orders                        spec=tenantId,page  observed=+debug,+__internal
  /api/v2/me                            spec=name,email     observed=+role,+tier  <span class="hi">!</span>
  /search                               spec=q              observed=+debug,+source
  /auth/return                          spec=to             observed=+next,+redirect
  /api/v2/orders/{id}                   spec=id             observed=+include
`}/>
      </div>
    </>
  );
}

window.VulnCategory = VulnCategory;
window.AuthView = AuthView;
window.ApiView = ApiView;
