using Ayay.SerilogLogs;
using Core.WcfProtocol;
using Serilog;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;

namespace SHH.MjpegPlayer
{
    /// <summary>
    /// Mjpeg 会话工作单元
    /// </summary>
    public class MjpegSession : IDisposable
    {
        #region Defines

        private static readonly ILogger _sysLog = Log.ForContext("SourceContext", LogModules.Core);

        private CancellationTokenSource? _sessionCts;

        private SumByTime _sumBySecond = new SumByTime();

        /// <summary>计数器</summary>
        public SumByTime Counter => _sumBySecond;

        // 引入 Disposed 标志位
        private volatile bool _isDisposed = false;

        #endregion

        #region Info

        /// <summary>
        /// 基础信息
        /// </summary>
        public SessionInfo Info { get; private set; }

        #endregion

        #region Cmd

        /// <summary>
        /// 命令
        /// </summary>
        public string? Cmd { get; set; }

        #endregion

        #region Constructor

        /// <summary>
        /// 构造函数
        /// </summary>
        public MjpegSession()
        {
            Info = new SessionInfo
            {
                Counter = _sumBySecond
            };
        }

        #endregion

        #region DoHttpHeader

        private bool DoHttpHeader(NetworkStream stream)
        {
            try
            {
                byte[] buffer = new byte[4096];
                int totalBytesRead = 0;
                string httpRequest = string.Empty;

                while (totalBytesRead < buffer.Length)
                {
                    int bytesRead = stream.Read(buffer, totalBytesRead, buffer.Length - totalBytesRead);
                    if (bytesRead == 0) return false;

                    totalBytesRead += bytesRead;
                    httpRequest = Encoding.ASCII.GetString(buffer, 0, totalBytesRead);
                    if (httpRequest.Contains("\r\n\r\n")) break;
                }

                if (!httpRequest.Contains("\r\n\r\n")) return false;

                if (!string.IsNullOrEmpty(httpRequest))
                {
                    int queryStartIndex = httpRequest.IndexOf('?');
                    if (queryStartIndex > -1)
                    {
                        int spaceIndex = httpRequest.IndexOf(' ', queryStartIndex);
                        if (spaceIndex == -1) spaceIndex = httpRequest.Length;
                        string queryString = httpRequest.Substring(queryStartIndex + 1, spaceIndex - queryStartIndex - 1);
                        var queryParams = System.Web.HttpUtility.ParseQueryString(queryString);
                        if (queryParams != null)
                        {
                            Info.DeviceId = queryParams["id"];
                            Info.TypeCode = queryParams["typeCode"];
                            Cmd = queryParams["cmd"];
                        }
                    }
                }

                if (string.IsNullOrEmpty(Cmd))
                {
                    if (string.IsNullOrEmpty(Info.DeviceId) || string.IsNullOrEmpty(Info.TypeCode))
                    {
                        SendErrorResponse(stream, "错误：缺少必要参数（id 或 typeCode）");
                        return false;
                    }
                }
                else
                {
                    if (MjpegHttpCmd.DoHttpCmd(stream, Info, Cmd)) return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                SendErrorResponse(stream, $"解析异常: {ex.Message}");
                return false;
            }
        }

        private void SendErrorResponse(NetworkStream stream, string msg)
        {
            try
            {
                byte[] response = Encoding.UTF8.GetBytes(
                    $"HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n{msg}");
                stream.Write(response, 0, response.Length);
                stream.Flush();
            }
            catch { }
        }

        #endregion

        #region Create

        /// <summary>
        /// 创建会话
        /// </summary>
        public void Create(TcpClient client)
        {
            try
            {
                if (Info == null) return;
                Info.AcceptTime = DateTime.Now;
                // 初始化最近接收时间，避免刚连接就被判定为超时
                LastRecImgTime = DateTime.Now;

                // 绑定全局取消令牌，确保系统停止时能立即强制中断所有会话
                _sessionCts = new CancellationTokenSource();

                Task.Run(() => { DoWorkTask(client, _sessionCts.Token); }, _sessionCts.Token);
            }
            catch (Exception ex)
            {
                _sysLog.Error($"MjpegSession Create Exception, 异常信息:{ex.Message}, {ex.StackTrace}");
            }
        }

        #endregion

        #region DoWorkTask

        private void DoWorkTask(TcpClient client, CancellationToken token)
        {
            try
            {
                using (var stream = client.GetStream())
                {
                    // 设置写入超时 3秒
                    stream.WriteTimeout = 3000;

                    #region 等待连接, 处理地址栏参数

                    int iLoc = 0;
                    while (!client.Connected && !token.IsCancellationRequested)
                    {
                        Thread.Sleep(50);
                        if (++iLoc > 60) return;
                    }
                    if (token.IsCancellationRequested) return;

                    try
                    {
                        if (client.Client?.RemoteEndPoint is IPEndPoint endpoint)
                        {
                            Info.ClientIp = endpoint.Address.ToString();
                            Info.ClientPort = endpoint.Port;
                        }
                    }
                    catch { }

                    if (!DoHttpHeader(stream)) return;

                    #endregion

                    MjpegStatics.Sessions.AddSession(this);

                    byte[] header = Encoding.ASCII.GetBytes(
                        "HTTP/1.1 200 OK\r\n" +
                        "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n");
                    stream.Write(header, 0, header.Length);

                    var frameInterval = MjpegStatics.Cfg.FrameInterval;
                    if (frameInterval < 1 || frameInterval > 500) frameInterval = 125;

                    Stopwatch stopwatch = Stopwatch.StartNew();
                    UploadImageRequest? lastProcItem = null;

                    byte[] boundaryBytes = Encoding.ASCII.GetBytes("\r\n--frame\r\nContent-Type: image/jpeg\r\nContent-Length: ");
                    byte[] doubleNewLine = Encoding.ASCII.GetBytes("\r\n\r\n");

                    while (client.Connected && !_isDisposed && !token.IsCancellationRequested)
                    {
                        try
                        {
                            // [新增] 僵尸连接熔断机制：如果源头超过 60 秒没有新图片，主动断开连接
                            if ((DateTime.Now - LastRecImgTime).TotalSeconds > 60)
                            {
                                _sysLog.Warning($"会话超时断开 (源头无数据 > 60s): {Info.Key} - Client: {Info.ClientIp}");
                                break;
                            }

                            stopwatch.Restart();

                            if (_lastRecObj == null || _lastRecObj.ImageBytes == null)
                            {
                                Info.Message = "等待图片数据抵达";
                                Thread.Sleep(40);
                                continue;
                            }

                            Info.Message = "视频流播放中";
                            if (lastProcItem != null && lastProcItem != _lastRecObj)
                            {
                                _sumBySecond.Refresh("有效帧数");
                            }
                            lastProcItem = _lastRecObj;

                            // 如果图片太旧（超过3秒），认为是滞后数据，暂时不发
                            if ((DateTime.Now - _lastRecObj.Time).TotalSeconds > 3)
                            {
                                Thread.Sleep(40);
                                continue;
                            }

                            byte[] imageData = _lastRecObj.ImageBytes;

                            stream.Write(boundaryBytes, 0, boundaryBytes.Length);
                            byte[] lengthBytes = Encoding.ASCII.GetBytes(imageData.Length.ToString());
                            stream.Write(lengthBytes, 0, lengthBytes.Length);
                            stream.Write(doubleNewLine, 0, doubleNewLine.Length);
                            stream.Write(imageData, 0, imageData.Length);

                            _sumBySecond.Refresh("播放帧数");

                            stopwatch.Stop();
                            var needSleep = frameInterval - (int)stopwatch.ElapsedMilliseconds;
                            if (needSleep > 0)
                                Task.Delay(needSleep, token).Wait(token);
                        }
                        catch (Exception ex)
                        {
                            _sysLog.Warning($"播放连接断开, : {ex.Message}");
                            break;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                _sysLog.Error($"异常信息:{ex.Message}, {ex.StackTrace}");
            }
            finally
            {
                Dispose();
                if (client != null)
                {
                    try { client.Close(); client.Dispose(); } catch { }
                }
            }
        }

        #endregion

        #region DoImageProc

        private UInt64 _lastPlayImageOrder = 0;
        private UploadImageRequest? _lastRecObj = null;

        /// <summary>
        /// 处置图片
        /// </summary>
        public void DoImageProc(UploadImageRequest req)
        {
            try
            {
                LastRecImgTime = DateTime.Now;
                _sumBySecond.Refresh("接收帧数");
                if (req == null || req.ImageBytes == null || req.ImageBytes.Length < 100) return;

                // 防止死锁：序号重置检测
                if (req.Order < _lastPlayImageOrder)
                {
                    if (_lastPlayImageOrder > 100 && req.Order < 100)
                    {
                        _lastPlayImageOrder = req.Order;
                    }
                    else
                    {
                        return;
                    }
                }

                _lastPlayImageOrder = req.Order;
                _lastRecObj = req;
            }
            catch (Exception ex)
            {
                _sysLog.Error($"异常信息:{ex.Message}, {ex.StackTrace}");
            }
        }

        /// <summary>
        /// 最近收到图片时间
        /// </summary>
        public DateTime LastRecImgTime { get; set; } = DateTime.MinValue;

        #endregion

        #region Dispose

        public void Dispose()
        {
            if (_isDisposed) return;
            _isDisposed = true;

            // 释放令牌资源
            try
            {
                _sessionCts?.Cancel();
                _sessionCts?.Dispose();
            }
            catch { }

            MjpegStatics.Sessions.RemoveSession(this);
        }

        #endregion
    }
}