Source: global/audioManager.js

/**
 * @module AudioManager
 * @description Manages background audio for tours and demos
 * @copyright Synaptory Fractal Traveler, 2025-2026
 * @license MIT
 */

import {FF_RIEMANN_TOUR_MUSIC} from './constants';

/** @type {HTMLAudioElement|null} */
let tourAudio = null;

/** @type {boolean} */
let isMuted = false;

/** @type {number|null} */
let fadeInterval = null;

/** @type {boolean} */
let audioReady = false;

/** Default volume level (0-1) */
const DEFAULT_VOLUME = 0.4;

/** Fade duration in ms */
const FADE_DURATION = 2000;

/** Fade step interval in ms */
const FADE_STEP = 50;

/**
 * Initializes the audio element for the Riemann tour.
 * Call this once at app startup.
 * @param {string} audioSrc - Path to the audio file
 */
export function initTourAudio(audioSrc) {
    if (!FF_RIEMANN_TOUR_MUSIC) {
        console.log('AudioManager: Tour music disabled by feature flag');
        return;
    }

    if (tourAudio) {
        console.log('AudioManager: Tour audio already initialized');
        return;
    }

    try {
        tourAudio = new Audio(audioSrc);
        tourAudio.loop = true;
        tourAudio.volume = 0;
        tourAudio.preload = 'auto';

        tourAudio.addEventListener('canplaythrough', () => {
            audioReady = true;
            console.log('AudioManager: Audio loaded and ready to play');
        });

        tourAudio.addEventListener('error', (e) => {
            const error = tourAudio?.error;
            console.error('AudioManager: Failed to load tour audio', {
                code: error?.code,
                message: error?.message,
                src: audioSrc
            });
            tourAudio = null;
            audioReady = false;
        });

        tourAudio.addEventListener('loadstart', () => {
            console.log('AudioManager: Loading audio from', audioSrc);
        });

        // Force load
        tourAudio.load();

        console.log('AudioManager: Tour audio initialized');
    } catch (e) {
        console.error('AudioManager: Could not create audio element', e);
        tourAudio = null;
    }
}

/**
 * Starts playing the tour music with a fade-in effect.
 * @returns {Promise<void>}
 */
export async function startTourMusic() {
    console.log('AudioManager: startTourMusic called', {
        featureFlag: FF_RIEMANN_TOUR_MUSIC,
        tourAudio: !!tourAudio,
        audioReady,
        isMuted
    });

    if (!FF_RIEMANN_TOUR_MUSIC) {
        console.log('AudioManager: Feature flag disabled');
        return;
    }

    if (!tourAudio) {
        console.warn('AudioManager: No audio element available');
        return;
    }

    if (isMuted) {
        console.log('AudioManager: Audio is muted');
        return;
    }

    // Clear any existing fade
    if (fadeInterval) {
        clearInterval(fadeInterval);
        fadeInterval = null;
    }

    try {
        tourAudio.currentTime = 0;
        tourAudio.volume = 0.01; // Start with tiny volume (some browsers need non-zero)

        console.log('AudioManager: Attempting to play...');
        const playPromise = tourAudio.play();

        if (playPromise !== undefined) {
            await playPromise;
            console.log('AudioManager: Play started successfully');
        }

        // Fade in
        const targetVolume = DEFAULT_VOLUME;
        const steps = FADE_DURATION / FADE_STEP;
        const volumeStep = targetVolume / steps;

        fadeInterval = setInterval(() => {
            if (!tourAudio) {
                clearInterval(fadeInterval);
                fadeInterval = null;
                return;
            }
            if (tourAudio.volume < targetVolume - volumeStep) {
                tourAudio.volume = Math.min(targetVolume, tourAudio.volume + volumeStep);
            } else {
                tourAudio.volume = targetVolume;
                clearInterval(fadeInterval);
                fadeInterval = null;
                console.log('AudioManager: Fade-in complete, volume:', targetVolume);
            }
        }, FADE_STEP);

    } catch (e) {
        console.error('AudioManager: Could not play audio', e.name, e.message);
        // NotAllowedError = autoplay blocked, need user interaction
        if (e.name === 'NotAllowedError') {
            console.warn('AudioManager: Autoplay blocked - browser requires user interaction first');
        }
    }
}

/**
 * Stops the tour music with a fade-out effect.
 * @returns {Promise<void>}
 */
export async function stopTourMusic() {
    if (!tourAudio) {
        return;
    }

    // Clear any existing fade
    if (fadeInterval) {
        clearInterval(fadeInterval);
        fadeInterval = null;
    }

    if (tourAudio.paused) {
        return;
    }

    console.log('AudioManager: Stopping tour music');

    // Fade out
    const startVolume = tourAudio.volume;
    if (startVolume === 0) {
        tourAudio.pause();
        return;
    }

    const steps = FADE_DURATION / FADE_STEP;
    const volumeStep = startVolume / steps;

    return new Promise((resolve) => {
        fadeInterval = setInterval(() => {
            if (!tourAudio) {
                clearInterval(fadeInterval);
                fadeInterval = null;
                resolve();
                return;
            }
            if (tourAudio.volume > volumeStep) {
                tourAudio.volume = Math.max(0, tourAudio.volume - volumeStep);
            } else {
                tourAudio.volume = 0;
                tourAudio.pause();
                clearInterval(fadeInterval);
                fadeInterval = null;
                console.log('AudioManager: Fade-out complete');
                resolve();
            }
        }, FADE_STEP);
    });
}

/**
 * Toggles mute state for tour music.
 * @returns {boolean} New mute state
 */
export function toggleMute() {
    isMuted = !isMuted;

    if (tourAudio) {
        if (isMuted) {
            tourAudio.volume = 0;
        } else if (!tourAudio.paused) {
            tourAudio.volume = DEFAULT_VOLUME;
        }
    }

    console.log(`AudioManager: Tour music ${isMuted ? 'muted' : 'unmuted'}`);
    return isMuted;
}

/**
 * Returns current mute state.
 * @returns {boolean}
 */
export function isTourMusicMuted() {
    return isMuted;
}

/**
 * Returns whether tour music is currently playing.
 * @returns {boolean}
 */
export function isTourMusicPlaying() {
    return tourAudio && !tourAudio.paused;
}

/**
 * Sets the volume for tour music.
 * @param {number} volume - Volume level (0-1)
 */
export function setTourMusicVolume(volume) {
    if (tourAudio && !isMuted) {
        tourAudio.volume = Math.max(0, Math.min(1, volume));
    }
}

/**
 * Cleans up audio resources.
 */
export function destroyTourAudio() {
    if (fadeInterval) {
        clearInterval(fadeInterval);
        fadeInterval = null;
    }

    if (tourAudio) {
        tourAudio.pause();
        tourAudio.src = '';
        tourAudio = null;
    }
    audioReady = false;

    console.log('AudioManager: Tour audio destroyed');
}