using System;
using FairyGUI;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BingoBrain.Asset;
using UnityEngine.Events;

namespace BingoBrain.Core
{
    public sealed class Audio : BaseUnity<Audio>
    {
        #region 变量定义

        public const bool IsUnscaleTime = true;


        private Dictionary<string, AudioClip> audioClipCacheDict = new Dictionary<string, AudioClip>();


        private GameObject newEffectSourcesRoot;


        private GameObject dynamicEffectSourcesRoot;


        [HideInInspector] public AudioListener audioListener;


        [HideInInspector] public AudioSource bgmSource;


        [HideInInspector] public AudioSource effectSource;


        [HideInInspector] public List<AudioSource> newEffectSources = new List<AudioSource>();


        [HideInInspector] public List<AudioSource> dynamicEffectSources = new List<AudioSource>();


        [HideInInspector] public List<AudioSource> unscaleTimeSounds = new List<AudioSource>();


        [HideInInspector] public float currUISoundVolume = 1;

        #endregion 变量定义

        #region 音乐开关

        private bool isOpenBGM;

        public bool IsOpenBGM
        {
            get { return isOpenBGM; }
            set
            {
                isOpenBGM = value;
                RrysKit.WriteBool(FsyConst.AudioMgr_isOpenBGM, isOpenBGM);
                if (!bgmSource) return;

                bgmSource.enabled = isOpenBGM;
                if (isOpenBGM)
                {
                    bgmSource.Play();
                }
                else
                {
                    bgmSource.Pause();
                }
            }
        }

        private bool isOpenEffect;

        public bool IsOpenEffect
        {
            get { return isOpenEffect; }
            set
            {
                isOpenEffect = value;
                RrysKit.WriteBool(FsyConst.AudioMgr_isOpenEffect, isOpenEffect);


                GRoot.inst.soundVolume = isOpenEffect ? currUISoundVolume : 0f;
                if (isOpenEffect)
                {
                    GRoot.inst.EnableSound();
                }
                else
                {
                    GRoot.inst.DisableSound();
                }
            }
        }

        private void InitAudioMode()
        {
            isOpenBGM = RrysKit.ReadBool(FsyConst.AudioMgr_isOpenBGM, true);
            isOpenEffect = RrysKit.ReadBool(FsyConst.AudioMgr_isOpenEffect, true);


            GRoot.inst.soundVolume = 1;
            currUISoundVolume = GRoot.inst.soundVolume;
            GRoot.inst.soundVolume = isOpenEffect ? currUISoundVolume : 0f;
        }

        public void PauseAllSource()
        {
            bgmSource.Pause();

            IsOpenEffect = false;
            effectSource.Pause();
            for (int i = 0; i < newEffectSources.Count; i++)
            {
                newEffectSources[i].Pause();
            }

            for (int i = 0; i < dynamicEffectSources.Count; i++)
            {
                dynamicEffectSources[i].Pause();
            }


            GRoot.inst.DisableSound();
        }

        public void UnPauseAllSource()
        {
            bgmSource.UnPause();

            IsOpenEffect = true;
            effectSource.UnPause();
            for (int i = 0; i < newEffectSources.Count; i++)
            {
                newEffectSources[i].UnPause();
            }

            for (int i = 0; i < dynamicEffectSources.Count; i++)
            {
                dynamicEffectSources[i].UnPause();
            }


            GRoot.inst.EnableSound();
        }

        #endregion 音乐开关

        #region 音量控制

        public float BgmVolume
        {
            get { return bgmSource.volume; }
            set { bgmSource.volume = value; }
        }


        public float EffectVolume
        {
            get { return effectSource.volume; }
            set { effectSource.volume = value; }
        }


        public float newEffectVolume
        {
            get
            {
                for (int i = 0; i < newEffectSources.Count; i++)
                {
                    return newEffectSources[i].volume;
                }

                return 0;
            }
            set
            {
                for (int i = 0; i < newEffectSources.Count; i++)
                {
                    newEffectSources[i].volume = value;
                }
            }
        }


        public float dynamicEffectVolume
        {
            get
            {
                for (int i = 0; i < dynamicEffectSources.Count; i++)
                {
                    return dynamicEffectSources[i].volume;
                }

                return 0;
            }
            set
            {
                for (int i = 0; i < dynamicEffectSources.Count; i++)
                {
                    dynamicEffectSources[i].volume = value;
                }
            }
        }

        #endregion

        #region 初始化

        public override void Init()
        {
            base.Init();
            AppDispatcher.Instance.AddListener(CsjInfoC.TimeScale_Change, OnTimeScaleChange);

            audioListener = gameObject.AddComponent<AudioListener>();

            bgmSource = gameObject.AddComponent<AudioSource>();
            bgmSource.playOnAwake = false;
            bgmSource.loop = true;

            effectSource = gameObject.AddComponent<AudioSource>();
            effectSource.playOnAwake = false;
            effectSource.loop = false;

            newEffectSourcesRoot = new GameObject("NewEffectSources");
            newEffectSourcesRoot.transform.SetParent(gameObject.transform, false);
            dynamicEffectSourcesRoot = new GameObject("DynamicEffectSources");
            dynamicEffectSourcesRoot.transform.SetParent(gameObject.transform, false);

            InitAudioMode();
        }

        public override void Dispose()
        {
            base.Dispose();
            AppDispatcher.Instance.RemoveListener(CsjInfoC.TimeScale_Change, OnTimeScaleChange);
        }

        public void InitDefaultButtonClickSound(string btnSound)
        {
            string defaultSound = DoConst.UIButtonDefault;
            if (!string.IsNullOrEmpty(btnSound))
            {
                defaultSound = btnSound;
            }

            BetKit.Instance.LoadAudio("Audio", defaultSound, audioClip =>
            {
                if (audioClip != null)
                {
                    UIConfig.buttonSound = new NAudioClip(audioClip);
                    UIConfig.buttonSoundVolumeScale = 1;
                }
            });
        }

        private void OnTimeScaleChange(object value)
        {
            if (unscaleTimeSounds.Count != 0)
            {
                for (int i = 0; i < unscaleTimeSounds.Count; i++)
                {
                    AudioSource audioSource = unscaleTimeSounds[i];
                    if (audioSource)
                    {
                        audioSource.pitch = Jsvva.NormalTimeScale;
                    }
                }
            }
        }

        #endregion 初始化

        #region 背景音乐: 只有一个播放器

        public void PlayBGM(string audioName, bool isUnscaleTime = IsUnscaleTime)
        {
            if (string.IsNullOrEmpty(audioName)) return;


            string curName;
            if (bgmSource.clip == null)
            {
                curName = null;
            }
            else
            {
                curName = bgmSource.clip.name;
            }

            if (curName != audioName)
            {
                AudioClip currClip = null;
                if (audioClipCacheDict.ContainsKey(audioName))
                {
                    currClip = audioClipCacheDict[audioName];
                }
                else
                {
                    currClip = BetKit.Instance.LoadAsset<AudioClip>("Audio", audioName);
                }


                if (currClip != null)
                {
                    bgmSource.clip = currClip;
                    if (!isOpenBGM)
                    {
                        return;
                    }

                    if (isUnscaleTime)
                    {
                        if (!unscaleTimeSounds.Contains(bgmSource))
                        {
                            unscaleTimeSounds.Add(bgmSource);
                        }
                    }
                    else
                    {
                        if (unscaleTimeSounds.Contains(bgmSource))
                        {
                            unscaleTimeSounds.Remove(bgmSource);
                        }
                    }

                    bgmSource.pitch = isUnscaleTime ? Jsvva.NormalTimeScale : Jsvva.GetTimeScale();
                    bgmSource.Play();
                }
            }
        }


        public void StopBGM()
        {
            bgmSource.Stop();
            bgmSource.clip = null;
        }

        #endregion 背景音乐

        #region 音效: 只有一个播放器

        public void PlayOnceEffect(string audioName, bool isLoop = false, bool isUnscaleTime = IsUnscaleTime)
        {
            if (!isOpenEffect || string.IsNullOrEmpty(audioName)) return;


            string currName;
            AudioClip currClip = null;
            if (effectSource.clip == null)
            {
                currName = null;
            }
            else
            {
                currClip = effectSource.clip;
                currName = currClip.name;
            }

            if (currName != audioName)
            {
                if (audioClipCacheDict.ContainsKey(audioName))
                {
                    currClip = audioClipCacheDict[audioName];
                }
                else
                {
                    currClip = BetKit.Instance.LoadAsset<AudioClip>("Audio", audioName);
                }
            }


            if (currClip)
            {
                if (effectSource.loop != isLoop)
                {
                    effectSource.loop = isLoop;
                }

                effectSource.clip = currClip;

                if (isUnscaleTime)
                {
                    if (!unscaleTimeSounds.Contains(effectSource))
                    {
                        unscaleTimeSounds.Add(effectSource);
                    }
                }
                else
                {
                    if (unscaleTimeSounds.Contains(effectSource))
                    {
                        unscaleTimeSounds.Remove(effectSource);
                    }
                }

                effectSource.pitch = isUnscaleTime ? Jsvva.NormalTimeScale : Jsvva.GetTimeScale();
                effectSource.Play();
            }
        }


        public void PlayFullOnceEffect(string audioName)
        {
            if (!effectSource.isPlaying)
            {
                PlayOnceEffect(audioName);
            }
        }


        public void StopOnceEffect()
        {
            effectSource.Stop();
            effectSource.clip = null;
        }


        public void PauseOnceEffect()
        {
            effectSource.Pause();
        }


        public void ContinuousOnceEffect()
        {
            effectSource.Play();
        }

        #endregion 音效

        #region 新建音效

        public AudioSource NewAudioSource()
        {
            AudioSource newEffectSource = newEffectSourcesRoot.AddComponent<AudioSource>();
            newEffectSource.playOnAwake = false;
            newEffectSource.loop = false;
            newEffectSources.Add(newEffectSource);
            return newEffectSource;
        }


        public void PlayOnceEffect(AudioSource source, string audioName, bool isLoop = false,
            bool isUnscaleTime = IsUnscaleTime)
        {
            if (!isOpenEffect || string.IsNullOrEmpty(audioName)) return;


            string currName;
            AudioClip currClip = null;
            if (source.clip == null)
            {
                currName = null;
            }
            else
            {
                currClip = source.clip;
                currName = currClip.name;
            }

            if (currName != audioName)
            {
                if (audioClipCacheDict.ContainsKey(audioName))
                {
                    currClip = audioClipCacheDict[audioName];
                }
                else
                {
                    currClip = BetKit.Instance.LoadAsset<AudioClip>("Audio", audioName);
                }
            }


            if (currClip)
            {
                if (source.loop != isLoop)
                {
                    source.loop = isLoop;
                }

                source.clip = currClip;

                if (isUnscaleTime)
                {
                    if (!unscaleTimeSounds.Contains(source))
                    {
                        unscaleTimeSounds.Add(source);
                    }
                }
                else
                {
                    if (unscaleTimeSounds.Contains(source))
                    {
                        unscaleTimeSounds.Remove(source);
                    }
                }

                source.pitch = isUnscaleTime ? Jsvva.NormalTimeScale : Jsvva.GetTimeScale();
                source.Play();
            }
        }


        public void PlayFullOnceEffect(AudioSource source, string audioName)
        {
            if (!source.isPlaying)
            {
                PlayOnceEffect(source, audioName);
            }
        }


        public void StopOnceEffect(AudioSource source)
        {
            source.Stop();
            source.clip = null;
        }

        #endregion

        #region 动态音效: 多个播放器

        public AudioSource PlayDynamicEffect(string audioName, float delay = 0, bool isLoop = false,
            bool isUnscaleTime = IsUnscaleTime)
        {
            if (!isOpenEffect || string.IsNullOrEmpty(audioName)) return null;

            AudioSource effectSourceCom = null;
            for (int i = 0; i < dynamicEffectSources.Count; i++)
            {
                AudioSource sourceItem = dynamicEffectSources[i];
                if (!sourceItem.isPlaying)
                {
                    effectSourceCom = sourceItem;
                    break;
                }
            }

            if (effectSourceCom == null)
            {
                effectSourceCom = dynamicEffectSourcesRoot.AddComponent<AudioSource>();
                effectSourceCom.playOnAwake = false;
                dynamicEffectSources.Add(effectSourceCom);
            }

            if (effectSourceCom.loop != isLoop)
            {
                effectSourceCom.loop = isLoop;
            }


            string curName;
            AudioClip currClip = null;
            if (effectSourceCom.clip == null)
            {
                curName = null;
            }
            else
            {
                currClip = effectSourceCom.clip;
                curName = currClip.name;
            }

            var playAction = new UnityAction(delegate
            {
                if (currClip != null)
                {
                    effectSourceCom.clip = currClip;

                    if (isUnscaleTime)
                    {
                        if (!unscaleTimeSounds.Contains(effectSourceCom))
                        {
                            unscaleTimeSounds.Add(effectSourceCom);
                        }
                    }
                    else
                    {
                        if (unscaleTimeSounds.Contains(effectSourceCom))
                        {
                            unscaleTimeSounds.Remove(effectSourceCom);
                        }
                    }

                    effectSourceCom.pitch =
                        isUnscaleTime ? Jsvva.NormalTimeScale : Jsvva.GetTimeScale();
                    if (delay == 0)
                    {
                        effectSourceCom.Play();
                    }
                    else
                    {
                        effectSourceCom.PlayDelayed(delay);
                    }
                }
            });

            if (curName != audioName)
            {
                if (audioClipCacheDict.ContainsKey(audioName))
                {
                    currClip = audioClipCacheDict[audioName];
                    playAction();
                }
                else
                {
                    var path = new StringBuilder("Audio");
                    var strs = audioName.Split('.');
                    var assetName = strs.Last();
                    if (strs.Length > 1)
                    {
                        var assetUrl = audioName.Replace($".{assetName}", string.Empty);
                        path.Append(".").Append(assetUrl);
                    }

                    BetKit.Instance.LoadAudio(path.ToString(), assetName, (clip) =>
                    {
                        currClip = clip;
                        audioClipCacheDict[audioName] = clip;
                        playAction();
                    });
                }
            }
            else
            {
                try
                {
                    if (delay == 0)
                    {
                        effectSourceCom.Play();
                    }
                    else
                    {
                        effectSourceCom.PlayDelayed(delay);
                    }
                }
                catch (System.Exception)
                {
                }
            }


            return effectSourceCom;
        }

        #endregion 动态音效

        #region UI声音: 只有一个播放器

        public void PlayUIButtonAudio()
        {
            PlayOnceEffect(DoConst.UIButtonDefault);
        }

        #endregion UI声音

        #region 玩法声音: 多个播放器

        public void PlayGameAudio(string audioName, float delay = 0, bool isLoop = false,
            bool isUnscaleTime = IsUnscaleTime)
        {
            PlayDynamicEffect(audioName, delay, isLoop, isUnscaleTime);
        }

        #endregion 玩法声音
    }
}