using System.Collections;
using UnityEngine;

namespace OCES.Audio
{
    /// <summary>
    /// 音乐通道播放器。
    /// 负责：切换目标 Container、等待节拍对齐、执行淡入淡出 Transition。
    /// </summary>
    public class MusicChannelPlayer
    {
        readonly MusicContainerConfig m_containerConfig;
        readonly MusicTransitionConfig m_transitionConfig;
        readonly MonoBehaviour m_coroutineHost;
        readonly ChannelFader m_fader;
                
        Coroutine m_currentFadeInCoroutine;
        Coroutine m_currentFadeOutCoroutine;

        // 当前正在播放的句柄
        ContainerPlayHandle m_currentHandle;
        uint m_currentContainerId;

        // 当前播放的 Container（用于读取 bpm/timeSig 做节拍对齐）
        MusicContainer m_currentContainer;

        // 当前播放开始的时间（用于计算当前播到哪个拍子）
        double m_playStartTime;

        // 正在进行的 transition 协程（防止重叠）
        Coroutine m_transitionCoroutine;

        public MusicChannelPlayer(
            MusicContainerConfig containerConfig,
            MusicTransitionConfig transitionConfig,
            MusicContainerPlayer player,
            MonoBehaviour coroutineHost)
        {
            this.m_containerConfig   = containerConfig;
            this.m_transitionConfig  = transitionConfig;
            this.m_coroutineHost     = coroutineHost;
            this.m_fader = new ChannelFader(player, coroutineHost);
        }

        // ─────────────────────────────────────────────
        // 公开接口
        // ─────────────────────────────────────────────

        /// <summary>
        /// 切换到新的 Container。
        /// fromPathId / toPathId 用于查询 Transition 配置。
        /// </summary>
        internal void SwitchTo(uint newContainerId, uint fromPathId, uint toPathId)
        {
            if (newContainerId == this.m_currentContainerId && this.m_currentHandle != null)
                return; // 已经在播目标，无需切换

            MusicTransition transition = ResolveTransition(fromPathId, toPathId);

            if (this.m_transitionCoroutine != null)
                this.m_coroutineHost.StopCoroutine(this.m_transitionCoroutine);

            this.m_transitionCoroutine = this.m_coroutineHost.StartCoroutine(
                DoTransition(newContainerId, transition));
        }

        /// <summary>
        /// 立即停止当前播放（无淡出）
        /// </summary>
        public void Stop()
        {
            if (this.m_transitionCoroutine != null)
                this.m_coroutineHost.StopCoroutine(this.m_transitionCoroutine);

            this.m_fader.StopCurrent();
        }

        // ─────────────────────────────────────────────
        // Transition 流程
        // ─────────────────────────────────────────────

        IEnumerator DoTransition(uint newContainerId, MusicTransition transition)
        {
            if (this.m_currentFadeInCoroutine != null)
            {
                this.m_coroutineHost.StopCoroutine(this.m_currentFadeInCoroutine);
                this.m_currentFadeInCoroutine = null;
            }

            if (this.m_currentFadeOutCoroutine != null)
            {
                this.m_coroutineHost.StopCoroutine(this.m_currentFadeOutCoroutine);
                this.m_currentFadeOutCoroutine = null;
            }
            
            // ── 1. 等待节拍对齐（由 Transition 的 AlignMode 决定）──
            if (transition != null && this.m_currentContainer != null)
            {
                yield return this.m_coroutineHost.StartCoroutine(
                    WaitForAlignment(transition.AlignMode, this.m_currentContainer));
            }

            // ── 2 & 3. 淡出与淡入并行：两条分支从同一时刻起算各自的 Offset，互不等待 ──
            if (newContainerId == this.m_fader.CurrentContainerId && this.m_fader.CurrentHandle != null) yield break; 
            // 如果等待期间被切回来了，就不淡变了
            
            ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
            float outVol = this.m_fader.CurrentVolume;

            this.m_currentFadeOutCoroutine = this.m_coroutineHost.StartCoroutine(
                this.m_fader.FadeOutBranch(outgoing, outVol, transition));

            this.m_currentFadeInCoroutine = this.m_coroutineHost.StartCoroutine(
                this.m_fader.FadeInBranch(newContainerId, transition,
                    onContainerStarted: () =>
                    {
                        // Music 独有：记录新 container 和播放起始时间
                        this.m_currentContainer = this.m_containerConfig.QueryById(newContainerId);
                        this.m_playStartTime    = AudioSettings.dspTime;
                    }));
            yield return this.m_currentFadeInCoroutine;
            this.m_currentFadeInCoroutine = null;
        }

        // ─────────────────────────────────────────────
        // 节拍对齐等待
        // ─────────────────────────────────────────────

        IEnumerator WaitForAlignment(AlignMode mode, MusicContainer container)
        {
            if (mode == AlignMode.Immediate || container.Bpm <= 0f)
                yield break;

            double now = AudioSettings.dspTime;
            double elapsed = now - this.m_playStartTime;

            double secondsPerBeat = 60.0 / container.Bpm;

            if (mode == AlignMode.Beat)
            {
                double beatsElapsed  = elapsed / secondsPerBeat;
                double nextBeat      = System.Math.Ceiling(beatsElapsed);
                double waitSeconds   = (nextBeat - beatsElapsed) * secondsPerBeat;
                if (waitSeconds > 0.001)
                    yield return new WaitForSeconds((float)waitSeconds);
            }
            else if (mode == AlignMode.Bar)
            {
                int beatsPerBar = ParseBeatsPerBar(container.TimeSig);
                double secondsPerBar   = secondsPerBeat * beatsPerBar;
                double barsElapsed     = elapsed / secondsPerBar;
                double nextBar         = System.Math.Ceiling(barsElapsed);
                double waitSeconds     = (nextBar - barsElapsed) * secondsPerBar;
                if (waitSeconds > 0.001)
                    yield return new WaitForSeconds((float)waitSeconds);
            }
        }

        /// <summary>
        /// 解析拍号字符串（如 "4/4", "3/4"），返回每小节拍数。
        /// </summary>
        static int ParseBeatsPerBar(string timeSig)
        {
            if (string.IsNullOrEmpty(timeSig)) return 4;
            string[] parts = timeSig.Split('/');
            if (parts.Length >= 1 && int.TryParse(parts[0], out int beats))
                return beats;
            return 4;
        }
        // ─────────────────────────────────────────────
        // 工具
        // ─────────────────────────────────────────────

        /// <summary>
        /// 查询 Transition 配置，支持精确匹配和 999 通配符。
        /// ID 规则：FromPathId × 1000 + ToPathId，999 表示任意。
        /// </summary>
        MusicTransition ResolveTransition(uint fromPathId, uint toPathId)
        {
            // 优先精确匹配
            uint exactId = fromPathId * 1000 + toPathId;
            MusicTransition exact = this.m_transitionConfig.QueryById(exactId);
            if (exact != null) return exact;

            // From 为任意
            uint fromWildcard = 999u * 1000 + toPathId;
            MusicTransition fromWild = this.m_transitionConfig.QueryById(fromWildcard);
            if (fromWild != null) return fromWild;

            // To 为任意
            uint toWildcard = fromPathId * 1000 + 999u;
            MusicTransition toWild = this.m_transitionConfig.QueryById(toWildcard);
            if (toWild != null) return toWild;

            // 全通配
            const uint allWild = 999u * 1000 + 999u;
            return this.m_transitionConfig.QueryById(allWild);
        }
    }
}
