/**
 * Encode an arbitrary audio file (ArrayBuffer) to MP3 in the browser.
 * Uses Web Audio's decodeAudioData to get PCM, then lamejs to encode.
 */
import lamejs from "@breezystack/lamejs";

const BITRATE_KBPS = 128;

export async function encodeToMp3(input: ArrayBuffer): Promise<Uint8Array> {
  const Ctx = window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext;
  const audioCtx = new Ctx();
  // decodeAudioData mutates its input on some browsers; pass a copy.
  const copy = input.slice(0);
  const buffer = await audioCtx.decodeAudioData(copy);
  const sampleRate = buffer.sampleRate;
  const channels = Math.min(2, buffer.numberOfChannels);

  // Get Int16 PCM channel data.
  const left = floatToInt16(buffer.getChannelData(0));
  const right = channels === 2 ? floatToInt16(buffer.getChannelData(1)) : null;

  const encoder = new lamejs.Mp3Encoder(channels, sampleRate, BITRATE_KBPS);
  const blockSize = 1152;
  const mp3Chunks: Uint8Array[] = [];
  for (let i = 0; i < left.length; i += blockSize) {
    const l = left.subarray(i, i + blockSize);
    const r = right ? right.subarray(i, i + blockSize) : null;
    const mp3buf = r ? encoder.encodeBuffer(l, r) : encoder.encodeBuffer(l);
    if (mp3buf.length > 0) mp3Chunks.push(mp3buf);
  }
  const last = encoder.flush();
  if (last.length > 0) mp3Chunks.push(last);

  try { audioCtx.close(); } catch {}

  // Concatenate.
  const total = mp3Chunks.reduce((s, c) => s + c.length, 0);
  const out = new Uint8Array(total);
  let off = 0;
  for (const c of mp3Chunks) { out.set(c, off); off += c.length; }
  return out;
}

function floatToInt16(input: Float32Array): Int16Array {
  const out = new Int16Array(input.length);
  for (let i = 0; i < input.length; i++) {
    const s = Math.max(-1, Math.min(1, input[i]));
    out[i] = s < 0 ? s * 0x8000 : s * 0x7fff;
  }
  return out;
}
