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

namespace OCES.Audio
{
    /// <summary>
    /// 音乐与环境音系统。由 AudioSystem 持有并初始化。
    /// 对外只暴露 OnStateChanged，由 AudioSystem.SetState 转发调用。
    /// </summary>
    class MusicSystem : MonoBehaviour
    {
        MusicStateRouter m_stateRouter;
        MusicChannelPlayer m_musicChannel;
        AmbienceChannelPlayer m_ambienceChannel;

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


        
        internal IReadOnlyDictionary<Type, Enum> ActiveStates
        {
            get { return this.m_stateRouter.ActiveStates; }
        }

        internal void Initialize(
            MusicSegmentConfig segments,
            MusicContainerConfig containers,
            MusicPathConfig musicPaths,
            AmbiencePathConfig ambiencePaths,
            MusicTransitionConfig musicTransitions,
            AmbienceTransitionConfig ambienceTransitions,
            AudioSourcePool musicPool,
            AudioSourcePool ambiencePool)
        {
            LongAudioContainerPlayer longAudioContainerPlayer = new(containers, segments, musicPool, this);
            LongAudioContainerPlayer ambientContainerPlayer = new(containers, segments, ambiencePool, this);

            this.m_stateRouter      = new MusicStateRouter(musicPaths, ambiencePaths);
            this.m_musicChannel     = new MusicChannelPlayer(
                containers, segments, musicTransitions, longAudioContainerPlayer, this,
                id => OnBeat?.Invoke(id),
                id => OnBar?.Invoke(id),
                id => OnGrid?.Invoke(id));
            this.m_ambienceChannel  = new AmbienceChannelPlayer(ambienceTransitions, ambientContainerPlayer, this);
            
            
        }

        /// <summary>
        /// 由 AudioSystem.SetState 调用，更新状态并驱动两个通道切换。
        /// </summary>
        internal void OnStateChanged<TEnum>(TEnum state) where TEnum : Enum
        {
            this.m_stateRouter.SetState(
                state,
                out uint musicContainerId,
                out uint ambienceContainerId);

            this.m_musicChannel.SwitchTo(musicContainerId);
            this.m_ambienceChannel.SwitchTo(ambienceContainerId);
        }
    }
}
