// auxequalizer.js — AUX segmented EQ
// scope animation rules for the equalizer

const BAR_COUNT = 18;
const SEGMENT_COUNT = 13;

let frame = null;
let bars = [];
let mode = 'offline';
let patternQueue = [];

let heights = Array.from({ length: BAR_COUNT }, () => Math.random() * 0.08);
let targets = Array.from({ length: BAR_COUNT }, () => Math.random() * 0.08);
let needleLeft = 0;
let needleRight = 0;
let needleTargetLeft = 0;
let needleTargetRight = 0;
let needleTick = 0;

const modes = {
  offline: { min: 0.04, max: 0.22, jitter: 0.05, smoothing: 0.10, opacity: 0.64 },
  idle:    { min: 0.05, max: 0.24, jitter: 0.05, smoothing: 0.10, opacity: 0.72 },
  low:     { min: 0.06, max: 0.28, jitter: 0.06, smoothing: 0.12, opacity: 0.78 },
  medium:  { min: 0.20, max: 0.68, jitter: 0.11, smoothing: 0.18, opacity: 0.90 },
  high:    { min: 0.42, max: 1.00, jitter: 0.18, smoothing: 0.24, opacity: 0.96 }
};

const patterns = {
  reading: ['medium', 'medium', 'medium', 'high'],
  sending: ['low', 'low', 'medium', 'high', 'low', 'medium', 'low', 'high'],
  parsing: ['medium', 'low']
};

export function initEq() {
  const wrap = document.getElementById('eq-bars');
  if (!wrap || wrap.dataset.eqReady === 'true') return;

  wrap.dataset.eqReady = 'true';
  wrap.innerHTML = '';

  const vuLeft = document.createElement('img');
  vuLeft.className = 'StudioNeedle-Eo StudioNeedleLeft-Eo';
  vuLeft.src = 'assets/studioneedle.png';
  vuLeft.alt = '';
  vuLeft.setAttribute('aria-hidden', 'true');
  const vuRight = document.createElement('img');
  vuRight.className = 'StudioNeedle-Eo StudioNeedleRight-Eo';
  vuRight.src = 'assets/studioneedle.png';
  vuRight.alt = '';
  vuRight.setAttribute('aria-hidden', 'true');
  wrap.appendChild(vuLeft);
  wrap.appendChild(vuRight);

  for (let i = 0; i < BAR_COUNT; i++) {
    const bar = document.createElement('div');
    bar.className = 'eq-bar';

    for (let j = 0; j < SEGMENT_COUNT; j++) {
      const seg = document.createElement('span');
      seg.className = 'eq-seg';
      bar.appendChild(seg);
    }

    wrap.appendChild(bar);
  }

  bars = Array.from(wrap.querySelectorAll('.eq-bar'));

  window.addEventListener('aux:eq', event => {
    const nextMode = event.detail?.mode;
    if (patterns[nextMode]) pulseEq(nextMode);
    else setEqMode(nextMode);
  });

  window.addEventListener('aux:verbatim-connection-changed', event => {
    setEqMode(event.detail?.isConnected ? 'idle' : 'offline');
  });

  ensureLoop();
}

export function setEqConnected(connected) {
  setEqMode(connected ? 'idle' : 'offline');
}

export function setEqMode(nextMode = 'idle') {
  if (!modes[nextMode]) nextMode = 'idle';
  mode = nextMode;
  patternQueue = [];
  ensureLoop();
}

export function pulseEq(patternName) {
  patternQueue = patterns[patternName] ? [...patterns[patternName]] : [];
  ensureLoop();
}

function ensureLoop() {
  if (!frame) frame = requestAnimationFrame(runLoop);
}

function runLoop() {
  frame = null;

  if (!bars.length) return;

  const activeMode = patternQueue.shift() || mode;
  renderEq(activeMode);

  frame = requestAnimationFrame(runLoop);
}

function renderStudioNeedles(activeMode) {
  const wrap = document.getElementById('eq-bars');
  const left = wrap?.querySelector('.StudioNeedleLeft-Eo');
  const right = wrap?.querySelector('.StudioNeedleRight-Eo');
  if (!left || !right) return;

  needleTick += 1;

  const bands = {
    offline: { min: 0,  max: 0,   targetEveryLeft: 44, targetEveryRight: 52, rise: 0.045, fall: 0.030, bias: 3.2, crash: 0 },
    idle:    { min: 45, max: 0,   targetEveryLeft: 46, targetEveryRight: 56, rise: 0.044, fall: 0.028, bias: 2.8, crash: 0 },
    low:     { min: 45, max: 0,   targetEveryLeft: 38, targetEveryRight: 48, rise: 0.054, fall: 0.034, bias: 2.0, crash: 0 },
    medium:  { min: 60, max: -30, targetEveryLeft: 30, targetEveryRight: 38, rise: 0.066, fall: 0.040, bias: 1.7, crash: 0 },
    high:    { min: 0,  max: -45, targetEveryLeft: 24, targetEveryRight: 30, rise: 0.078, fall: 0.048, bias: 1.45, crash: 0.02 }
  };
  const band = bands[activeMode] || bands.idle;
  const leftCrash = activeMode === 'high' && Math.random() < band.crash;
  const rightCrash = activeMode === 'high' && Math.random() < band.crash * 0.85;
  const leftUnit = leftCrash ? 1 : Math.pow(Math.random(), band.bias);
  const rightUnit = rightCrash ? 0.96 : Math.pow(Math.random(), band.bias);

  if (needleTick % band.targetEveryLeft === 0 || leftCrash) needleTargetLeft = band.min + (band.max - band.min) * leftUnit;
  if (needleTick % band.targetEveryRight === 0 || rightCrash) needleTargetRight = band.min + (band.max - band.min) * rightUnit;

  const riseLeft = needleTargetLeft < needleLeft;
  const riseRight = needleTargetRight < needleRight;
  needleLeft += (needleTargetLeft - needleLeft) * (riseLeft ? band.rise : band.fall);
  needleRight += (needleTargetRight - needleRight) * (riseRight ? band.rise * 0.92 : band.fall * 0.92);
  left.style.transform = `rotate(${needleLeft.toFixed(2)}deg)`;
  right.style.transform = `rotate(${needleRight.toFixed(2)}deg)`;
}

function renderEq(activeMode) {
  const cfg = modes[activeMode] || modes.idle;
  renderStudioNeedles(activeMode);

  bars.forEach((bar, index) => {
    if (Math.random() < 0.08 + cfg.jitter) {
      targets[index] = cfg.min + Math.random() * (cfg.max - cfg.min);
    }

    heights[index] += (targets[index] - heights[index]) * cfg.smoothing;

    const ratio = Math.max(0.01, Math.min(1, heights[index]));
    const level = Math.max(1, Math.min(SEGMENT_COUNT, Math.round(ratio * SEGMENT_COUNT)));

    bar.style.opacity = String(cfg.opacity);

    Array.from(bar.children).forEach((seg, segIndex) => {
      seg.classList.toggle('on', segIndex < level);
    });
  });
}