using Core.WcfProtocol;
using System.Collections.Concurrent;

namespace SHH.MjpegPlayer;

/// <summary>
/// 服务器会话集合 (线程安全重构版)
/// </summary>
public class MjpegSessions
{
    // 核心改变：使用字典建立索引，Key = DeviceId#TypeCode
    // 这样可以将查找特定摄像头的复杂度从 O(N) 降低到 O(1)
    private readonly ConcurrentDictionary<string, List<MjpegSession>> _sessionMap
        = new ConcurrentDictionary<string, List<MjpegSession>>();

    /// <summary>
    /// 构造函数
    /// </summary>
    public MjpegSessions()
    {
        PrismMsg<UploadImageRequest>.Subscribe(ProcUploadImageRequest);
    }

    /// <summary>
    /// 优化后的图片分发逻辑 (解决 O(N) 和 线程安全问题)
    /// </summary>
    /// <param name="req"></param>
    public void ProcUploadImageRequest(UploadImageRequest req)
    {
        try
        {
            string key = $"{req.Id}#{req.Type}";

            // 1. 更新通道信息 (ImageChannels 现已是线程安全的)
            var chn = MjpegStatics.ImageChannels.Do(req, key);

            // 2. O(1) 快速查找关注该流的会话列表
            if (_sessionMap.TryGetValue(key, out var targetSessions))
            {
                // 必须加锁，防止遍历时 List 被其他线程(如 AddSession/RemoveSession) 修改
                lock (targetSessions)
                {
                    // 倒序遍历，方便在需要时移除失效会话
                    for (var i = targetSessions.Count - 1; i >= 0; i--)
                    {
                        var session = targetSessions[i];
                        session.DoImageProc(req);
                    }
                }

                if (chn != null) chn.IsPlaying = targetSessions.Count > 0;
            }
            else
            {
                if (chn != null) chn.IsPlaying = false;
            }
        }
        catch (Exception ex)
        {
            //Logs.LogWarning<MjpegSessions>(ex.Message, ex.StackTrace);
        }
    }

    /// <summary>
    /// 添加会话
    /// </summary>
    /// <param name="session"></param>
    public void AddSession(MjpegSession session)
    {
        if (session?.Info?.Key == null) return;

        // 使用 GetOrAdd 确保线程安全地获取或创建 List
        var list = _sessionMap.GetOrAdd(session.Info.Key, _ => new List<MjpegSession>());

        lock (list)
        {
            list.Add(session);
        }
    }

    /// <summary>
    /// 移除会话
    /// </summary>
    /// <param name="session"></param>
    public void RemoveSession(MjpegSession session)
    {
        if (session?.Info?.Key == null) return;

        if (_sessionMap.TryGetValue(session.Info.Key, out var list))
        {
            lock (list)
            {
                list.Remove(session);
            }
        }
    }

    /// <summary>
    /// 获取当前所有会话信息的快照 (用于 HTTP API 统计与展示)
    /// [新增] 此方法替代旧版直接访问 Sessions 列表，防止 HTTP 线程与 MJPEG 线程发生冲突
    /// </summary>
    public List<SessionInfo> GetAllSessionInfos()
    {
        var result = new List<SessionInfo>();
        // 遍历字典，线程安全地收集所有 Info
        foreach (var kvp in _sessionMap)
        {
            // 对内部 List 加锁，确保复制过程不被打断
            lock (kvp.Value)
            {
                result.AddRange(kvp.Value.Select(s => s.Info));
            }
        }
        return result;
    }
}