using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace OCES.Audio
{
    /// <summary>
    /// 环境音通道播放器。
    /// 与 MusicChannelPlayer 逻辑相同，但使用 AmbienceTransition 表，不涉及节拍对齐。
    /// </summary>
    class AmbienceChannelPlayer
    {
        readonly AmbienceTransitionConfig m_transitionConfig;
        readonly MonoBehaviour m_coroutineHost;
        readonly ChannelFader m_fader;
        readonly List<AmbienceTransition> m_transitionCandidates = new();
        
        ContainerPlayHandle m_currentHandle;
        Coroutine m_transitionCoroutine;
        Coroutine m_currentFadeOutCoroutine;
        Coroutine m_currentFadeInCoroutine;
        
        uint m_currentContainerId;

        internal AmbienceChannelPlayer(
            AmbienceTransitionConfig transitionConfig,
            LongAudioContainerPlayer player,
            MonoBehaviour coroutineHost)
        {
            this.m_transitionConfig = transitionConfig;
            this.m_coroutineHost    = coroutineHost;
            this.m_fader = new ChannelFader(player, coroutineHost);
        }

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

        internal void SwitchTo(uint newContainerId)
        {
            if (newContainerId == this.m_currentContainerId && this.m_currentHandle != null)
                return;

            AmbienceTransition transition = ResolveTransition((int)this.m_currentContainerId, (int)newContainerId);

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

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

        public void Stop()
        {
            if (this.m_transitionCoroutine != null)
                this.m_coroutineHost.StopCoroutine(this.m_transitionCoroutine);

            this.m_fader.StopCurrent();
        }

        // ─────────────────────────────────────────────
        // Transition 流程（无节拍对齐）
        // ─────────────────────────────────────────────

        IEnumerator DoTransition(uint newContainerId, AmbienceTransition transition)
        {
            if (newContainerId == this.m_fader.CurrentContainerId && this.m_fader.CurrentHandle != null) yield break; 
            // 如果等待期间被切回来了，就不淡变了
            
            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;
            }

            ContainerPlayHandle outgoing = this.m_fader.CurrentHandle;
            float outgoingVolume = this.m_fader.CurrentVolume;

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

            this.m_currentFadeInCoroutine = this.m_coroutineHost.StartCoroutine(
                this.m_fader.FadeInBranch(newContainerId, transition));
            yield return this.m_currentFadeInCoroutine;
            this.m_currentFadeInCoroutine = null;
        }

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

        AmbienceTransition ResolveTransition(int sourceContainerId, int destinationContainerId)
        {
            this.m_transitionCandidates.Clear();
            foreach (AmbienceTransition transition in this.m_transitionConfig.AmbienceTransitionList())
            {
                bool sourceMatch = transition.SourceContainerID == sourceContainerId || transition.SourceContainerID < 0;
                bool destMatch = transition.DestinationContainerID == destinationContainerId || transition.DestinationContainerID < 0;
                if (sourceMatch && destMatch)
                {
                    this.m_transitionCandidates.Add(transition);
                }
            }

            if (this.m_transitionCandidates.Count == 0)
                return this.m_transitionConfig.QueryById(1);

            AmbienceTransition best = this.m_transitionCandidates[0];
            for (int i = 1; i < this.m_transitionCandidates.Count; i++)
            {
                if (this.m_transitionCandidates[i].Id > best.Id)
                    best = this.m_transitionCandidates[i];
            }
            return best;
        }
    }
}
