// Flash-rate safety.
//
// This project generates beat-reactive video that gets published. Rapid
// light-dark cycling between roughly 3 and 50 Hz is the photosensitive-epilepsy
// trigger, and a generator that flashes a bright scene on every kick of a 128 BPM
// track sits right in that band. WCAG 2.3.1 and the Harding test both use a
// three-flashes-per-second ceiling, which is what this measures.
//
// It is deliberately part of the gate rather than an afterthought: an
// unsupervised generator will find these states on its own, and nobody watches
// every frame of every export.

/** One flash = a min→max→min luminance cycle with amplitude at or above `threshold`. */
export function countFlashes(luminance, { threshold = 0.1 } = {}) {
    if (luminance.length < 3) return 0;

    const extrema = [];
    for (let i = 1; i < luminance.length - 1; i++) {
        const a = luminance[i - 1], b = luminance[i], c = luminance[i + 1];
        if ((b > a && b >= c) || (b < a && b <= c)) {
            extrema.push({ index: i, value: b, isMax: b > a });
        }
    }

    let flashes = 0;
    for (let i = 1; i < extrema.length - 1; i++) {
        const prev = extrema[i - 1], here = extrema[i], next = extrema[i + 1];
        if (!here.isMax) continue;
        const rise = here.value - prev.value;
        const fall = here.value - next.value;
        if (rise >= threshold && fall >= threshold) flashes++;
    }
    return flashes;
}

/** Flashes per second over a luminance series sampled at `fps`. */
export function flashRate(luminance, fps) {
    const seconds = luminance.length / fps;
    return seconds > 0 ? countFlashes(luminance) / seconds : 0;
}

/**
 * Worst flash rate in any one-second window. A track that averages 2/s but has a
 * drop running at 8/s is not safe, and the average would hide it.
 */
export function peakFlashRate(luminance, fps) {
    const window = Math.round(fps);
    if (luminance.length <= window) return flashRate(luminance, fps);
    let worst = 0;
    for (let i = 0; i + window < luminance.length; i += Math.max(1, Math.round(fps / 4))) {
        worst = Math.max(worst, countFlashes(luminance.slice(i, i + window)));
    }
    return worst;
}
