// Resample an arbitrary-length waveform into `bars` peak-per-bucket values
// normalized to 0..1. Handles both the on-wire MSC1767/Telegram integers
// (0..1024) and a 0..1 float sender via max-detection (peak > 1 ⇒ divide by
// peak). Used by the voice-note bubble and the recorder preview.
// The waveform arrives straight from hostile event content
// (`org.matrix.msc1767.audio.waveform`), so it may be ANY JSON value, not the
// `number[]` the type claims. Reject non-arrays and coerce non-finite samples
// to 0 — otherwise `.reduce` / `Math.abs` on a non-array (or a NaN sample)
// throws during render and, absent a per-message error boundary, white-screens
// the whole client (persistent DoS on the persisted event).
const sample = (v: unknown): number => {
  const n = typeof v === 'number' ? v : Number(v);
  return Number.isFinite(n) ? Math.abs(n) : 0;
};

export const normalizeWaveform = (waveform: number[] | undefined, bars: number): number[] => {
  if (!Array.isArray(waveform) || waveform.length === 0) return [];
  const peak = waveform.reduce((m, v) => Math.max(m, sample(v)), 0);
  const divisor = peak > 1 ? peak : 1;
  const out: number[] = [];
  const bucket = waveform.length / bars;
  for (let i = 0; i < bars; i += 1) {
    const start = Math.floor(i * bucket);
    const end = Math.max(start + 1, Math.floor((i + 1) * bucket));
    let localMax = 0;
    for (let j = start; j < end && j < waveform.length; j += 1) {
      localMax = Math.max(localMax, sample(waveform[j]));
    }
    out.push(Math.min(1, localMax / divisor));
  }
  return out;
};
