import { getAudioContext } from './superdough.mjs';

let worklet;
export async function dspWorklet(ac, code) {
  const name = `dsp-worklet-${Date.now()}`;
  const workletCode = `${code}
let __q = []; // trigger queue
class MyProcessor extends AudioWorkletProcessor {
  constructor() {
    super();
    this.t = 0;
    this.stopped = false;
    this.port.onmessage = (e) => {
      if(e.data==='stop') {
        this.stopped = true;
      } else if(e.data?.dough) {
        __q.push(e.data)
      } else {
        msg?.(e.data)
      }
    };
  }
  process(inputs, outputs, parameters) {
    const output = outputs[0];
    if(__q.length) {
      for(let i=0;i<__q.length;++i) {
        const deadline = __q[i].time-currentTime;
        if(deadline<=0) {
          trigger(__q[i].dough)
          __q.splice(i,1)
        }
      }
    }
    for (let i = 0; i < output[0].length; i++) {
      const out = dsp(this.t / sampleRate);
      output.forEach((channel) => {
        channel[i] = out;
      });
      this.t++;
    }
  return !this.stopped;
  }
}
registerProcessor('${name}', MyProcessor);
`;
  const base64String = btoa(workletCode);
  const dataURL = `data:text/javascript;base64,${base64String}`;
  await ac.audioWorklet.addModule(dataURL);
  const node = new AudioWorkletNode(ac, name);
  const stop = () => node.port.postMessage('stop');
  return { node, stop };
}
const stop = () => {
  if (worklet) {
    worklet?.stop();
    worklet?.node?.disconnect();
  }
};

if (typeof window !== 'undefined') {
  window.addEventListener('message', (e) => {
    if (e.data === 'strudel-stop') {
      stop();
    } else if (e.data?.dough) {
      worklet?.node.port.postMessage(e.data);
    }
  });
}

export const dough = async (code) => {
  const ac = getAudioContext();
  stop();
  worklet = await dspWorklet(ac, code);
  worklet.node.connect(ac.destination);
};

export function doughTrigger(t, hap, currentTime, duration, cps) {
  window.postMessage({ time: t, dough: hap.value, currentTime, duration, cps });
}
