// The YouTube player's volume arithmetic, kept out of PlayerModal so it can be unit-tested. Every
// rule here was established by a bug: a wheel spin that lost notches to the iframe's lagging
// getVolume, a partial stored object that became NaN and persisted as `null`, and a "corrupt →
// default" fallback that jumped an already-quiet session to full blast.

/** Level used when nothing trustworthy is available. */
export const DEFAULT_VOLUME = 100;

const clamp = (n: number) => Math.max(0, Math.min(100, Math.round(n)));

/**
 * Coerce anything that claims to be a volume into a usable 0–100 level.
 *
 * Only a real, finite `number` is accepted: the stored blob is JSON, so a level is a number or it
 * is corrupt — `null`, `undefined`, `"80"` and `NaN` all mean "we don't know", and `Number(null)`
 * being `0` (silently muting the player) is exactly the coercion to avoid. `fallback` is the last
 * level known to work; it is itself validated, so a corrupt value can never travel through it.
 */
export function normalizeVolume(raw: unknown, fallback: unknown = DEFAULT_VOLUME): number {
  if (typeof raw === "number" && Number.isFinite(raw)) return clamp(raw);
  if (typeof fallback === "number" && Number.isFinite(fallback)) return clamp(fallback);
  return DEFAULT_VOLUME;
}

/** One volume step (wheel notch / arrow key) from `current`.
 *
 * `delta` and `fallback` ride in an options object on purpose: as two adjacent `number`
 * parameters they were transposable without a type error, and swapping them silently steps the
 * volume BY the current level. */
export function stepVolume(current: unknown, opts: { delta: number; fallback: unknown }): number {
  const base = normalizeVolume(current, opts.fallback);
  return clamp(base + opts.delta);
}
