// File -> AudioBuffer. Decoding is done once, up front, and the PCM is kept:
// the analysis pass, the seed hash, the click track and the export mux all read
// the same decoded samples.

let sharedContext = null;

function context() {
    if (!sharedContext) {
        sharedContext = new (window.AudioContext || window.webkitAudioContext)();
    }
    return sharedContext;
}

export async function decodeFile(file) {
    const arrayBuffer = await file.arrayBuffer();
    return decodeArrayBuffer(arrayBuffer);
}

export async function decodeArrayBuffer(arrayBuffer) {
    const ctx = context();
    // decodeAudioData detaches the buffer, so hand it a copy if the caller may
    // still need the original bytes.
    return await ctx.decodeAudioData(arrayBuffer.slice(0));
}

/** Interleaved mono mixdown. Used for the content hash that seeds the look. */
export function monoSamples(audioBuffer) {
    const channels = audioBuffer.numberOfChannels;
    const left = audioBuffer.getChannelData(0);
    if (channels === 1) return left;
    const right = audioBuffer.getChannelData(1);
    const out = new Float32Array(left.length);
    for (let i = 0; i < left.length; i++) out[i] = (left[i] + right[i]) * 0.5;
    return out;
}

export function audioContext() {
    return context();
}

/** Human-readable duration, used by the transport display. */
export function formatTime(seconds) {
    if (!isFinite(seconds) || seconds < 0) return '0:00';
    const m = Math.floor(seconds / 60);
    const s = Math.floor(seconds % 60);
    return `${m}:${String(s).padStart(2, '0')}`;
}
