using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Random = UnityEngine.Random;

namespace OCES.Audio
{
    /// <summary>
    /// 负责递归播放一个 MusicContainer 树。
    /// 被 MusicChannelPlayer 和 AmbienceChannelPlayer 共同使用。
    /// 不持有状态机逻辑，只负责"把这个 Container 播完"。
    /// </summary>
    class MusicContainerPlayer
    {
        readonly MusicContainerConfig m_containerConfig;
        readonly MusicSegmentConfig m_segmentConfig;
        readonly AudioSourcePool m_pool;
        readonly MonoBehaviour m_coroutineHost;
        UnityEngine.Audio.AudioMixerGroup m_mixerGroup;

        /// <summary>
        /// 开始播放Container时触发 音乐回调系统
        /// container本身，继承来的bpm，进入时刻的dspTime
        /// </summary>
        internal event Action<MusicContainer, float, double> OnContainerEntered;
        internal event Action<MusicContainer> OnBlendError;

        // Sequence Step 模式的全局游标，key = containerId
        readonly Dictionary<uint, int> m_sequenceStepIndex = new();

        // Random 模式的不放回历史，key = containerId
        readonly Dictionary<uint, HashSet<uint>> m_randomHistory = new();

        public MusicContainerPlayer(
            MusicContainerConfig containerConfig,
            MusicSegmentConfig segmentConfig,
            AudioSourcePool pool,
            MonoBehaviour coroutineHost)
        {
            this.m_containerConfig = containerConfig;
            this.m_segmentConfig   = segmentConfig;
            this.m_pool            = pool;
            this.m_coroutineHost   = coroutineHost;
        }

        // ─────────────────────────────────────────────
        // 公开入口
        // ─────────────────────────────────────────────

        /// <summary>
        /// 开始播放指定 Container，播放完毕后调用 onFinished。
        /// 返回可用于外部停止的句柄。
        /// </summary>
        internal ContainerPlayHandle Play(uint containerId, Action onFinished = null, float inheritedBpm = 0f)
        {
            MusicContainer container = this.m_containerConfig.QueryById(containerId);
            if (container == null)
            {
                Debug.LogError($"[MusicContainerPlayer] 找不到 ContainerId: {containerId}");
                onFinished?.Invoke();
                return null;
            }

            ContainerPlayHandle handle = new();
            handle.TargetVolume = 1f;
            handle.Coroutine = this.m_coroutineHost.StartCoroutine(
                PlayContainerCoroutine(container, handle, inheritedBpm, onFinished));
            return handle;
        }

        /// <summary>
        /// 停止一个播放句柄（立即停止，不淡出）
        /// </summary>
        public void Stop(ContainerPlayHandle handle)
        {
            if (handle == null) return;
            handle.Cancelled = true;

            foreach (ContainerPlayHandle child in handle.ChildHandles)
            {
                Stop(child);
            }
            handle.ChildHandles.Clear();
            
            
            if (handle.Coroutine != null)
                this.m_coroutineHost.StopCoroutine(handle.Coroutine);
            foreach (AudioSource src in handle.ActiveSources)
            {
                ReturnSource(src);
            }
            handle.ActiveSources.Clear();
        }

        // ─────────────────────────────────────────────
        // 核心协程
        // ─────────────────────────────────────────────

        IEnumerator PlayContainerCoroutine(
            MusicContainer container,
            ContainerPlayHandle handle,
            float inheritedBpm,
            Action onFinished)
        {
            float effectiveBpm = container.Bpm > 0f ? container.Bpm : inheritedBpm;
            //Debug.Log($"[MusicContainerPlayer] OnContainerEntered firing, container={container.Id}, subscribers={OnContainerEntered != null}");
            OnContainerEntered?.Invoke(container, effectiveBpm, AudioSettings.dspTime);
            
            int loopsCompleted = 0;

            while (true)
            {
                yield return this.m_coroutineHost.StartCoroutine(
                    PlayContainerOnce(container, handle.TargetVolume, handle, effectiveBpm));

                if (handle.Cancelled) yield break;

                loopsCompleted++;

                // -1 = 无限循环，一直重复
                if (container.LoopCount == -1)
                    continue;

                // 0 = 不循环，播一次就结束
                if (container.LoopCount == 0)
                    break;

                // >= 1，播满次数后结束
                if (loopsCompleted >= container.LoopCount)
                    break;
            }

            if (!handle.Cancelled)
                onFinished?.Invoke();
        }

        /// <summary>
        /// 播放一个 Container 一轮（不含循环逻辑）
        /// </summary>
        IEnumerator PlayContainerOnce(MusicContainer container, float volumeScale, ContainerPlayHandle handle, float inheritedBpm)
        {
            if (container.Segments == null || container.Segments.Count == 0)
                yield break;

            switch (container.ContainerType)
            {
                case ContainerType.Blend:
                    yield return PlayBlend(container, volumeScale, handle, inheritedBpm);
                    break;

                case ContainerType.Sequence:
                    yield return PlaySequence(container, volumeScale, handle, inheritedBpm);
                    break;

                case ContainerType.Random:
                    yield return PlayRandom(container, volumeScale, handle, inheritedBpm);
                    break;
            }
        }

        // ─────────────────────────────────────────────
        // Blend（同时播放）
        // ─────────────────────────────────────────────

        IEnumerator PlayBlend(MusicContainer container, float volumeScale, ContainerPlayHandle handle, float inheritedBpm)
        {
            IEnumerable<float> tempos = container.Segments.Select(id =>
            {
                MusicContainer c = this.m_containerConfig.QueryById(id);
                return c?.Bpm ?? 0f;
            }).Where(b => b > 0f).Distinct();

            if (tempos.Count() > 1)
            {
                OnBlendError?.Invoke(container);
            }
            
            // 同时启动所有子元素，等待全部结束
            List<ContainerPlayHandle> childHandles = new();
            bool allDone = false;
            int remaining = container.Segments.Count;

            foreach (uint segId in container.Segments)
            {
                if (handle.Cancelled) yield break;

                ContainerPlayHandle childHandle = PlayChild(segId, volumeScale, () =>
                {
                    remaining--;
                    if (remaining <= 0) allDone = true;
                }, inheritedBpm);
                if (childHandle != null)
                {
                    childHandles.Add(childHandle);
                    handle.ChildHandles.AddRange(childHandles);
                }
            }

            yield return new WaitUntil(() => allDone || handle.Cancelled);

            if (handle.Cancelled)
            {
                foreach (var ch in childHandles)
                    Stop(ch);
            }
        }

        // ─────────────────────────────────────────────
        // Sequence
        // ─────────────────────────────────────────────

        IEnumerator PlaySequence(MusicContainer container, float volumeScale, ContainerPlayHandle handle, float inheritedBpm)
        {
            bool isStep = container.ContainerPlayMode; 

            if (isStep)
            {
                // Step: 每次只播一个，游标全局推进
                int index = GetNextSequenceIndex(container);
                yield return PlayChildAndWait(container.Segments[index], volumeScale, handle, inheritedBpm);
                
            }
            else
            {
                // Continuous: 顺序播完所有子元素，算一轮
                for (int i = 0; i < container.Segments.Count; i++)
                {
                    if (handle.Cancelled) yield break;

                    // StrategyParam 作为两段之间的间隔时间（秒）
                    if (i > 0 && container.StrategyParam > 0)
                        yield return new WaitForSeconds(container.StrategyParam);

                    yield return PlayChildAndWait(container.Segments[i], volumeScale, handle, inheritedBpm);
                }
            }
        }

        // ─────────────────────────────────────────────
        // Random
        // ─────────────────────────────────────────────

        IEnumerator PlayRandom(MusicContainer container, float volumeScale, ContainerPlayHandle handle, float inheritedBpm)
        {
            bool isStep = container.ContainerPlayMode; // 同上，音乐系统默认 Continuous

            if (isStep)
            {
                // Step Random: 随机选一个播放，算一次 loopCount
                uint chosen = PickRandomChild(container);
                yield return PlayChildAndWait(chosen, volumeScale, handle, inheritedBpm);
            }
            else
            {
                // Continuous Random: 随机不放回地播完所有子元素，算一轮
                var remaining = new List<uint>(container.Segments);

                while (remaining.Count > 0)
                {
                    if (handle.Cancelled) yield break;

                    int idx = Random.Range(0, remaining.Count);
                    uint chosen = remaining[idx];
                    remaining.RemoveAt(idx);

                    if (container.StrategyParam > 0 && remaining.Count < container.Segments.Count - 1)
                        yield return new WaitForSeconds(container.StrategyParam);

                    yield return PlayChildAndWait(chosen, volumeScale, handle, inheritedBpm);
                }
            }
        }

        // ─────────────────────────────────────────────
        // 子元素分发（Segment 或嵌套 Container）
        // ─────────────────────────────────────────────

        /// <summary>
        /// 播放一个子元素（segment 或 container），等待其完成后返回。
        /// </summary>
        IEnumerator PlayChildAndWait(uint id, float volumeScale, ContainerPlayHandle parentHandle, float inheritedBpm)
        {
            bool done = false;
            ContainerPlayHandle child = PlayChild(id, volumeScale, () => done = true, inheritedBpm);
            if (child != null)
                parentHandle.ChildHandles.Add(child);

            yield return new WaitUntil(() => done || parentHandle.Cancelled);

            if (parentHandle.Cancelled && child != null)
                Stop(child);
        }

        /// <summary>
        /// 启动一个子元素的播放，不等待，返回句柄。
        /// </summary>
        ContainerPlayHandle PlayChild(uint id, float volumeScale, Action onDone, float inheritedBpm)
        {
            // ID < 1000000 是 MusicSegment，否则是嵌套 Container
            return id < 1000000u ? PlaySegment(id, volumeScale, onDone) : Play(id, onDone, inheritedBpm: inheritedBpm);
        }

        // ─────────────────────────────────────────────
        // Segment 播放
        // ─────────────────────────────────────────────

        ContainerPlayHandle PlaySegment(uint segmentId, float volumeScale, Action onFinished)
        {
            MusicSegment segment = this.m_segmentConfig.QueryById(segmentId);
            if (segment == null)
            {
                Debug.LogError($"[MusicContainerPlayer] 找不到 SegmentId: {segmentId}");
                onFinished?.Invoke();
                return null;
            }

            AudioClip clip = Resources.Load<AudioClip>($"Audios/{segment.Name}");
            if (!clip)
            {
                Debug.LogError($"[MusicContainerPlayer] 音频文件未找到: {segment.Name}");
                onFinished?.Invoke();
                return null;
            }

            AudioSource source = this.m_pool.AcquireAudioSource();
            source.clip   = clip;
            source.loop   = false;
            source.volume = volumeScale;
            source.Play();

            var handle = new ContainerPlayHandle();
            handle.ActiveSources.Add(source);
            handle.Coroutine = this.m_coroutineHost.StartCoroutine(
                WaitSegmentFinish(source, handle, onFinished));
            return handle;
        }

        IEnumerator WaitSegmentFinish(AudioSource source, ContainerPlayHandle handle, Action onFinished)
        {
            yield return new WaitWhile(() => source.isPlaying && !handle.Cancelled);
            
            
            source.Stop();
            ReturnSource(source);
            handle.ActiveSources.Remove(source);
            if (!handle.Cancelled)
                onFinished?.Invoke();
        }

        // ─────────────────────────────────────────────
        // 工具
        // ─────────────────────────────────────────────

        void ReturnSource(AudioSource source)
        {
            source.Stop();
            this.m_pool.ReturnToPool(source.gameObject);
        }

        int GetNextSequenceIndex(MusicContainer container)
        {
            int current = this.m_sequenceStepIndex.GetValueOrDefault(container.Id, 0);
            this.m_sequenceStepIndex[container.Id] = (current + 1) % container.Segments.Count;
            return current;
        }

        uint PickRandomChild(MusicContainer container)
        {
            if (!this.m_randomHistory.TryGetValue(container.Id, out HashSet<uint> history))
            {
                history = new HashSet<uint>();
                this.m_randomHistory[container.Id] = history;
            }

            List<uint> available = container.Segments.Where(id => !history.Contains(id)).ToList();
            if (available.Count == 0)
            {
                history.Clear();
                available = new List<uint>(container.Segments);
            }

            uint chosen = available[Random.Range(0, available.Count)];
            history.Add(chosen);
            return chosen;
        }
    }

    // ─────────────────────────────────────────────
    // 播放句柄
    // ─────────────────────────────────────────────

    /// <summary>
    /// 一次 Container 播放的句柄，用于外部停止或淡出时访问正在播放的 AudioSource。
    /// </summary>
    class ContainerPlayHandle
    {
        internal Coroutine Coroutine;
        internal bool Cancelled;
        internal float TargetVolume = 1f;
        internal List<AudioSource> ActiveSources  = new();
        internal List<ContainerPlayHandle> ChildHandles = new();

        /// <summary>
        /// 递归收集所有正在发声的 AudioSource（用于淡出）
        /// </summary>
        internal void CollectActiveSources(List<AudioSource> result)
        {
            result.AddRange(this.ActiveSources);
            foreach (ContainerPlayHandle child in this.ChildHandles)
                child.CollectActiveSources(result);
        }

        /// <summary>
        /// 获取第一个正在播放的 Leaf Segment 的 AudioSource。
        /// 递归遍历子句柄，优先取当前层级的 ActiveSources，找不到再深入子层级。
        /// </summary>
        internal AudioSource GetFirstLeafSource()
        {
            if (this.ActiveSources.Count > 0) return this.ActiveSources[0];
            foreach (ContainerPlayHandle child in this.ChildHandles)
            {
                AudioSource src = child.GetFirstLeafSource();
                if (src) return src;
            }
            return null;
        }
    }
}
