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

namespace OCES.Audio
{
    /// <summary>
    /// SyncPoint 协调状态，在 FadeOutBranch 和 FadeInBranch 之间共享。
    /// </summary>
    internal class SyncPointState
    {
        public SyncPoint Mode;
        public int BaseTimeSamples;        // 读取Source Segment 的 timeSamples
        public double BaseDspTime;         // 读取Source Segment 的 dspTime
        public int SampleRate;             // Source Segment 的采样率
        public bool Ready;
        public double SourceStartOffset;
        public double TargetAudioTime;
        public double StartPlayTime;
    }

    /// <summary>
    /// 与Transition无关的音量/生命周期管理逻辑
    /// </summary>
    public class ChannelFader
    {
        readonly LongAudioContainerPlayer m_player;
        readonly MonoBehaviour m_coroutineHost;
        
        internal ContainerPlayHandle CurrentHandle { get; private set; }
        public uint CurrentContainerId { get; private set; }
        public float CurrentVolume { get; private set; }

        internal ChannelFader(LongAudioContainerPlayer player, MonoBehaviour coroutineHost)
        {
            this.m_player = player;
            this.m_coroutineHost = coroutineHost;
        }
        
        void StartNew(uint containerId, float startVolume)
        {
            CurrentContainerId = containerId;
            CurrentVolume      = startVolume;
            CurrentHandle      = this.m_player.Play(containerId);
            Debug.Log($"[ChannelFader] StartNew: containerId={containerId}, CurrentHandle={CurrentHandle}");
        }

        public void StopCurrent()
        {
            Debug.Log($"[ChannelFader] StopCurrent called! CurrentHandle={CurrentHandle}, stack=\n{Environment.StackTrace}");
            StopHandle(CurrentHandle);
            CurrentHandle      = null;
            CurrentContainerId = 0;
        }

        void StopHandle(ContainerPlayHandle handle)
        {
            if (handle == null) return;
            this.m_player.Stop(handle);
        }
        
        /// <summary>
        /// 淡出分支：fire-and-forget，由调用方 StartCoroutine
        /// </summary>
        internal IEnumerator FadeOutBranch(
            ContainerPlayHandle outgoingHandle,
            float outgoingVolume,
            ITransitionConfig transition,
            SyncPointState syncState = null)
        {
            if (outgoingHandle == null) yield break;

            if (transition?.FadeOutOffset > 0f)
            {
                //Debug.Log($"Waiting for {transition.FadeOutOffset} to fade out.");
                yield return new WaitForSeconds(transition.FadeOutOffset);
            }

            if (transition?.FadeOutTime > 0f )
                yield return this.m_coroutineHost.StartCoroutine(
                    FadeOut(outgoingHandle, outgoingVolume, transition.FadeOutTime));
            else
                StopHandle(outgoingHandle);
        }

        /// <summary>
        /// 淡入分支：等待 FadeInOffset 后启动新音乐并淡入。
        /// 主协程 yield return 此分支，以便 DoTransition 在新音乐就绪后才结束。
        /// </summary>
        internal IEnumerator FadeInBranch(uint newContainerId, ITransitionConfig transition, SyncPointState syncState = null,
            Action onContainerStarted = null)
        {
            if (transition?.FadeInOffset > 0f)
            {
                //Debug.Log($"Waiting {transition.FadeInOffset} to fade in.");
                yield return new WaitForSeconds(transition.FadeInOffset);
            }

            if (newContainerId == 0)
            {
                CurrentHandle = null;
                CurrentContainerId = 0;
                if (syncState != null) syncState.Ready = true;
                yield break;
            }

            float startVolume = transition?.FadeInTime > 0f ? 0f : 1f;
            StartNew(newContainerId, startVolume);
            onContainerStarted?.Invoke();

            switch (syncState)
            {
                // SyncPoint: 获取新 Segment 的 AudioSource 并设置 timeSamples
                case { Mode: SyncPoint.SameAsCurrentSegment }:
                {
                    AudioSource newSource = CurrentHandle?.GetFirstLeafSource();
                    if (newSource && newSource.clip)
                    {
                        double targetAudioTime = syncState.TargetAudioTime;
                        if (targetAudioTime > 0)
                        {
                            int targetTimeSamples = (int)(targetAudioTime * newSource.clip.frequency);
                            if (targetTimeSamples >= 0 && targetTimeSamples < newSource.clip.samples)
                            {
                                newSource.timeSamples = targetTimeSamples;
                            }
                            else
                            {
                                Debug.LogError(
                                    $"[ChannelFader] SyncPoint: 目标 samples({targetTimeSamples}) 超出范围 [0, {newSource.clip.samples})，降级为 Start");
                            }
                        }
                    }
                    else
                    {
                        Debug.LogError($"[ChannelFader] SyncPoint.SameAsCurrentSegment: 未能获取新 Segment 的 AudioSource，降级为 Start");
                    }
                    syncState.Ready = true;
                    break;
                }
                case { Mode: SyncPoint.Start, StartPlayTime: > 0 }:
                {
                    AudioSource newSource = CurrentHandle?.GetFirstLeafSource();
                    if (!newSource || !newSource.clip)
                        yield break;
                    
                    //在赋值的时候减过fade in time了
                    int targetTimeSamples = (int)(syncState.StartPlayTime * newSource.clip.frequency); 
                    
                    if (targetTimeSamples >= 0 && targetTimeSamples < newSource.clip.samples)
                    {
                        newSource.timeSamples = targetTimeSamples;
                    }
                    break;
                }
            }
            
            
            if (transition?.FadeInTime > 0f)
            {
                yield return this.m_coroutineHost.StartCoroutine(
                    FadeIn(CurrentHandle, transition.FadeInTime));
            }
        }

        IEnumerator FadeOut(ContainerPlayHandle handle, float fromVolume, float duration)
        {
            //Debug.Log($"Fading out in {duration} seconds.");
            if (handle == null || handle.Cancelled) yield break;

            float elapsed = 0f;
            List<AudioSource> sources = new();
            handle.CollectActiveSources(sources);

            while (elapsed < duration)
            {
                if (handle.Cancelled) break;
                elapsed += Time.deltaTime;
                // 为每个 source 创建 DOFade（仅创建一次）
                sources.Clear();
                handle.CollectActiveSources(sources);

                foreach (AudioSource src in sources)
                {
                    if (!src) continue;

                    if (DOTween.IsTweening(src))
                        continue;

                    src.volume = fromVolume;
                    src.DOFade(0f, duration - elapsed).SetEase(Ease.InSine); //TODO 支持读表
                }
                yield return null;
            }

            // 确保最终状态
            sources.Clear();
            handle.CollectActiveSources(sources);
            foreach (AudioSource src in sources)
                if (src) src.volume = 0f;

            StopHandle(handle);
        }

        IEnumerator FadeIn(ContainerPlayHandle handle, float duration)
        {
            if (handle == null || handle.Cancelled) yield break;

            List<AudioSource> sources = new();
            float elapsed = 0f;

            while (elapsed < duration)
            {
                if (handle.Cancelled) yield break;

                elapsed += Time.deltaTime;

                // 每帧收集当前活跃的 sources，并为新加入的 source 创建 tween
                sources.Clear();
                handle.CollectActiveSources(sources);

                foreach (AudioSource src in sources)
                {
                    if (!src) continue;

                    // 如果这个 source 还没被 tween 过，则创建一个 DOFade
                    if (DOTween.IsTweening(src))
                        continue;
                    src.volume = 0f;
                    src.DOFade(1f, duration - elapsed).SetEase(Ease.OutSine); //TODO 支持读表
                }

                yield return null;
            }

            // 确保最终音量
            sources.Clear();
            handle.CollectActiveSources(sources);
            foreach (AudioSource src in sources)
                if (src) src.volume = 1f;

            CurrentVolume = 1f;
        }
        

    }
}
