import { assetUrl } from '@/commons/assets'

const game1MusicUrl = assetUrl('game1.mp3')
const game2MusicUrl = assetUrl('game2.mp3')
const game3Music1Url = assetUrl('game3_1.mp3')
const game3Music2Url = assetUrl('game3_2.mp3')
const game6Music1Url = assetUrl('game6_1.mp3')
const game6Music2Url = assetUrl('game6_2.mp3')
const go321 = assetUrl('321go.mp3')


const effectTemplates = new Map<string, HTMLAudioElement>()
const playingEffects = new Set<HTMLAudioElement>()
const exclusiveEffects = new Map<string, HTMLAudioElement>()
let pendingPlay = false
let pendingRetry: (() => void) | null = null


export function stopAllMusic() {
    stopGame1Music();
    stopGame2Music();
    stopGame3Music();
    // stopGame4Music();
    // stopGame5Music();
    stopGame6Music();
    playingEffects.clear();
}



function getEffectTemplate(music: string) {
    let template = effectTemplates.get(music)

    if (!template) {
        template = new Audio(music)
        template.loop = false
        template.preload = 'auto'
        template.volume = 1
        template.load()
        effectTemplates.set(music, template)
    }

    return template
}

function releaseEffect(audio: HTMLAudioElement) {
    audio.pause()
    audio.removeAttribute('src')
    audio.load()
    playingEffects.delete(audio)
}

function clearPendingRetry() {
    if (pendingRetry) {
        window.removeEventListener('pointerdown', pendingRetry)
        window.removeEventListener('keydown', pendingRetry)
        pendingRetry = null
    }
    pendingPlay = false
}

function setPendingRetry(retry: () => void) {
    clearPendingRetry()
    pendingPlay = true
    pendingRetry = retry
    window.addEventListener('pointerdown', retry, { once: true })
    window.addEventListener('keydown', retry, { once: true })
}

async function playEffect(music: string, retry: () => void, exclusive = false) {
    if (exclusive && exclusiveEffects.has(music)) {
        return
    }

    const audio = getEffectTemplate(music).cloneNode(true) as HTMLAudioElement
    audio.loop = false
    audio.volume = 1
    playingEffects.add(audio)
    if (exclusive) {
        exclusiveEffects.set(music, audio)
    }

    const release = () => {
        if (exclusiveEffects.get(music) === audio) {
            exclusiveEffects.delete(music)
        }
        releaseEffect(audio)
    }
    audio.addEventListener('ended', release, { once: true })
    audio.addEventListener('error', release, { once: true })

    try {
        await audio.play()
        if (pendingRetry === retry) {
            clearPendingRetry()
        }
    } catch {
        release()

        if (!pendingPlay) {
            setPendingRetry(retry)
        }
    }
}

function stopEffects() {
    clearPendingRetry()
    for (const audio of playingEffects) {
        releaseEffect(audio)
    }
    playingEffects.clear()
    exclusiveEffects.clear()
}

export async function playGame1Music() {
    await playEffect(game1MusicUrl, playGame1Music)
}

export function stopGame1Music() {
    window.removeEventListener('pointerdown', playGame1Music)
    window.removeEventListener('keydown', playGame1Music)
    stopEffects()
}

/*  3 2 1 go */
export async function playCountdownMusic() {
    await playEffect(go321, playCountdownMusic)
}

export function stopCountdownMusic() {
    window.removeEventListener('pointerdown', playCountdownMusic)
    window.removeEventListener('keydown', playCountdownMusic)
    stopEffects()
}

export async function playGame2Music() {
    await playEffect(game2MusicUrl, playGame2Music, true)
}

export function stopGame2Music() {
    window.removeEventListener('pointerdown', playGame2Music)
    window.removeEventListener('keydown', playGame2Music)
    stopEffects()
}
/*
接到红包3-1
接到炸弹3-2
*/
export async function playGame3Music(index: number) {
    let arr: [string, string, string] = ['', game3Music1Url, game3Music2Url];
    const music = arr[index]

    if (!music) {
        return
    }

    const retry = () => { playGame3Music(index) }
    await playEffect(music, retry)
}

export function stopGame3Music() {
    stopEffects()
}


/*
打地鼠击中爆炸6-1
打小白兔眩晕6-2
*/
export async function playGame6Music(index: number) {
    let arr: [string, string, string] = ['', game6Music1Url, game6Music2Url];
    const music = arr[index]

    if (!music) {
        return
    }

    const retry = () => { playGame6Music(index) }
    await playEffect(music, retry)
}

export function stopGame6Music() {
    stopEffects()
}
