﻿using System.Collections.Generic;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Audio
{
    /// <summary>
    /// Audio manager.
    /// </summary>
    [RequireComponent(typeof(AudioMusicHandler), typeof(AudioSoundHandler))]
    public class AudioManager : MonoBehaviour, IAudioManager
    {
        public const string DefaultSettingsNamed = "AudioSettings";

        //当前脚本实例名称(标识)
        [SerializeField] [Tooltip("Instance Name\n实例名称")]
        private string m_Named = AudioManagerPool.DefaultManagerNamed;

        [SerializeField] [Tooltip("Audio Settings\n音频设置")]
        private AudioSettings m_Settings;

        [SerializeField] [Tooltip("Keep when the scene is destroyed\n场景销毁时保留")]
        private bool m_DontDestroyOnLoad = true;

        [SerializeField] [Tooltip("Music Register\n音乐注册表")]
        private AudioInfo[] m_MusicRegisterInfos;

        [SerializeField] [Tooltip("Sound Register\n音效注册")]
        private AudioInfo[] m_SoundRegisterInfos;

        private AudioMusicHandler m_HandlerM;
        private AudioSoundHandler m_HandlerS;
        private AudioCache m_MusicCache;
        private AudioCache m_SoundCache;
        private IAudioLoaderAdapter m_Adapter;
        private readonly List<AudioInfo> m_MusicRegister = new List<AudioInfo>();
        private readonly List<AudioInfo> m_SoundRegister = new List<AudioInfo>();

        private AudioMusicHandler MusicHandler
        {
            get
            {
                m_HandlerM = gameObject.GetComponent<AudioMusicHandler>();
                if (null == m_HandlerM)
                {
                    m_HandlerM = gameObject.AddComponent<AudioMusicHandler>();
                }

                return m_HandlerM;
            }
        }

        private AudioSoundHandler SoundHandler
        {
            get
            {
                m_HandlerS = gameObject.GetComponent<AudioSoundHandler>();
                if (null == m_HandlerM)
                {
                    m_HandlerS = gameObject.AddComponent<AudioSoundHandler>();
                }

                return m_HandlerS;
            }
        }

        internal void InitManager(AudioSettings settings)
        {
            if (null == settings) return;
            m_Settings = settings;
            InitManager();
        }

        private void InitManager()
        {
            if (null == m_Settings) return;
            m_MusicCache = new AudioCache(m_Settings.SysSettings.MusicCacheSize);
            m_SoundCache = new AudioCache(m_Settings.SysSettings.SoundCacheSize);

            MusicHandler.InitSysSettings(m_Settings.SysSettings);
            SoundHandler.InitSysSettings(m_Settings.SysSettings);

            MusicHandler.SetUserSettings(m_Settings.UserSettings);
            SoundHandler.SetUserSettings(m_Settings.UserSettings);

            if (null != m_MusicRegisterInfos) m_MusicRegister.AddRange(m_MusicRegisterInfos);
            if (null != m_SoundRegisterInfos) m_SoundRegister.AddRange(m_SoundRegisterInfos);
        }

        #region Public Functions

        public string Named
        {
            get { return m_Named; }
            set { m_Named = value; }
        }

        public void SetLoaderAdapter(IAudioLoaderAdapter adapter)
        {
            m_Adapter = adapter;
        }

        public bool CheckCache(string key)
        {
            return m_MusicCache.Exist(key);
        }

        public bool SoundPausable => m_Settings.SysSettings.SoundPausable;

        public AudioSettingsUser UserSettings => m_Settings.UserSettings.Clone();

        public void SetUserSettings(AudioSettingsUser userSettings, bool refresh = true)
        {
            if (null == userSettings) return;
            m_Settings.SetUserSettings(userSettings);
            MusicHandler.SetUserSettings(userSettings);
            SoundHandler.SetUserSettings(userSettings);
            if (refresh)
            {
                MusicHandler.ApplyMuted();
                SoundHandler.ApplyMuted();
                MusicHandler.ApplyVolume();
                SoundHandler.ApplyVolume();
            }
        }

        // 音乐相关---------------------

        public bool IsMusicPlaying => MusicHandler.IsMusicPlaying;

        public string PlayingMusicName => MusicHandler.PlayingMusicName;

        public void SetMusicVolume(float volume, bool refresh = true)
        {
            if (null == m_Settings) return;
            m_Settings.UserSettings.VolumeMusic = volume;
            if (refresh)
            {
                MusicHandler.ApplyVolume();
            }
        }

        public void SetMusicMuted(bool muted, bool refresh = true)
        {
            if (null == m_Settings) return;
            if (muted == m_Settings.UserSettings.IsMutedMusic) return;
            m_Settings.UserSettings.IsMutedMusic = muted;
            if (refresh)
            {
                MusicHandler.ApplyMuted();
            }
        }

        public void RegisterMusic(string key, string bundleName, string path)
        {
            if (string.IsNullOrEmpty(key)) return;
            if (m_MusicRegister.Find(info => info.AudioKey == key) != null) return;
            m_MusicRegister.Add(new AudioInfo
            {
                AudioKey = key,
                AudioBundle = bundleName,
                AudioPath = path,
            });
        }

        public void ClearMusicRegister()
        {
            m_MusicRegister.Clear();
        }

        public void SwitchMusic(string key, bool fading = true)
        {
            if (string.IsNullOrEmpty(key)) return;
            var info = m_MusicRegister.Find(audioInfo => audioInfo.AudioKey == key);
            if (null == info) return;
            SwitchMusicByPath(info.AudioKey, info.AudioBundle, info.AudioPath, fading);
        }

        public void SwitchMusic(string key, AudioClip music, bool fading = true)
        {
//            DebugUtil.LogWarning("SwitchMusic:", key, music, fading);
            if (null != music)
            {
                MusicHandler.SwitchMusic(key, music, fading);
                m_MusicCache.AddToCache(key, music);
                return;
            }

            music = GetMusicFromCache(key);
//            DebugUtil.Log("加载Cache:", music == null);
            if (null == music) return;
            MusicHandler.SwitchMusic(key, music, fading);
        }

        public void SwitchMusicByPath(string key, string bundle, string path, bool fading = true)
        {
            var music = GetMusicFromCache(key);
            if (null != music)
            {
                MusicHandler.SwitchMusic(key, music, fading);
                return;
            }

            m_Adapter?.LoadClip(bundle, path, (clip, succ) =>
            {
                if (!succ) return;
                MusicHandler.SwitchMusic(key, clip, fading);
                m_MusicCache.AddToCache(key, clip);
            });
        }

        public void StopMusic(bool fading = false)
        {
            MusicHandler.StopMusic(fading);
        }

        public void PauseMusic()
        {
            MusicHandler.PauseMusic();
        }

        public void GoseOnMusic()
        {
            MusicHandler.GoseOnMusic();
        }

        public void ApplyMusicVolume()
        {
            MusicHandler.ApplyVolume();
        }

        public void ApplyMusicMuted()
        {
            MusicHandler.ApplyMuted();
        }

        // 音效相关---------------------

        public void SetSoundVolume(float volume, bool refresh = true)
        {
            if (null == m_Settings) return;
            m_Settings.UserSettings.VolumeSound = volume;
            if (refresh)
            {
                SoundHandler.ApplyVolume();
            }
        }

        public void SetSoundMuted(bool muted, bool refresh = true)
        {
            if (null == m_Settings) return;
            if (muted == m_Settings.UserSettings.IsMutedSound) return;
            m_Settings.UserSettings.IsMutedSound = muted;
            if (refresh)
            {
                SoundHandler.ApplyMuted();
            }
        }

        public void RegisterSound(string key, string bundleName, string path)
        {
            if (string.IsNullOrEmpty(key)) return;
            if (m_SoundRegister.Find(info => info.AudioKey == key) != null) return;
            m_SoundRegister.Add(new AudioInfo
            {
                AudioKey = key,
                AudioBundle = bundleName,
                AudioPath = path,
            });
        }

        public void ClearSoundRegister()
        {
            m_SoundRegister.Clear();
        }

        public void PlaySound(string key)
        {
            if (string.IsNullOrEmpty(key)) return;
            var info = m_SoundRegister.Find(audioInfo => audioInfo.AudioKey == key);
            if (null == info) return;
            PlaySoundByPath(info.AudioKey, info.AudioBundle, info.AudioPath);
        }

        public void PlaySound(string key, AudioClip sound)
        {
            PlaySound(key, sound, null, 1, !m_Settings.SysSettings.SoundPausable);
        }

        public void PlaySound(string key, AudioClip sound, Transform attachObject)
        {
            PlaySound(key, sound, attachObject, 1, !m_Settings.SysSettings.SoundPausable);
        }

        public void PlaySound(string key, AudioClip sound, float volumeScale)
        {
            PlaySound(key, sound, null, volumeScale, !m_Settings.SysSettings.SoundPausable);
        }

        public void PlaySound(string key, AudioClip sound, bool ignorePause)
        {
            PlaySound(key, sound, null, 1, ignorePause);
        }

        public void PlaySound(string key, AudioClip sound, Transform attachObject, float volumeScale, bool ignorePause)
        {
//            DebugUtil.Log("PlaySound:", key, volumeScale, ignorePause);
            if (null != sound)
            {
                SoundHandler.PlaySound(key, sound, attachObject, volumeScale, !ignorePause);
                m_SoundCache.AddToCache(key, sound);
                return;
            }

            sound = GetSouncFromCache(key);
            if (null == sound) return;

            SoundHandler.PlaySound(key, sound, attachObject, volumeScale, !ignorePause);
        }

        public void PlaySoundByPath(string key, string bundle, string path)
        {
            PlaySoundByPath(key, bundle, path, null, 1, !m_Settings.SysSettings.SoundPausable);
        }

        public void PlaySoundByPath(string key, string bundle, string path, Transform attachObject)
        {
            PlaySoundByPath(key, bundle, path, attachObject, 1, !m_Settings.SysSettings.SoundPausable);
        }

        public void PlaySoundByPath(string key, string bundle, string path, float volumeScale)
        {
            PlaySoundByPath(key, bundle, path, null, volumeScale, !m_Settings.SysSettings.SoundPausable);
        }

        public void PlaySoundByPath(string key, string bundle, string path, bool ignorePause)
        {
            PlaySoundByPath(key, bundle, path, null, 1, ignorePause);
        }

        public void PlaySoundByPath(string key, string bundle, string path, Transform attachObject, float volumeScale, bool ignorePause)
        {
//            DebugUtil.Log("PlaySoundByPath:", key, volumeScale, ignorePause);
            var sound = GetSouncFromCache(key);
            if (null != sound)
            {
                SoundHandler.PlaySound(key, sound, attachObject, volumeScale, !ignorePause);
                return;
            }

            m_Adapter?.LoadClip(bundle, path, (clip, succ) =>
            {
                if (!succ) return;
                SoundHandler.PlaySound(key, clip, attachObject, volumeScale, !ignorePause);
                m_SoundCache.AddToCache(key, clip);
            });
        }

        public void PauseSounds(string key = null)
        {
            SoundHandler.PauseSounds(key);
        }

        public void GoseOnSounds(string key = null)
        {
            SoundHandler.GoesOnSounds(key);
        }

        public void StopSounds(string key = null)
        {
            SoundHandler.StopSounds(key);
        }

        public void ApplySoundVolume()
        {
            SoundHandler.ApplyVolume();
        }

        public void ApplySoundMuted()
        {
            SoundHandler.ApplyMuted();
        }

        #endregion

        #region MonoBehaviour

        private void Awake()
        {
            if (m_DontDestroyOnLoad)
            {
                DontDestroyOnLoad(gameObject);
            }

            AudioManagerPool.AddToMap(this);
            InitManager();
        }

        private void Start()
        {
//            AudioManagerPool.AddToMap(this);
//            InitManager();
        }

        private void OnDestroy()
        {
            m_MusicCache?.Dispose();
            AudioManagerPool.RemoveFromMap(m_Named);
        }

        #endregion

        private AudioClip GetMusicFromCache(string key)
        {
            if (!m_Settings.SysSettings.MusicCacheOpend || !m_MusicCache.Exist(key))
            {
                return null;
            }

            return m_MusicCache.GetAudioClip(key);
        }

        private AudioClip GetSouncFromCache(string key)
        {
            if (!m_Settings.SysSettings.SoundCacheOpend || !m_SoundCache.Exist(key))
            {
                return null;
            }

            return m_SoundCache.GetAudioClip(key);
        }
    }
}