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

namespace OCES.Audio
{
    public class AudioContainerSelector
    {
        // TODO: 根据 audioObject.ContainerScope 控制随机历史的共享范围：
        //   - Global（当前实现）：同一 AudioObject 的所有并发实例共享同一份 playHistory 和 limitRepetition 队列，
        //     不放回随机在全局层面生效，并发实例之间互相感知已播放记录。
        //   - PerInstance：每个并发播放实例持有独立的 playHistory 和 limitRepetition 队列，
        //     不放回随机仅在该实例内生效，实例之间完全隔离。
        //   实现思路：PerInstance 模式下将 HashSet/Queue 作为局部变量传入协程，不再写入这两个 Dictionary。
        readonly Dictionary<uint, HashSet<int>> m_randomPlayedHistories = new();
        readonly Dictionary<uint, Queue<int>> m_randomRecentQueues = new();
        readonly Dictionary<uint, int> m_sequenceNextIndex = new();
        
        
         /// <summary>
        /// Shuffle 随机模式下选取 index（支持 LimitRepetition 队列）
        /// </summary>
        public int PickShuffleIndex(AudioObject audioObject)
        {
            int count = audioObject.Name.Count;

            // LimitRepetition 队列
            int limitRepetition = Mathf.Clamp(audioObject.LimitRepetition, 0, count - 1);
            if (!this.m_randomRecentQueues.TryGetValue(audioObject.Id, out Queue<int> recent))
            {
                recent = new Queue<int>();
                this.m_randomRecentQueues[audioObject.Id] = recent;
            }

            if (!audioObject.RandomType)
            {
                List<int> candidates = Enumerable.Range(0, count)
                    .Where(i => !recent.Contains(i))
                    .ToList();

                if (candidates.Count == 0)
                    candidates = Enumerable.Range(0, count).ToList();

                int chosen = candidates[Random.Range(0, candidates.Count)];

                if (limitRepetition > 0)
                {
                    recent.Enqueue(chosen);
                    if (recent.Count > limitRepetition)
                        recent.Dequeue();
                }

                return chosen;
            }

            // 不放回随机
            if (!this.m_randomPlayedHistories.TryGetValue(audioObject.Id, out HashSet<int> history))
            {
                history = new HashSet<int>();
                this.m_randomPlayedHistories[audioObject.Id] = history;
            }

            List<int> available = Enumerable.Range(0, count)
                .Where(i => !history.Contains(i) && !recent.Contains(i))
                .ToList();

            if (available.Count == 0)
            {
                history.Clear();
                available = Enumerable.Range(0, count)
                    .Where(i => !recent.Contains(i))
                    .ToList();

                if (available.Count == 0)
                    available = Enumerable.Range(0, count).ToList();
            }

            int chosenIndex = available[Random.Range(0, available.Count)];
            history.Add(chosenIndex);

            if (limitRepetition > 0)
            {
                recent.Enqueue(chosenIndex);
                if (recent.Count > limitRepetition)
                    recent.Dequeue();
            }

            return chosenIndex;
        }

        /// <summary>
        /// 连续容器的 Random 模式下，带 LimitRepetition 逻辑地选取 index
        /// </summary>
        public int PickNextRandomIndex(AudioObject audioObject, List<int> remainingPool, Queue<int> recentPlayed, int limitRepetition)
        {
            if (!this.m_randomPlayedHistories.TryGetValue(audioObject.Id, out HashSet<int> history))
            {
                history = new HashSet<int>();
                this.m_randomPlayedHistories[audioObject.Id] = history;
            }
            
            List<int> candidates = remainingPool
                .Where(i => !recentPlayed.Contains(i))
                .ToList();
            
            if (candidates.Count == 0)
                candidates = new List<int>(remainingPool);

            int index = candidates[Random.Range(0, candidates.Count)];

            if (audioObject.RandomType)
                remainingPool.Remove(index);

            if (limitRepetition > 0)
                recentPlayed.Enqueue(index);

            if (recentPlayed.Count > limitRepetition)
                recentPlayed.Dequeue();

            history.Add(index);
            return index;
        }

        /// <summary>
        /// 获取 Sequence 模式下的当前 index 并推进游标
        /// </summary>
        public int GetNextSequenceIndex(AudioObject audioObject)
        {
            int current = this.m_sequenceNextIndex.GetValueOrDefault(audioObject.Id, 0);
            this.m_sequenceNextIndex[audioObject.Id] = (current + 1) % audioObject.Name.Count;
            return current;
        }

        public void ResetHistory(uint id)
        {
            if (this.m_randomPlayedHistories.TryGetValue(id, out HashSet<int> history))
            {
                history.Clear();
            }
        }

        public int GetHistoryCount(uint id)
        {
            return this.m_randomPlayedHistories.TryGetValue(id, out HashSet<int> history) ? history.Count : 0;
        }
    }
}
