(() => {
  const state = {
    audioContext: null,
    destination: null,
    micStream: null,
    systemStream: null,
    mixedStream: null,
    recorder: null,
    chunks: [],
    animationFrame: null,
    analyzers: {},
    downloadUrl: null,
  };

  const els = {
    connectMic: document.getElementById('connect-mic'),
    connectSystem: document.getElementById('connect-system'),
    start: document.getElementById('start-recording'),
    stop: document.getElementById('stop-recording'),
    reset: document.getElementById('reset-audio'),
    micStatus: document.getElementById('mic-status'),
    systemStatus: document.getElementById('system-status'),
    mixStatus: document.getElementById('mix-status'),
    micMeter: document.getElementById('mic-meter'),
    systemMeter: document.getElementById('system-meter'),
    mixMeter: document.getElementById('mix-meter'),
    log: document.getElementById('audio-log'),
    result: document.getElementById('recording-result'),
    preview: document.getElementById('recording-preview'),
    download: document.getElementById('download-recording'),
    sharedVideo: document.getElementById('shared-video-preview'),
  };

  if (!navigator.mediaDevices || !window.MediaRecorder) {
    log('This browser does not support the required MediaDevices/MediaRecorder APIs. Try current Chrome or Edge over HTTPS.');
    [els.connectMic, els.connectSystem, els.start].forEach((button) => {
      if (button) button.disabled = true;
    });
    return;
  }

  els.connectMic?.addEventListener('click', connectMicrophone);
  els.connectSystem?.addEventListener('click', connectSystemAudio);
  els.start?.addEventListener('click', startRecording);
  els.stop?.addEventListener('click', stopRecording);
  els.reset?.addEventListener('click', resetAudio);
  window.addEventListener('beforeunload', cleanupTracks);

  async function ensureAudioGraph() {
    if (state.audioContext) return;

    const AudioContextClass = window.AudioContext || window.webkitAudioContext;
    state.audioContext = new AudioContextClass();
    state.destination = state.audioContext.createMediaStreamDestination();
    state.mixedStream = state.destination.stream;
    state.analyzers.mix = createAnalyser();

    const mixSource = state.audioContext.createMediaStreamSource(state.mixedStream);
    mixSource.connect(state.analyzers.mix);
    updateStatus(els.mixStatus, 'Waiting', 'muted');
    startMeters();
  }

  async function connectMicrophone() {
    try {
      await ensureAudioGraph();
      await state.audioContext.resume();

      const stream = await navigator.mediaDevices.getUserMedia({
        audio: {
          echoCancellation: true,
          noiseSuppression: true,
          autoGainControl: true,
        },
      });

      replaceStream('micStream', stream);
      connectStream(stream, 'mic');
      updateStatus(els.micStatus, 'Connected', 'active');
      log('Microphone connected.');
      refreshButtons();
    } catch (error) {
      handleCaptureError('microphone', error);
    }
  }

  async function connectSystemAudio() {
    try {
      await ensureAudioGraph();
      await state.audioContext.resume();

      const stream = await navigator.mediaDevices.getDisplayMedia({
        video: true,
        audio: {
          echoCancellation: false,
          noiseSuppression: false,
          autoGainControl: false,
        },
      });

      if (!stream.getAudioTracks().length) {
        stopStream(stream);
        throw new Error('No audio track was shared. Reopen sharing and enable tab/system audio.');
      }

      replaceStream('systemStream', stream);
      connectStream(stream, 'system');
      els.sharedVideo.srcObject = stream;
      els.sharedVideo.play().catch(() => {});
      updateStatus(els.systemStatus, 'Connected', 'active');
      log('Computer/tab audio connected. Keep the shared source open while recording.');

      stream.getTracks().forEach((track) => {
        track.addEventListener('ended', () => {
          if (state.systemStream === stream) {
            updateStatus(els.systemStatus, 'Stopped', 'muted');
            log('Shared computer/tab audio stopped by the browser.');
            state.systemStream = null;
            refreshButtons();
          }
        });
      });

      refreshButtons();
    } catch (error) {
      handleCaptureError('computer/tab audio', error);
    }
  }

  function connectStream(stream, sourceName) {
    const audioTracks = stream.getAudioTracks();
    if (!audioTracks.length) return;

    const audioOnlyStream = new MediaStream(audioTracks);
    const source = state.audioContext.createMediaStreamSource(audioOnlyStream);
    const analyser = createAnalyser();
    state.analyzers[sourceName] = analyser;
    source.connect(analyser);
    source.connect(state.destination);
    updateStatus(els.mixStatus, 'Mix ready', 'active');
  }

  function createAnalyser() {
    const analyser = state.audioContext.createAnalyser();
    analyser.fftSize = 256;
    analyser.smoothingTimeConstant = 0.78;
    return analyser;
  }

  function startMeters() {
    if (state.animationFrame) return;
    const data = new Uint8Array(128);

    const draw = () => {
      drawMeter(state.analyzers.mic, els.micMeter, data);
      drawMeter(state.analyzers.system, els.systemMeter, data);
      drawMeter(state.analyzers.mix, els.mixMeter, data);
      state.animationFrame = requestAnimationFrame(draw);
    };

    draw();
  }

  function drawMeter(analyser, element, data) {
    if (!element) return;
    if (!analyser) {
      element.style.width = '0%';
      return;
    }

    analyser.getByteTimeDomainData(data);
    let sum = 0;
    for (const value of data) {
      const centered = value - 128;
      sum += centered * centered;
    }
    const rms = Math.sqrt(sum / data.length);
    const width = Math.min(100, Math.max(3, rms * 4.6));
    element.style.width = `${width}%`;
  }

  function startRecording() {
    if (!state.mixedStream || !state.mixedStream.getAudioTracks().length) {
      log('Connect at least one audio source before recording.');
      return;
    }

    cleanupRecordingUrl();
    state.chunks = [];
    const options = pickRecorderOptions();
    state.recorder = new MediaRecorder(state.mixedStream, options);

    state.recorder.addEventListener('dataavailable', (event) => {
      if (event.data && event.data.size > 0) state.chunks.push(event.data);
    });

    state.recorder.addEventListener('stop', () => {
      const mimeType = state.recorder?.mimeType || 'audio/webm';
      const blob = new Blob(state.chunks, { type: mimeType });
      state.downloadUrl = URL.createObjectURL(blob);
      els.preview.src = state.downloadUrl;
      els.download.href = state.downloadUrl;
      els.download.download = `reliefsignal-audio-test-${new Date().toISOString().replace(/[:.]/g, '-')}.webm`;
      els.result.hidden = false;
      log(`Recording ready (${formatBytes(blob.size)}).`);
      refreshButtons();
    });

    state.recorder.start(1000);
    updateStatus(els.mixStatus, 'Recording', 'recording');
    log('Local recording started.');
    refreshButtons();
  }

  function stopRecording() {
    if (state.recorder && state.recorder.state !== 'inactive') {
      state.recorder.stop();
      updateStatus(els.mixStatus, 'Mix ready', hasAnySource() ? 'active' : 'muted');
      log('Recording stopped.');
      refreshButtons();
    }
  }

  function resetAudio() {
    if (state.recorder && state.recorder.state !== 'inactive') {
      state.recorder.stop();
    }
    cleanupTracks();
    cleanupRecordingUrl();
    state.micStream = null;
    state.systemStream = null;
    state.mixedStream = null;
    state.destination = null;
    state.analyzers = {};
    state.audioContext?.close().catch(() => {});
    state.audioContext = null;
    state.recorder = null;
    state.chunks = [];
    if (state.animationFrame) cancelAnimationFrame(state.animationFrame);
    state.animationFrame = null;
    els.preview.removeAttribute('src');
    els.download.removeAttribute('href');
    els.result.hidden = true;
    els.sharedVideo.srcObject = null;
    updateStatus(els.micStatus, 'Not connected', 'muted');
    updateStatus(els.systemStatus, 'Not connected', 'muted');
    updateStatus(els.mixStatus, 'Waiting', 'muted');
    [els.micMeter, els.systemMeter, els.mixMeter].forEach((meter) => {
      if (meter) meter.style.width = '0%';
    });
    log('Audio capture reset.');
    refreshButtons();
  }

  function refreshButtons() {
    const recording = state.recorder && state.recorder.state === 'recording';
    const hasSource = hasAnySource();
    els.start.disabled = !hasSource || recording;
    els.stop.disabled = !recording;
    els.reset.disabled = !hasSource && !state.downloadUrl;
    els.connectMic.disabled = Boolean(state.micStream) || recording;
    els.connectSystem.disabled = Boolean(state.systemStream) || recording;
  }

  function hasAnySource() {
    return Boolean(
      state.micStream?.getAudioTracks().some((track) => track.readyState === 'live') ||
      state.systemStream?.getAudioTracks().some((track) => track.readyState === 'live')
    );
  }

  function pickRecorderOptions() {
    const candidates = [
      'audio/webm;codecs=opus',
      'audio/webm',
      'audio/mp4',
    ];
    const mimeType = candidates.find((type) => MediaRecorder.isTypeSupported(type));
    return mimeType ? { mimeType } : {};
  }

  function replaceStream(key, stream) {
    if (state[key]) stopStream(state[key]);
    state[key] = stream;
  }

  function stopStream(stream) {
    stream?.getTracks().forEach((track) => track.stop());
  }

  function cleanupTracks() {
    stopStream(state.micStream);
    stopStream(state.systemStream);
  }

  function cleanupRecordingUrl() {
    if (state.downloadUrl) {
      URL.revokeObjectURL(state.downloadUrl);
      state.downloadUrl = null;
    }
  }

  function updateStatus(element, label, mode) {
    if (!element) return;
    element.textContent = label;
    element.classList.remove('active', 'muted', 'recording');
    element.classList.add(mode);
  }

  function log(message) {
    if (!els.log) return;
    const item = document.createElement('li');
    item.textContent = `${new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' })} — ${message}`;
    els.log.prepend(item);
  }

  function handleCaptureError(label, error) {
    const message = error?.name === 'NotAllowedError'
      ? `Permission was not granted for ${label}.`
      : error?.message || `Could not connect ${label}.`;
    log(message);
  }

  function formatBytes(bytes) {
    if (!bytes) return '0 B';
    const units = ['B', 'KB', 'MB', 'GB'];
    const index = Math.min(Math.floor(Math.log(bytes) / Math.log(1024)), units.length - 1);
    return `${(bytes / Math.pow(1024, index)).toFixed(index ? 1 : 0)} ${units[index]}`;
  }
})();
