using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Audio;
using DG.Tweening;

namespace OCES.Audio
{
    public class AudioSystem : MonoBehaviour
    {
        public static AudioSystem Instance { get; private set; }
        public bool startWithMusic;
        public ConsoleLogLevel logLevel;
        
        // ReSharper disable once MemberCanBePrivate.Global
        public IReadOnlyDictionary<Type, Enum> ActiveStates { get; private set; }
        public enum ConsoleLogLevel { Off, Log, Warning, Error } //TODO 实现这个功能
        
        const string k_audioConfigPath = "AudioData";
        const string k_audioResourcePath = "Audios";

        SfxSystem m_sfxSystem;
        MusicSystem m_musicSystem;

        AudioObjectConfig m_audioObjects;
        AudioGroupConfig m_groups;
        AudioMixer m_mixer;
        Tween m_lowpassTween;
        
        // ─────────────────────────────────────────────
        // 公开接口
        // ─────────────────────────────────────────────

        public event Action<uint> OnBeat;
        public event Action<uint> OnBar;
        public event Action<uint> OnGrid;

        public void Play(uint audioId, Action onPlay = null)
        {
            AudioObject obj = this.m_audioObjects.QueryById(audioId);
            if (obj != null)
            {
                Play(obj, onPlay);
            }
        }

        public void Play(AudioObject audioObject, Action onPlay = null)
        {
            if (audioObject.ContainerType == ContainerType.Switch)
            {
                audioObject = ResolveSwitchContainer(audioObject);
                if (audioObject == null)
                {
                    Debug.Log("[AudioSystem] 无法解析Switch Container，检查配置表！");
                    return;
                }
            }
            
            this.m_sfxSystem.TryPlay(audioObject, onPlay);
        }

        public void Play(int audioId)
        {
            Play((uint)audioId);
        }
        
        [Obsolete("Use Play(uint) instead")]
        public void Play(string audioName)
        {
            if (!NameDictionaries.NameToId.TryGetValue(audioName, out uint id))
            {
                Debug.LogWarning($"[Audio] Name '{audioName}' not found.");
                return;
            }

            if (NameDictionaries.AmbiguousNames.Contains(audioName))
            {
                Debug.LogWarning(
                    $"[AudioSystem] Name '{audioName}' is ambiguous. Using first matched ID: {id}. " +
                    "Use ID instead to avoid unexpected behavior."
                );
            }

            if (NameDictionaries.SharedIdNames.Contains(audioName))
            {
                Debug.LogWarning(
                    $"[AudioSystem] Name '{audioName}' is a item of a container AudioObject (ID: {id}). " +
                    "Use ID instead to avoid unexpected behavior."
                );
            }

            Play(id);
        }

        public void SetLowpass(bool enable)
        {
            float target = enable ? 440f : 22000f;

            // Kill existing tween to avoid stacking
            if (this.m_lowpassTween != null && this.m_lowpassTween.IsActive())
                this.m_lowpassTween.Kill();

            // Get current value as start
            if (!this.m_mixer.GetFloat("LowpassFreq", out float current))
                current = target;

            float startLog = Mathf.Log10(current);
            float endLog = Mathf.Log10(target);
            
            this.m_lowpassTween = DOTween.To(
                () => startLog,
                x =>
                {
                    startLog = x;
                    float value = Mathf.Pow(10f, startLog);
                    this.m_mixer.SetFloat("LowpassFreq", value);
                },
                endLog,
                0.2f // duration in seconds
            ).SetEase(Ease.OutCubic);
        }

        /// <summary>
        /// 更新游戏状态，驱动音乐与环境音系统切换。
        /// 调用示例：AudioSystem.Instance.SetState(GameState.Game);
        /// </summary>
        public void SetState<TEnum>(TEnum state) where TEnum : Enum
        {
            this.m_musicSystem.OnStateChanged(state);
            ActiveStates = this.m_musicSystem.ActiveStates;
        }

        public void PlayOnTrigger(uint audioId, CallbackFlags callbackFlags)
        {
            Action<uint> callback = null;
            callback = (id) =>
            {
                // 播放音效
                Play(audioId);
        
                // 取消订阅，确保只触发一次
                switch (callbackFlags)
                {
                    case CallbackFlags.MusicSyncBeat:
                        OnBeat -= callback;
                        break;
                    case CallbackFlags.MusicSyncBar:
                        OnBar -= callback;
                        break;
                    case CallbackFlags.MusicSyncGrid:
                        OnGrid -= callback;
                        break;
                }
            };
    
            // 订阅对应的事件
            switch (callbackFlags)
            {
                case CallbackFlags.MusicSyncBeat:
                    OnBeat += callback;
                    break;
                case CallbackFlags.MusicSyncBar:
                    OnBar += callback;
                    break;
                case CallbackFlags.MusicSyncGrid:
                    OnGrid += callback;
                    break;
                
                default:
                    Debug.LogWarning($"[AudioSystem] Unknown callback flag '{callbackFlags}'." +
                                     $"Audio Container with ID {audioId} will be ignored.");
                    break;
            }
        }

        public void Stop(uint audioId)
        {
            this.m_sfxSystem.Stop(audioId);
        }

        // ─────────────────────────────────────────────
        // 初始化
        // ─────────────────────────────────────────────

        void Awake()
        {
            if ((bool)Instance && Instance != this)
            {
                Destroy(gameObject);
                return;
            }
            Instance = this;
            DontDestroyOnLoad(gameObject);

            this.m_mixer        = Resources.Load<AudioMixer>("Audios/Master");
            
            // ── SFX 调度器 ──
            // AudioSystem.cs 中
            GameObject sfxPoolRoot = new("SfxSourcePool");
            sfxPoolRoot.transform.SetParent(transform, false);
            AudioSourcePool sfxPool = new(sfxPoolRoot.transform); // 不传 mixer group，让 SfxSystem 自己设置
            this.m_sfxSystem    = gameObject.AddComponent<SfxSystem>();
            this.m_audioObjects = AudioConfigLoader.Load<AudioObjectConfig>($"{k_audioConfigPath}/AudioObject");
            this.m_audioObjects.PreParseSwitchMappings();
            this.m_groups       = AudioConfigLoader.Load<AudioGroupConfig>($"{k_audioConfigPath}/AudioGroup");
            this.m_sfxSystem.Initialize(this.m_groups, this.m_mixer, sfxPool); // 传入 pool
            

            // ── 音乐与环境音系统 ──
            var segments            = AudioConfigLoader.Load<MusicSegmentConfig>($"{k_audioConfigPath}/MusicSegment");
            var containers          = AudioConfigLoader.Load<MusicContainerConfig>($"{k_audioConfigPath}/MusicContainer");
            var musicPaths          = AudioConfigLoader.Load<MusicPathConfig>($"{k_audioConfigPath}/MusicPath");
            var ambiencePaths       = AudioConfigLoader.Load<AmbiencePathConfig>($"{k_audioConfigPath}/AmbiencePath");
            var musicTransitions    = AudioConfigLoader.Load<MusicTransitionConfig>($"{k_audioConfigPath}/MusicTransition");
            var ambienceTransitions = AudioConfigLoader.Load<AmbienceTransitionConfig>($"{k_audioConfigPath}/AmbienceTransition");

            // MusicSystem 需要运行协程，作为 MonoBehaviour 挂载在同一 GameObject 上
            this.m_musicSystem = gameObject.AddComponent<MusicSystem>();

            // AudioSourcePool 由 MusicSystem 独占一个子节点，与 SFX pool 隔离
            GameObject musicPoolRoot = new("MusicSourcePool");
            musicPoolRoot.transform.SetParent(transform, false);
            AudioMixerGroup musicGroup = this.m_mixer.FindMatchingGroups("Master/Regular/Music")[0];
            AudioSourcePool musicPool = new(musicPoolRoot.transform, musicGroup);

            GameObject ambiencePoolRoot = new("AmbienceSourcePool");
            ambiencePoolRoot.transform.SetParent(transform, false);
            AudioMixerGroup ambienceGroup = this.m_mixer.FindMatchingGroups("Master/Regular/SFX/Ambience")[0];
            AudioSourcePool ambiencePool = new(ambiencePoolRoot.transform, ambienceGroup);

            this.m_musicSystem.Initialize(
                segments,
                containers,
                musicPaths,
                ambiencePaths,
                musicTransitions,
                ambienceTransitions,
                musicPool,
                ambiencePool);
            
            this.m_musicSystem.OnBeat += id => this.OnBeat?.Invoke(id);
            this.m_musicSystem.OnBar  += id => this.OnBar?.Invoke(id);
            this.m_musicSystem.OnGrid += id => this.OnGrid?.Invoke(id);
            
            // ── 注册 StateGroup ──
            Parameters.EnumIds.RegisterAllGameState();

            ActiveStates = new Dictionary<Type, Enum>();
        }

        void Start()
        {
            // ── 启动默认音乐与环境音 ──
            // 触发一次初始状态，让音乐系统从默认状态开始匹配
            if (this.startWithMusic)
            {
                SetState(Parameters.GameState.Home);
            }
        }
       
        AudioObject ResolveSwitchContainer(AudioObject switchContainer)
        {
            // 遍历 ActiveStates 找到 TypeId 匹配的枚举类型
            Enum currentStateValue = null;
            bool foundGroup = false;
            foreach (KeyValuePair<Type, Enum> keyValuePair in ActiveStates)
            {
                if (StateGroupRegistry.GetTypeId(keyValuePair.Key) != switchContainer.SwitchGroupId) continue;
                currentStateValue = keyValuePair.Value;
                foundGroup = true;
                break;
            }

            if (!foundGroup)
            {
                Debug.LogWarning($"[AudioSystem] Switch Container {switchContainer.Id} 找不到 TypeId={switchContainer.SwitchGroupId} 对应的状态组。");
                return this.m_audioObjects.GetDefaultSwitchOrFallback(switchContainer);
            }
            
            // 解析AudioObject对象
            AudioObject childContainer = this.m_audioObjects.GetMappingResult(switchContainer.Id, currentStateValue);
            return childContainer ?? this.m_audioObjects.GetDefaultSwitchOrFallback(switchContainer);
        }


    }

    public static class AudioConfigLoader
    {
        public static T Load<T>(string configPath, string fileName)
            where T : IBinarySerializable, new()
        {
            string path = Path.Combine(
                Application.dataPath, "Resources", configPath, fileName);

            if (!File.Exists(path))
            {
                Debug.LogError($"[AudioImportTool] 找不到配置文件: {path}");
                return default;
            }

            try
            {
                T config = new T();
                using MemoryStream ms = new(File.ReadAllBytes(path));
                using BinaryReader reader = new(ms);
                config.DeSerialize(reader);
                return config;
            }
            catch (Exception e)
            {
                Debug.LogError($"[AudioImportTool] 配置表反序列化失败 {fileName}: {e.Message}");
                return default;
            }
        }

        public static T Load<T>(string tableName) where T : IBinarySerializable, new()
        {
            TextAsset bytes = Resources.Load<TextAsset>(tableName);
            if (!bytes)
                Debug.LogError($"未找到表 {tableName}");
            IBinarySerializable data = new T();
            bool readOk = FileManager.ReadBinaryDataFromBytes(bytes.bytes, ref data);
            if (readOk)
                return (T)data;
            Debug.LogError($"{tableName} 解析出错，类型 {typeof(T)}");
            return default;
        }

        class AudioObjectArrayWrapper<T>
        {
            public T[] AudioObjects;
        }
    }
}
