<?php
// admin/widgets/speedtest_gauges.php
// UI: original user code (scoped). Added ONLY MikroTik data feed mapping.
// Second gauge shows TOTAL subscribers instantaneous consumption (mixed mode).

if (session_status() === PHP_SESSION_NONE) { @session_start(); }
?>
<?php $ua_widget_css_v = @filemtime(__DIR__ . '/../assets/css/ua_program_unified.css') ?: 1; ?>
<link rel="stylesheet" href="../assets/css/ua_program_unified.css?v=<?= (int)$ua_widget_css_v ?>">
<div class="ua-speedtest-scope">

<div class="wrap">
  <div class="main-card" id="mainCard">

    <div class="grid">

      <!-- UPLOAD SPEED -->
      <div class="cell js-gauge" data-title="UPLOAD" data-unit="Mbps" data-max="20" data-value="8.6" data-accent="orange">
        <div class="topbar">
          <div class="left">
            <div class="badge">⬆</div>
            <div class="meta">
              <div class="k">UPLOAD</div>
              <div class="v"><span class="val">8.6</span> Mbps</div>
            </div>
          </div>
          <div class="hint">MAX 20</div>
        </div>
        <div class="canvasWrap"><canvas></canvas></div>
      </div>

      <!-- DOWNLOAD SPEED -->
      <div class="cell js-gauge" data-title="DOWNLOAD" data-unit="Mbps" data-max="100" data-value="42.5" data-accent="cyan">
        <div class="topbar">
          <div class="left">
            <div class="badge">⬇</div>
            <div class="meta">
              <div class="k">DOWNLOAD</div>
              <div class="v"><span class="val">42.5</span> Mbps</div>
            </div>
          </div>
          <div class="hint">MAX 100</div>
        </div>
        <div class="canvasWrap"><canvas></canvas></div>
      </div>

      <!-- UPLOAD USAGE -->
      <div class="cell js-gauge" data-title="UPLOAD USE" data-unit="GB" data-max="50" data-value="18" data-accent="orange">
        <div class="topbar">
          <div class="left">
            <div class="badge">📤</div>
            <div class="meta">
              <div class="k">UPLOAD USE</div>
              <div class="v"><span class="val">18</span> GB</div>
            </div>
          </div>
          <div class="hint">50 GB</div>
        </div>
        <div class="canvasWrap"><canvas></canvas></div>
      </div>

      <!-- DOWNLOAD USAGE -->
      <div class="cell js-gauge" data-title="DOWNLOAD USE" data-unit="GB" data-max="200" data-value="120" data-accent="cyan">
        <div class="topbar">
          <div class="left">
            <div class="badge">📥</div>
            <div class="meta">
              <div class="k">DOWNLOAD USE</div>
              <div class="v"><span class="val">120</span> GB</div>
            </div>
          </div>
          <div class="hint">200 GB</div>
        </div>
        <div class="canvasWrap"><canvas></canvas></div>
      </div>

    </div>

    <div class="tap">🔊 لتفعيل الصوت: اضغط مرة واحدة داخل الكرت (<b>Click</b>)</div>
  </div>
</div>


</div>

<script>

(() => {
  const DPR = Math.min(2, window.devicePixelRatio || 1);
  const rad = d => d * Math.PI / 180;
  const clamp = (n,a,b)=>Math.max(a,Math.min(b,n));
  const lerp = (a,b,p)=>a+(b-a)*p;

  /* ✅ فتحة القوس للأسفل + أكبر شوي */
  const START_DEG = 132;
  const END_DEG   = 48;
  const startA = rad(START_DEG);
  const endA0  = rad(END_DEG);
  const endA   = endA0 < startA ? (endA0 + Math.PI*2) : endA0;
  const sweep  = endA - startA;

  /* ===== WebAudio tick ===== */
  let audioCtx = null;
  let audioEnabled = false;

  function ensureAudio(){
    if (!audioCtx){
      audioCtx = new (window.AudioContext || window.webkitAudioContext)();
    }
    if (audioCtx.state === "suspended") audioCtx.resume();
    audioEnabled = true;
  }

  function tickSound(strength=0.18){
    if (!audioEnabled || !audioCtx) return;
    const t0 = audioCtx.currentTime;

    const osc = audioCtx.createOscillator();
    const gain = audioCtx.createGain();

    osc.type = "triangle";
    osc.frequency.setValueAtTime(1200, t0);
    osc.frequency.exponentialRampToValueAtTime(420, t0 + 0.03);

    gain.gain.setValueAtTime(0.0001, t0);
    gain.gain.exponentialRampToValueAtTime(strength, t0 + 0.005);
    gain.gain.exponentialRampToValueAtTime(0.0001, t0 + 0.06);

    osc.connect(gain);
    gain.connect(audioCtx.destination);

    osc.start(t0);
    osc.stop(t0 + 0.07);
  }

  document.getElementById("mainCard").addEventListener("pointerdown", () => {
    ensureAudio();
  }, { once:true });

  /* ===== Colors ===== */
  function theme(accent){
    if (accent === "orange") {
      return {
        arcA: "rgba(90,220,255,.92)",
        arcB: "rgba(255,105,70,.95)",
        needle: "rgba(255,200,140,.92)",
        wave: "rgba(255,190,120,.40)",
        scan: "rgba(255,210,170,.35)"
      };
    }
    return {
      arcA: "rgba(90,220,255,.98)",
      arcB: "rgba(255,105,70,.90)",
      needle: "rgba(120,255,240,.92)",
      wave: "rgba(90,255,200,.50)",
      scan: "rgba(120,255,240,.30)"
    };
  }

  /* ===== Ticks like speedtest (smart) ===== */
  function ticksFor(unit, max){
    if (unit === "Mbps"){
      if (max <= 10)  return [0,1,2,5,8,10].filter(v=>v<=max);
      if (max <= 20)  return [0,1,2,5,10,15,20].filter(v=>v<=max);
      if (max <= 50)  return [0,5,10,20,30,40,50].filter(v=>v<=max);
      if (max <= 100) return [0,5,10,20,30,50,75,100].filter(v=>v<=max);
      return [0, max*0.1, max*0.2, max*0.3, max*0.5, max*0.75, max].map(v=>Math.round(v));
    }
    // GB: 0/25/50/75/100%
    return [0, 0.25, 0.5, 0.75, 1].map(p => Math.round(max*p));
  }

  class Gauge {
    constructor(root){
      this.root = root;
      this.canvas = root.querySelector("canvas");
      this.ctx = this.canvas.getContext("2d");
      this.unit = root.dataset.unit || "";
      this.max = parseFloat(root.dataset.max || "100") || 100;
      this.target = parseFloat(root.dataset.value || "0") || 0;

      this.colors = theme(root.dataset.accent || "cyan");
      this.value = 0;
      this.wavePhase = 0;
      this.scanPhase = Math.random();    // لكل عداد توقيت خاص
      this.tickPhase = 0;
      this.lastTickBucket = null;

      this.ticks = ticksFor(this.unit, this.max);

      root.querySelector(".val").textContent = this.target;

      this.resize();
      window.addEventListener("resize", () => this.resize());
    }

    setTarget(v){
      const n = parseFloat(v);
      this.target = isFinite(n) ? n : 0;
      const valEl = this.root.querySelector(".val");
      if (valEl) valEl.textContent = (this.unit === "GB") ? this.target.toFixed(2) : this.target.toFixed(1);
    }

    resize(){
      const w = this.canvas.clientWidth;
      const h = this.canvas.clientHeight;
      this.canvas.width = Math.floor(w * DPR);
      this.canvas.height= Math.floor(h * DPR);
    }

    angle(v){
      const p = clamp(v/this.max, 0, 1);
      return startA + p*sweep;
    }

    drawTicks(cx, cy, R){
      const x = this.ctx;

      // minor ticks
      const minor = 28;
      x.save();
      x.lineCap = "round";
      for(let i=0;i<=minor;i++){
        const p = i/minor;
        const a = startA + p*sweep;
        const r1 = R*0.92, r2 = R*1.02;
        x.strokeStyle = "rgba(255,255,255,.16)";
        x.lineWidth = 1.3*DPR;
        x.beginPath();
        x.moveTo(cx+Math.cos(a)*r1, cy+Math.sin(a)*r1);
        x.lineTo(cx+Math.cos(a)*r2, cy+Math.sin(a)*r2);
        x.stroke();
      }

      // major ticks + labels
      x.fillStyle = "rgba(255,255,255,.72)";
      x.font = `${Math.round(11*DPR)}px Arial`;
      x.textAlign = "center";
      x.textBaseline = "middle";

      for(const v of this.ticks){
        const p = clamp(v/this.max, 0, 1);
        const a = startA + p*sweep;

        const r1 = R*0.88, r2 = R*1.03;
        x.strokeStyle = "rgba(255,255,255,.45)";
        x.lineWidth = 2.1*DPR;

        x.beginPath();
        x.moveTo(cx+Math.cos(a)*r1, cy+Math.sin(a)*r1);
        x.lineTo(cx+Math.cos(a)*r2, cy+Math.sin(a)*r2);
        x.stroke();

        const lr = R*1.18;
        const lx = cx + Math.cos(a)*lr;
        const ly = cy + Math.sin(a)*lr;
        x.fillText(String(v), lx, ly);
      }

      x.restore();
    }

    drawWave(W,H,intensity){
      const x = this.ctx;
      this.wavePhase += 0.01;

      x.save();
      x.strokeStyle = this.colors.wave;
      x.lineWidth = 2*DPR;
      x.beginPath();

      for(let i=0;i<=120;i++){
        const p = i/120;
        const xx = W*0.08 + p*W*0.84;
        const amp = 5.5 + 2.0*intensity;
        const yy = H*0.86 + Math.sin((p*8 + this.wavePhase)*Math.PI*2) * amp;
        i ? x.lineTo(xx,yy) : x.moveTo(xx,yy);
      }
      x.stroke();
      x.restore();
    }

    drawLiveScan(cx, cy, R){
      // وميض ماسح يتحرك على القوس
      const x = this.ctx;
     this.scanPhase += 0.002;

      const scanAngle = startA + ( (this.scanPhase % 1) * sweep );
      const width = rad(10); // عرض الماسح (زاوي)

      x.save();
      x.globalCompositeOperation = "lighter";
      x.strokeStyle = this.colors.scan;
      x.lineWidth = R*0.17;
      x.lineCap = "round";
      x.shadowColor = this.colors.scan;
      x.shadowBlur = 16*DPR;

      x.beginPath();
      x.arc(cx, cy, R, scanAngle - width, scanAngle + width, false);
      x.stroke();
      x.restore();
    }

    drawPrismNeedle(cx, cy, R, a){
      const x = this.ctx;

      // اهتزاز خفيف جدًا (micro shake)
      const shake = (Math.sin((this.scanPhase*22)) * 0.0035);
      const aa = a + shake;

      const dx = Math.cos(aa), dy = Math.sin(aa);
      const ex = cx + dx * R * 0.82;
      const ey = cy + dy * R * 0.82;

      x.save();

      // Glow
      x.shadowColor = this.colors.needle;
      x.shadowBlur = 16*DPR;

      // Prism gradient along needle
      const grad = x.createLinearGradient(cx, cy, ex, ey);
      grad.addColorStop(0.00, "rgba(255,255,255,0.92)");
      grad.addColorStop(0.20, this.colors.needle);
      grad.addColorStop(0.60, "rgba(120,255,240,0.90)");
      grad.addColorStop(0.85, "rgba(255,170,220,0.70)");
      grad.addColorStop(1.00, "rgba(255,255,255,0.90)");

      // main needle
      x.strokeStyle = grad;
      x.lineWidth = R * 0.040;
      x.lineCap = "round";
      x.beginPath();
      x.moveTo(cx, cy);
      x.lineTo(ex, ey);
      x.stroke();

      // glossy reflection
      x.shadowBlur = 0;
      x.strokeStyle = "rgba(255,255,255,0.42)";
      x.lineWidth = R * 0.014;
      x.beginPath();
      x.moveTo(cx + dx*2, cy + dy*2);
      x.lineTo(ex - dx*6, ey - dy*6);
      x.stroke();

      // crystal tip
      const tipR = R * 0.040;
      const tipGrad = x.createRadialGradient(ex, ey, 1, ex, ey, tipR);
      tipGrad.addColorStop(0, "rgba(255,255,255,0.95)");
      tipGrad.addColorStop(0.4, this.colors.needle);
      tipGrad.addColorStop(1, "rgba(0,0,0,0)");
      x.fillStyle = tipGrad;
      x.beginPath(); x.arc(ex, ey, tipR, 0, Math.PI*2); x.fill();

      // hub glass
      const hubGrad = x.createRadialGradient(cx, cy, 1, cx, cy, R*0.08);
      hubGrad.addColorStop(0, "rgba(255,255,255,0.95)");
      hubGrad.addColorStop(0.45, this.colors.needle);
      hubGrad.addColorStop(1, "rgba(0,0,0,0.65)");
      x.fillStyle = hubGrad;
      x.beginPath(); x.arc(cx, cy, R*0.065, 0, Math.PI*2); x.fill();

      x.restore();
    }

    draw(){
      const x = this.ctx;
      const W = this.canvas.width;
      const H = this.canvas.height;
      x.clearRect(0,0,W,H);

      const cx = W*0.50;
      const cy = H*0.52;
      const R  = Math.min(W,H)*0.40;

      // arc
      x.save();
      x.lineWidth = R*0.14;
      x.lineCap = "round";
      const g = x.createLinearGradient(cx-R, cy, cx+R, cy);
      g.addColorStop(0, this.colors.arcA);
      g.addColorStop(0.70, this.colors.arcB);

      x.strokeStyle = g;
      x.beginPath();
      x.arc(cx, cy, R, startA, endA, false);
      x.stroke();

      // inner depth ring
      x.strokeStyle = "rgba(0,0,0,.35)";
      x.lineWidth = R*0.04;
      x.beginPath();
      x.arc(cx, cy, R - (R*0.14)*0.55, startA, endA, false);
      x.stroke();
      x.restore();

      // ticks + labels
      this.drawTicks(cx, cy, R);

      // Live Scan effect
      this.drawLiveScan(cx, cy, R);

      // needle
      const a = this.angle(this.value);
      this.drawPrismNeedle(cx, cy, R, a);

      // value text (بدون تكرار اسم t)
      x.save();
      x.textAlign = "center";
      x.textBaseline = "middle";
      x.fillStyle = "rgba(255,255,255,.95)";
      x.font = `${Math.round(40*DPR)}px Arial`;

      const txtVal = (this.unit === "GB")
        ? this.value.toFixed(1).replace(/\.0$/,"")
        : this.value.toFixed(2).replace(/\.00$/,"");

      x.fillText(txtVal, cx, cy - R*0.08);

      x.font = `${Math.round(11*DPR)}px Arial`;
      x.fillStyle = "rgba(255,255,255,.70)";
      x.fillText(this.unit, cx, cy + R*0.11);
      x.restore();

      // wave
      const intensity = clamp(this.value/this.max, 0, 1);
      this.drawWave(W,H,intensity);
    }

    tick(){
      // smooth value
      const prev = this.value;
      this.value = lerp(this.value, this.target, 0.09);
      this.draw();

      // sound tick: each time cross bucket (light, not annoying)
      // bucket size depends on max
      const bucketSize = (this.unit === "Mbps") ? Math.max(1, Math.round(this.max/20)) : Math.max(1, Math.round(this.max/10));
      const bucket = Math.floor(this.value / bucketSize);

      if (bucket !== this.lastTickBucket && Math.abs(this.value - prev) > 0.02){
        this.lastTickBucket = bucket;
        tickSound(0.10);
      }
    }
  }

  // init gauges
  const gauges = [...document.querySelectorAll(".js-gauge")].map(el => new Gauge(el));
  window.__UA_GAUGES__ = gauges;

  // animation loop
  function loop(){
    for (const g of gauges) g.tick();
    requestAnimationFrame(loop);
  }
  requestAnimationFrame(loop);

})();

</script>

<script>
(() => {
  async function poll(){
    try {
      const r = await fetch('api/speed_gauges.php', {cache:'no-store'});
      const j = await r.json();

      const downMbps = (j.rx_bps||0) / 1e6;
      const upMbps   = (j.tx_bps||0) / 1e6;
      const consumedMbps = (j.consumed_bps||0) / 1e6;

      const downGB = (j.rx_gb||0);
      const upGB   = (j.tx_gb||0);

      if (window.__UA_GAUGES__ && window.__UA_GAUGES__.length>=4) {
        window.__UA_GAUGES__[0].setTarget(upMbps);
        window.__UA_GAUGES__[1].setTarget(consumedMbps); // second gauge = consumed
        window.__UA_GAUGES__[2].setTarget(upGB);
        window.__UA_GAUGES__[3].setTarget(downGB);
      } else if (window.__UA_GAUGES__ && window.__UA_GAUGES__.length>=2) {
        window.__UA_GAUGES__[0].setTarget(upMbps);
        window.__UA_GAUGES__[1].setTarget(consumedMbps);
      }
    } catch(e) {
      // keep zeros
    }
  }
  poll();
  setInterval(poll, 2000);
})();
</script>
