/**
 * SimulatorTab — Nano-Zeqond Simulator for the ZeqVM side panel.
 * Runs the validated local engines (no network):
 *   • ZeqNanoEvolver — differential HULYAS master-equation field evolver
 *   • ZeqMdEngine    — velocity-Verlet molecular dynamics (LJ + bonds, NVE)
 * One nano-zeqond clock: pulse-modulated dt (KO42), a snapshot printed every
 * 0.777 s zeqond, energy drift held ≤0.1% and reported live.
 * CSP-safe: no inline scripts/handlers; engines load from lib/ as globals.
 *
 * @version 1.287.31
 * @license CC BY 4.0 — Zeq. H / Zeq 1.287 Hz Limited
 */
const SimulatorTab = (() => {
  'use strict';
  const SEC_PER_YEAR = 31557600, TAU_LJ_PS = 2.156;
  let container = null, mode = 'field', eng = null, running = false, raf = 0;
  let lastWall = 0, rateSteps = 0, rateT = 0, lastSteps = 0, lastSim = 0, simRate = 0, initialized = false;
  let gpuSupported = false; try { gpuSupported = (typeof ZeqGpuField==='function') && ZeqGpuField.isSupported(); } catch(e){}
  function isGpu(){ const c = container && container.querySelector('#sm-gpu'); return mode==='field' && c && c.checked && gpuSupported; }

  function fmtTime(s){const y=s/SEC_PER_YEAR;if(y>=1e9)return(y/1e9).toFixed(2)+' Gyr';if(y>=1e6)return(y/1e6).toFixed(2)+' Myr';if(y>=1e3)return(y/1e3).toFixed(2)+' kyr';if(y>=1)return y.toFixed(2)+' yr';return s.toExponential(2)+' s';}
  function fmtPs(r){const ps=r*TAU_LJ_PS;if(ps>=1e6)return(ps/1e6).toFixed(2)+' µs';if(ps>=1e3)return(ps/1e3).toFixed(2)+' ns';return ps.toFixed(2)+' ps';}
  function fmtN(n){if(n>=1e12)return(n/1e12).toFixed(2)+'T';if(n>=1e9)return(n/1e9).toFixed(2)+'B';if(n>=1e6)return(n/1e6).toFixed(2)+'M';if(n>=1e3)return(n/1e3).toFixed(2)+'k';return n.toFixed(0);}

  function init(containerId) {
    container = document.getElementById(containerId);
    if (!container) return;
    if (initialized) { if (!running) toggleRun(true); return; }
    initialized = true;
    build();
  }

  function build() {
    const ok = (typeof ZeqNanoEvolver === 'function') && (typeof ZeqMdEngine === 'function');
    container.innerHTML = `
      <div style="flex:1;overflow-y:auto;padding:12px;font-family:'JetBrains Mono',monospace;font-size:11px;color:#fff">
        <div style="font-size:13px;font-weight:700;margin-bottom:2px">Nano-Zeqond <span style="color:#00ff88">Simulator</span></div>
        <div style="font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.45);margin-bottom:10px">prints every 0.777 s · local compute</div>
        ${ok ? '' : '<div style="color:#ff6b6b">Engines failed to load.</div>'}
        <div style="display:flex;gap:5px;margin-bottom:8px">
          <button id="sm-field" class="sm-mode" style="flex:1">Field ϕ</button>
          <button id="sm-md" class="sm-mode" style="flex:1">Molecular dynamics</button>
        </div>
        <div style="display:flex;flex-wrap:wrap;gap:5px;align-items:center;margin-bottom:8px">
          <button id="sm-run" style="flex:1">▶ Run</button>
          <button id="sm-reset">↻</button>
          <select id="sm-preset" class="sm-md-only" style="display:none">
            <option value="lj-liquid">LJ liquid</option><option value="lj-gas">LJ gas</option>
            <option value="crystal">Crystal → melt</option><option value="polymer">Polymer chains</option>
          </select>
          <select id="sm-comp" class="sm-field-only">
            <option value="1">1 s/step</option><option value="31557600" selected>1 yr/step</option>
            <option value="31557600000">1 kyr/step</option><option value="31557600000000">1 Myr/step</option>
          </select>
          <label class="sm-field-only" id="sm-gpu-label" style="display:flex;align-items:center;gap:4px;font-size:10px;color:#fff;cursor:pointer"><input type="checkbox" id="sm-gpu"> ⚡ GPU</label>
        </div>
        <canvas id="sm-canvas" width="340" height="190" style="width:100%;height:190px;background:#000;border:1px solid rgba(0,255,136,.18);border-radius:2px;display:block"></canvas>
        <canvas id="sm-gpucanvas" width="256" height="190" style="width:100%;height:190px;background:#000;border:1px solid rgba(0,255,136,.18);border-radius:2px;display:none"></canvas>
        <div style="height:5px;background:#000;border:1px solid rgba(0,255,136,.18);border-radius:2px;margin-top:7px;overflow:hidden"><i id="sm-pulse" style="display:block;height:100%;background:#00ff88;width:0%"></i></div>
        <div id="sm-stats" style="display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-top:10px"></div>
        <div style="font-size:9.5px;letter-spacing:.1em;text-transform:uppercase;color:#00ff88;margin:12px 0 6px">Zeqond prints — Δstate / 0.777 s</div>
        <div id="sm-prints" style="font-size:10px;max-height:150px;overflow-y:auto"></div>
        <div id="sm-note" style="font-size:9.5px;color:rgba(255,255,255,.45);margin-top:10px;line-height:1.6"></div>
      </div>`;
    // styling for buttons/selects (CSP-safe: classed, set via JS)
    container.querySelectorAll('.sm-mode,#sm-run,#sm-reset').forEach(b=>{b.style.cssText+=';font-family:inherit;font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding:7px 9px;border-radius:2px;cursor:pointer;border:1px solid #00ff88;background:transparent;color:#00ff88';});
    container.querySelectorAll('select').forEach(s=>{s.style.cssText+=';font-family:inherit;font-size:10px;background:#070b09;color:#00ff88;border:1px solid rgba(0,255,136,.18);border-radius:2px;padding:5px';});

    container.querySelector('#sm-field').addEventListener('click', () => setMode('field'));
    container.querySelector('#sm-md').addEventListener('click', () => setMode('md'));
    container.querySelector('#sm-run').addEventListener('click', () => toggleRun());
    container.querySelector('#sm-reset').addEventListener('click', () => { toggleRun(false); rebuild(); });
    container.querySelector('#sm-comp').addEventListener('change', e => { if (eng && mode==='field') eng.simDtPerStep = parseFloat(e.target.value); });
    container.querySelector('#sm-preset').addEventListener('change', () => { if (mode==='md') rebuild(); });
    const gpuChk = container.querySelector('#sm-gpu');
    gpuChk.addEventListener('change', rebuild);
    if(!gpuSupported){ gpuChk.disabled = true; const lbl=container.querySelector('#sm-gpu-label'); if(lbl){ lbl.style.opacity='.45'; lbl.title='WebGL2 float unavailable'; } }
    setMode('field');
  }

  function setMode(m){
    mode = m; toggleRun(false);
    const fb=container.querySelector('#sm-field'), mb=container.querySelector('#sm-md');
    fb.style.background = m==='field'?'#00ff88':'transparent'; fb.style.color = m==='field'?'#000':'#00ff88';
    mb.style.background = m==='md'?'#00ff88':'transparent'; mb.style.color = m==='md'?'#000':'#00ff88';
    container.querySelectorAll('.sm-field-only').forEach(e=>e.style.display=m==='field'?'':'none');
    container.querySelectorAll('.sm-md-only').forEach(e=>e.style.display=m==='md'?'':'none');
    rebuild();
  }

  function rebuild(){
    if (eng && eng.dispose){ try{ eng.dispose(); }catch(e){} }
    const cv2d = container.querySelector('#sm-canvas'), cvg = container.querySelector('#sm-gpucanvas');
    cv2d.style.display = isGpu() ? 'none' : 'block';
    cvg.style.display = isGpu() ? 'block' : 'none';
    if (isGpu()) eng = new ZeqGpuField(cvg, { N:256, simDtPerStep: parseFloat(container.querySelector('#sm-comp').value) });
    else if (mode==='field') eng = new ZeqNanoEvolver({ N:256, simDtPerStep: parseFloat(container.querySelector('#sm-comp').value) });
    else eng = new ZeqMdEngine({ preset: container.querySelector('#sm-preset').value });
    lastWall=0;rateSteps=0;rateT=0;lastSteps=0;lastSim=0;simRate=0;
    container.querySelector('#sm-prints').innerHTML = '<div style="color:rgba(255,255,255,.45)">awaiting first zeqond…</div>';
    container.querySelector('#sm-note').innerHTML = isGpu()
      ? '<strong>Deep nano — GPU.</strong> The 2-D field ϕ(x,y,t) steps every cell of a 256×256 grid in parallel (WebGL2 velocity-Verlet). Same physics, pulsed at 1.287 Hz, KO42 drift ≤0.1% — matches CPU to float precision. Billions of cell-updates/s, local.'
      : (mode==='field'
        ? 'Differential master equation integrated at nano-zeqond resolution; 1.287 Hz pulse modulates the metric (KO42 ≤0.1% drift). Local.'
        : 'Velocity-Verlet MD: NM19 F=ma under Lennard-Jones (+ NM30 bonds), NVE — energy + momentum conserved, drift ≤0.1%. Real MD throughput, local.');
    draw(); stats();
  }

  function toggleRun(force){
    running = (typeof force==='boolean') ? force : !running;
    const b = container.querySelector('#sm-run'); if (b) b.textContent = running ? '⏸ Pause' : '▶ Run';
    cancelAnimationFrame(raf);
    if (running){ lastWall=0; raf=requestAnimationFrame(loop); }
  }

  function loop(ts){
    if(!running) return;
    if(!lastWall) lastWall=ts;
    let dt=(ts-lastWall)/1000; lastWall=ts; if(dt>0.1)dt=0.1;
    const B = isGpu() ? 1200 : (mode==='field' ? 60000 : 1200);
    const p = eng.advance(dt,B); if(p) addPrint(p);
    if(isGpu() && eng.refreshStats) eng.refreshStats();
    rateT+=dt;
    if(rateT>=0.5){rateSteps=(eng.steps-lastSteps)/rateT;simRate=(eng.simTime-lastSim)/rateT;lastSteps=eng.steps;lastSim=eng.simTime;rateT=0;}
    draw(); stats();
    raf=requestAnimationFrame(loop);
  }

  function draw(){
    if(isGpu()){ if(eng && eng.render) eng.render(); return; }
    const cv=container.querySelector('#sm-canvas'); if(!cv) return; const x2=cv.getContext('2d'),w=cv.width,h=cv.height;
    x2.fillStyle='#000';x2.fillRect(0,0,w,h);
    if(mode==='field'){
      const N=eng.N,phi=eng.phi;x2.strokeStyle='rgba(0,255,136,.12)';x2.beginPath();x2.moveTo(0,h/2);x2.lineTo(w,h/2);x2.stroke();
      let mx=1e-6;for(let i=0;i<N;i++){const a=Math.abs(phi[i]);if(a>mx)mx=a;}
      x2.strokeStyle='#00ff88';x2.lineWidth=1.4;x2.beginPath();
      for(let i=0;i<N;i++){const px=i/(N-1)*w,py=h/2-(phi[i]/mx)*(h/2-6);i?x2.lineTo(px,py):x2.moveTo(px,py);}x2.stroke();
    } else {
      const sn=eng.snapshot(),L=sn.L,N=sn.N,xx=sn.x,s=Math.min(w,h)/L,ox=(w-L*s)/2,oy=(h-L*s)/2;
      x2.strokeStyle='rgba(0,255,136,.15)';x2.strokeRect(ox,oy,L*s,L*s);
      x2.strokeStyle='rgba(57,192,255,.55)';x2.lineWidth=1.2;
      for(const b of sn.bonds){const ax=xx[2*b.i],ay=xx[2*b.i+1],bx=xx[2*b.j],by=xx[2*b.j+1];
        if(Math.abs(ax-bx)<L/2&&Math.abs(ay-by)<L/2){x2.beginPath();x2.moveTo(ox+ax*s,oy+ay*s);x2.lineTo(ox+bx*s,oy+by*s);x2.stroke();}}
      const rad=Math.max(1.8,0.5*s);
      for(let i=0;i<N;i++){const vx=eng.v[2*i],vy=eng.v[2*i+1],sp=Math.sqrt(vx*vx+vy*vy),c=Math.min(255,80+sp*120);
        x2.fillStyle='rgb('+Math.round(c)+',255,'+Math.round(160-sp*40)+')';x2.beginPath();x2.arc(ox+xx[2*i]*s,oy+xx[2*i+1]*s,rad,0,6.2832);x2.fill();}
    }
  }

  function cell(k,v,amber){return '<div style="border:1px solid rgba(0,255,136,.18);border-radius:2px;padding:6px 7px;background:#000"><div style="font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;color:rgba(255,255,255,.45)">'+k+'</div><div style="font-size:13px;color:'+(amber?'#ffb000':'#00ff88')+';margin-top:2px;word-break:break-all">'+v+'</div></div>';}

  function stats(){
    const box=container.querySelector('#sm-stats'); if(!box) return; const sn=eng.snapshot();
    if(isGpu()){
      box.innerHTML=cell('Steps (2-D)',fmtN(sn.steps))+cell('Cell-updates/s',fmtN(rateSteps>0?rateSteps*sn.cells:0))+
        cell('Simulated time',fmtTime(sn.simTime),true)+cell('Grid',sn.gridN+'×'+sn.gridN)+
        cell('Master 𝓜',sn.masterSum.toFixed(4))+cell('Drift (KO42)',sn.driftPct.toFixed(3)+'%',sn.driftPct>0.1);
      const pbg=container.querySelector('#sm-pulse'); if(pbg) pbg.style.width=((eng.phase?eng.phase():0)*100).toFixed(1)+'%';
      return;
    }
    if(mode==='field'){
      box.innerHTML=cell('Nano-steps',fmtN(sn.steps))+cell('Rate',fmtN(rateSteps>0?rateSteps:0)+'/s')+
        cell('Simulated time',fmtTime(sn.simTime),true)+cell('Master 𝓜',sn.masterSum.toFixed(4))+
        cell('Sim rate',fmtTime(simRate)+'/s',true)+cell('Drift (KO42)',sn.driftPct.toFixed(3)+'%',sn.driftPct>0.1);
    } else {
      box.innerHTML=cell('Nano-steps',fmtN(sn.steps))+cell('Rate',fmtN(rateSteps>0?rateSteps:0)+'/s')+
        cell('Molecular time',fmtPs(sn.simTime),true)+cell('Temp T*',sn.T.toFixed(3))+
        cell('Energy E',sn.E.toFixed(2))+cell('Drift (KO42)',sn.driftPct.toFixed(3)+'%',sn.driftPct>0.1);
    }
    const pb=container.querySelector('#sm-pulse'); if(pb) pb.style.width=((eng.phase?eng.phase():0)*100).toFixed(1)+'%';
  }

  function addPrint(p){
    const box=container.querySelector('#sm-prints'); if(!box) return;
    if(box.firstChild && box.firstChild.textContent.indexOf('awaiting')>=0) box.innerHTML='';
    const row=document.createElement('div'); row.style.cssText='display:flex;justify-content:space-between;gap:6px;padding:3px 0;border-bottom:1px solid rgba(0,255,136,.18)';
    const m = mode==='field' ? '𝓜='+p.masterSum.toFixed(4)+' · '+fmtTime(p.simTime) : 'T*='+p.T.toFixed(3)+' · E='+p.E.toFixed(1)+' · '+fmtPs(p.simTime);
    row.innerHTML='<span style="color:#00ff88;font-weight:700">z'+p.zeqond+'</span><span style="color:rgba(255,255,255,.72);flex:1">'+m+'</span><span style="color:rgba(255,255,255,.45)">'+p.driftPct.toFixed(3)+'%</span>';
    box.insertBefore(row, box.firstChild);
    while(box.children.length>30) box.removeChild(box.lastChild);
  }

  return { init };
})();
