local AudioManager = {}

local BGM_VOLUME = 0.5
local MAX_EFFECT_NUM = 30

local AUDIO_CLIP = typeof(CS.UnityEngine.AudioClip)

AudioManager.BGM_ID = {
    MAINCITY = "assets/arts/sounds/music/main_city.wav",
    BATTLE = "assets/arts/sounds/music/battle.wav",
    ACT_PVP_CHOOSEBGM = "assets/arts/sounds/music/act_pvp_choosebgm.wav",
    ACT_PVP_FIGHT = "assets/arts/sounds/music/act_pvp_fight.wav",
    ACT_PVP_MAINBGM = "assets/arts/sounds/music/act_pvp_mainbgm.wav",
}

AudioManager.CLICK_ID = {
    [1] = "assets/arts/sounds/sfx/ui/ui_button.wav",
}

AudioManager.EFFECT_ID = {
    BUTTON = "assets/arts/sounds/sfx/ui/ui_button.wav",
    LINK_BO_1 = "assets/arts/sounds/sfx/battle/bo1.wav",
    LINK_BO_2 = "assets/arts/sounds/sfx/battle/bo2.wav",
    LINK_BO_3 = "assets/arts/sounds/sfx/battle/bo3.wav",
    LINK_BO_4 = "assets/arts/sounds/sfx/battle/bo4.wav",
    LINK_BO_5 = "assets/arts/sounds/sfx/battle/bo5.wav",
    LINK_BO_6 = "assets/arts/sounds/sfx/battle/bo6.wav",
    LINK_BO_7 = "assets/arts/sounds/sfx/battle/bo7.wav",
    LINK_BO_8 = "assets/arts/sounds/sfx/battle/bo8.wav",
    LINK_OVER = "assets/arts/sounds/sfx/battle/link_over.wav",
    LINK_READY = "assets/arts/sounds/sfx/battle/link_ready.wav",
    LINK_SKILL = "assets/arts/sounds/sfx/battle/link_skill.wav",
    BATTLE_VICTORY = "assets/arts/sounds/sfx/ui/battle_victory.wav",
    BATTLE_DEFEAT = "assets/arts/sounds/sfx/ui/battle_defeat.wav",
    SUMMON_START = "assets/arts/sounds/sfx/ui/summon_start.wav",
    REWARD = "assets/arts/sounds/sfx/ui/reward.wav",
    HERO_UP = "assets/arts/sounds/sfx/ui/hero_up.wav",
    PLAYER_UP = "assets/arts/sounds/sfx/ui/player_up.wav",
    BOSS_WARNING = "assets/arts/sounds/sfx/battle/warning_boss.wav",
    LINK_CANCEL = "assets/arts/sounds/sfx/battle/link_cancel.wav",
    FUNC_OPEN = "assets/arts/sounds/sfx/ui/func_open.wav",
    BATTLE_BOX_OPEN = "assets/arts/sounds/sfx/ui/ui_battle_open_box.wav",
    EQUIP_WEAPON_UP = "assets/arts/sounds/sfx/ui/equip_up.wav",
    EQUIP_ARMOR_UP = "assets/arts/sounds/sfx/ui/armor_up.wav",
    DUNGEON_SMASH = "assets/arts/sounds/sfx/ui/smash.wav",
    STAR_GET = "assets/arts/sounds/sfx/ui/star_get.wav",
    ACT_PVP_FINISH = "assets/arts/sounds/sfx/ui/act_pvp_finish.wav",
}

AudioManager.BO_EFFECT_ID = {
    [1] = AudioManager.EFFECT_ID.LINK_BO_1,
    [2] = AudioManager.EFFECT_ID.LINK_BO_2,
    [3] = AudioManager.EFFECT_ID.LINK_BO_3,
    [4] = AudioManager.EFFECT_ID.LINK_BO_4,
    [5] = AudioManager.EFFECT_ID.LINK_BO_5,
    [6] = AudioManager.EFFECT_ID.LINK_BO_6,
    [7] = AudioManager.EFFECT_ID.LINK_BO_7,
    [8] = AudioManager.EFFECT_ID.LINK_BO_8,
}

AudioManager.EFFECT_PREFIX = "assets/arts/sounds/sfx/ui/%s.wav"

function AudioManager:getBoEffectID(index)
    local id = AudioManager.BO_EFFECT_ID[index] or AudioManager.EFFECT_ID.LINK_BO_8
    return id
end

function AudioManager:init()
    self.musicEnabled = nil
    self.effectEnabled = nil
    self.musicVolume = 1
    self.effectVolume = 1
    self:setMusicVolume(LocalData:getAudioMusicVolume())
    self:setEffectVolume(LocalData:getAudioEffectVolume())

    self.audioSourcePool = {}
    self.bgmAudioSource = nil
    self.currentMusic = nil
end

function AudioManager:playMusic(audioPath, isLoop)
    if audioPath == nil or audioPath == "" then
        return
    end
    if not self.musicEnabled then
        self.disableMusic = audioPath
        self.disableMusicIsLoop = isLoop
        return
    end
    if self.currentMusic == audioPath then
        local as = self:getMusicSource()
        if self.currentMusicIsLoop ~= isLoop then
            if isLoop == nil then
                as.loop = true
            else
                as.loop = isLoop
            end
        end
    else
        self.currentMusic = audioPath
        self.currentMusicIsLoop = isLoop
        if self.musicPath then
            ResourceManager:unload(self.musicPath)
            self.musicPath = nil
        end
        ResourceManager:loadOriginAssetAsync(audioPath, AUDIO_CLIP, function(path, audioClip)
            if path == self.currentMusic then
                self.musicPath = path
                local as = self:getMusicSource()
                as.clip = audioClip
                if isLoop == nil then
                    isLoop = true
                end
                as.loop = isLoop
                as:Play()
            else
                ResourceManager:unload(path)
            end
        end)
    end
end

function AudioManager:stopMusicById(id, isClear)
    if self.currentMusic == id then
        self:stopMusic(isClear)
    end
end

function AudioManager:stopMusic(isClear)
    local bgmAudioSource = self:getMusicSource()
    if bgmAudioSource then
        bgmAudioSource:Stop()
        if isClear then
            bgmAudioSource.clip = nil
            if self.musicPath then
                ResourceManager:unload(self.musicPath)
                self.musicPath = nil
            end
            self.currentMusic = nil
        end
    end
end

function AudioManager:pauseMusic()
    local bgmAudioSource = self:getMusicSource()
    if bgmAudioSource then
        bgmAudioSource:Pause()
    end
end

function AudioManager:resumeMusic()
    local bgmAudioSource = self:getMusicSource()
    if bgmAudioSource then
        bgmAudioSource:UnPause()
    end
end

function AudioManager:getAudioSourceFromPool(path)
    local audioObj
    for i, v in ipairs(self.audioSourcePool) do
        if not v.audioSource.isPlaying then
            audioObj = v
            if v.path and v.path ~= path then
                ResourceManager:unload(v.path)
                v.path = path
            end
            break
        end
    end
    if not audioObj and #self.audioSourcePool < MAX_EFFECT_NUM then
        local audioSource = CS.BF.BFMain.Instance.SoundManager:addEffectAudioSource()
        audioObj = {
            path = path,
            audioSource = audioSource
        }
        table.insert(self.audioSourcePool, audioObj)
    end
    return audioObj
end

function AudioManager:getMusicSource()
    if not self.bgmAudioSource then
        self.bgmAudioSource = CS.BF.BFMain.Instance.SoundManager:getMusicAudioSource()
    end

    self.bgmAudioSource.volume = self.musicVolume
    return self.bgmAudioSource
end

function AudioManager:playEffect(audioPath, volume)
    if audioPath == nil or audioPath == "" then
        return
    end
    if not self.effectEnabled then
        return
    end
    if volume then
        volume = volume*self.effectVolume
    else
        volume = self.effectVolume
    end

    ResourceManager:loadOriginAssetAsync(audioPath, AUDIO_CLIP, function(path, audioClip)
        if audioClip then
            local asObj = self:getAudioSourceFromPool(path)
            if asObj then
                local audioSource = asObj.audioSource
                audioSource.clip = audioClip
                audioSource.loop = false
                audioSource.volume = volume
                audioSource:Play()
            end
        end
    end)
end

function AudioManager:stopEffect(path)
    for i, v in ipairs(self.audioSourcePool) do
        if v.path and v.path == path then
            v.audioSource:Stop()
        end
    end
end

function AudioManager:isMusicEnabled()
    return self.musicEnabled
end

function AudioManager:isEffectEnabled()
    return self.effectEnabled
end

function AudioManager:setMusicVolume(value)
    self.musicVolume = value or 1
    LocalData:setAudioMusicVolume(self.musicVolume)
    self.musicEnabled = self.musicVolume > 0

    if self.musicEnabled then
        self:getMusicSource()
        if self.disableMusic and self.disableMusic ~= "" then
            self:playMusic(self.disableMusic, self.disableMusicIsLoop)
        end
    else
        if self.currentMusic and self.currentMusic ~= "" then
            self.disableMusic = self.currentMusic
            self.disableMusicIsLoop = self.currentMusicIsLoop
        end
        self:stopMusic(true)
    end
end

function AudioManager:getMusicVolume()
    return self.musicVolume
end

function AudioManager:setEffectVolume(value)
    self.effectVolume = value or 1
    LocalData:setAudioEffectVolume(self.effectVolume)
    self.effectEnabled = self.effectVolume > 0

    if not self.effectEnabled then
        self:stopAndClearAudioFx()
    end
end

function AudioManager:getEffectVolume()
    return self.effectVolume
end

function AudioManager:stopAndClearAudioFx()
    if self.audioSourcePool then
        for i, v in ipairs(self.audioSourcePool) do
            v.audioSource:Stop()
            if v.audioSource.clip then
                v.audioSource.clip = nil
                if v.path then
                    ResourceManager:unload(v.path)
                    v.path = nil
                end
            end
        end
    end
end

function AudioManager:clear()
    self:stopMusic(true)
    self:stopAndClearAudioFx()
    self.bgmAudioSource = nil
    self.audioSourcePool = nil
    CS.BF.BFMain.Instance.SoundManager:clearAudioSource()
end

return AudioManager