using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// 音效 音乐管理器
/// 2D声音全局
/// 管理音乐、音效播放 暂停、声音大小管理
/// </summary>
public class MusicManager : BaseManager<MusicManager>
{
    private MusicManager() 
    {
        musicObject = new GameObject("MusicObject");
        GameObject.DontDestroyOnLoad(musicObject);
        musicObject.transform.position = Vector3.zero;
        MonoMgr.Instance.AddUpdateListener(Update);
    }

    /// <summary>
    /// 音乐音效组件挂在的对象
    /// </summary>
    private readonly GameObject musicObject;

    /// <summary>
    /// 背景音乐播放组件
    /// </summary>
    private AudioSource backMusicSource;

    /// <summary>
    /// 播放音效组件
    /// </summary>
    private readonly List<AudioSource> audioSources = new List<AudioSource>();

    /// <summary>
    /// 缓存池中的音效组件
    /// </summary>
    private readonly List<AudioSource> audioSourcesCache =new List<AudioSource>();

    /// <summary>
    /// 标记音效暂停
    /// </summary>
    private bool isPauseSound = false;

    /// <summary>
    /// 播放背景音乐
    /// </summary>
    /// <param name="clipName">b背景音乐资源文件名 Resources下路径名+文件名,不需要文件格式</param>
    /// <param name="volume">背景音乐声音大小</param>
    public void PlayBackMusic(string clipName,float volume)
    {
        ResourcesManager.Instance.LoadAsync<AudioClip>(clipName, (clip) => 
        {
            if (!clip)
            {
                Debug.Log("资源加载失败!请检查文件名");
            }

            //背景音乐播放组件 唯一
            if (backMusicSource == null)
                backMusicSource = musicObject.AddComponent<AudioSource>();
            backMusicSource.playOnAwake = false;
            //背景音乐声音 这个音乐根据项目 会有独立的设置数据 从设置数据传过来
            backMusicSource.volume = volume;
            //背景音乐 文件
            backMusicSource.clip = clip;
            //循环播放
            backMusicSource.loop = true;
            //播放
            backMusicSource.Play();
        });
    }

    /// <summary>
    /// 暂停背景音乐
    /// </summary>
    public void PauseBackMusic()
    {
        if (backMusicSource == null)
            return;
        backMusicSource.Pause();
    }

    /// <summary>
    /// 恢复播放
    /// </summary>
    public void UnPauseBackMusic()
    {
        if (backMusicSource == null)
            return;
        backMusicSource.UnPause();
    }

    /// <summary>
    /// 停止背景音乐
    /// </summary>
    public void StopBackMusic()
    {
        if (backMusicSource == null)
            return;
        backMusicSource.Stop();
    }

    /// <summary>
    /// 改变背景音乐声音大小
    /// </summary>
    /// <param name="volume">声音值</param>
    public void ChangeBackMusic(float volume)
    {
        if (backMusicSource == null)
            return;
        backMusicSource.volume = volume;
    }

    /// <summary>
    /// 背景音乐 静音
    /// </summary>
    /// <param name="isMute"></param>
    public void MuteMusic(bool isMute)
    {
        if (backMusicSource == null)
            return;
        backMusicSource.mute = isMute;
    }

    /// <summary>
    /// 播放音效 
    /// </summary>
    /// <param name="soundName">路径+音效文件名 不需要文件格式</param>
    /// <param name="volume">音效声音</param>
    /// <param name="isLoop">是否循环播放</param>
    /// <param name="action">获取音效播放组件</param>
    public void PlaySound(string soundName, float volume = 1, bool isLoop = false, UnityAction<AudioSource> action = null)
    {
        ResourcesManager.Instance.LoadAsync<AudioClip>(soundName, (clip) =>
        {
            AudioSource audioSource;
            if (audioSourcesCache.Count==0)
            {
                audioSource = musicObject.AddComponent<AudioSource>();
                audioSource.playOnAwake = false;
                audioSourcesCache.Add(audioSource);
            }
            audioSource = audioSourcesCache[0];
            audioSourcesCache.RemoveAt(0);
            //设置声音大小
            audioSource.volume = volume;
            //设置音效资源
            audioSource.clip = clip;
            //循环
            audioSource.loop = isLoop;
            //激活
            audioSource.enabled = true;
            //播放
            audioSource.Play();
            //记录音效组件  这个有可能在多个地方同时调用 需要用锁
            lock (this)
            {
                audioSources.Add(audioSource);

            }
            
            //播放音效后 获取音效组件
            action?.Invoke(audioSource);
        });
    }

    /// <summary>
    /// 暂停所有音效
    /// </summary>
    public void PauseSound()
    {
        isPauseSound= true;
        lock (this)
        {
            for (int i = 0; i < audioSources.Count; i++)
            {
                audioSources[i].Pause();
            }
        }        
    }

    /// <summary>
    /// 重新播放所有正在播放的音效
    /// </summary>
    public void UnPauseSounds()
    {
        isPauseSound = false;
        lock (this)
        {
            for (int i = 0; i < audioSources.Count; i++)
            {
                audioSources[i].UnPause();
            }
        }
    }

    /// <summary>
    /// 静音 音效
    /// </summary>
    /// <param name="isMute"></param>
    public void MuteSound(bool isMute)
    {
        lock(this)
        {
            for (int i = 0; i < audioSources.Count; i++)
            {
                audioSources[i].mute = isMute;
            }
        }
    }

    /// <summary>
    /// 改变音效声音
    /// </summary>
    /// <param name="volume"></param>
    public void ChangeSoundVolume(float volume)
    {
        lock (this)
        {
            for (int i = 0; i < audioSources.Count; i++)
            {
                audioSources[i].volume = volume;
            }
        }
    }

    /// <summary>
    /// 检测音效是否播放完  对播放完的音效进行删除 考虑性能 使用缓存池
    /// </summary>
    private void Update()
    {
        lock (this)
        {
            for (int i = audioSources.Count-1 ; i >= 0; i--)
            {
                if (!audioSources[i].isPlaying && !isPauseSound)
                {
                    audioSources[i].clip = null;
                    audioSources[i].mute = false;
                    audioSources[i].loop = false;
                    audioSources[i].enabled = false;
                    audioSourcesCache.Add(audioSources[i]);
                    audioSources.RemoveAt(i);
                }
            }
        }
    }

    ~MusicManager()
    {
        MonoMgr.Instance.RemoveUpdateListener(Update);
    }
}