using AForge.Video.DirectShow;
using OpenCvSharp;
using Serilog;
using System.Runtime.ExceptionServices;
using System.Security;

namespace SHH.CameraSdk;

/// <summary>
/// [USB驱动] 工业级视频源实现 (参考 DahuaVideoSource 逻辑重构版)
/// <para>当前模块: AiVideo | 核心原则: 逻辑对标、高并发防御、零拷贝</para>
/// </summary>
public class UsbVideoSource : BaseVideoSource
{
    protected override ILogger _sdkLog => Log.ForContext("SourceContext", "UsbSdk");

    #region --- 1. 静态资源 (Static Resources) ---

    // USB 驱动通常为本地设备，无需像大华那样维护全局 ConcurrentDictionary 句柄映射

    #endregion

    #region --- 2. 实例成员 (Instance Members) ---

    private VideoCapture? _capture;
    private CancellationTokenSource? _cts;
    private int _deviceIndex = -1;

    private FramePool? _framePool;
    private volatile bool _isPoolReady = false;
    private readonly object _initLock = new();

    #endregion

    public UsbVideoSource(VideoSourceConfig config) : base(config) { }

    #region --- 3. 生命周期实现 (Lifecycle Overrides) ---

    protected override async Task OnStartAsync(CancellationToken token)
    {
        _cts = CancellationTokenSource.CreateLinkedTokenSource(token);

        await Task.Run(() =>
        {
            lock (_initLock)
            {
                // 1. 获取配置的标识符 (存放在 RtspPath 中的那串 @device:sw...)
                string targetMoniker = _config.RtspPath;
                _deviceIndex = -1;

                _sdkLog.Information($"[SDK] 正在扫描 USB 设备以匹配 Moniker: {targetMoniker}");

                // 2. 使用 AForge 列出所有视频采集设备
                var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

                if (videoDevices.Count == 0)
                {
                    throw new Exception("系统中未检测到任何 USB 摄像头设备。");
                }

                // 3. 遍历并匹配
                for (int i = 0; i < videoDevices.Count; i++)
                {
                    _sdkLog.Debug($"[Scan] Index: {i}, Name: {videoDevices[i].Name}, Moniker: {videoDevices[i].MonikerString}");

                    // 进行比对
                    if (videoDevices[i].MonikerString.Equals(targetMoniker, StringComparison.OrdinalIgnoreCase))
                    {
                        _deviceIndex = i; // 找到了！这就是 OpenCV 需要的整数索引
                        _sdkLog.Information($"[Match] 成功匹配到设备: {videoDevices[i].Name}, 对应 OpenCV Index: {i}");
                        break;
                    }
                }

                // 4. 容错处理：如果没找到，尝试 fallback 到 IpAddress 里的索引
                if (_deviceIndex == -1)
                {
                    if (int.TryParse(_config.IpAddress, out int fallbackIndex))
                    {
                        _deviceIndex = fallbackIndex;
                        _sdkLog.Warning($"[Match] 未找到匹配的 Moniker，退回到使用 IpAddress 指定的索引: {fallbackIndex}");
                    }
                    else
                    {
                        throw new Exception($"无法找到指定的 USB 设备: {targetMoniker}");
                    }
                }

                // 5. 使用 DSHOW 模式打开 OpenCV
                _capture = new VideoCapture(_deviceIndex, VideoCaptureAPIs.DSHOW);
                _sdkLog.Information($"[SDK] USB 开启成功 => Index:{_deviceIndex}");
                AddAuditLog($"[SDK] USB 开启成功");

                // ... 后续设置和启动循环逻辑 ...
                _ = Task.Run(() => InternalCaptureLoop(_cts.Token), _cts.Token);
            }
        }, token);
    }

    protected override async Task OnStopAsync()
    {
        _cts?.Cancel();

        await Task.Run(() =>
        {
            lock (_initLock)
            {
                if (_capture != null)
                {
                    _capture.Release();
                    _capture.Dispose();
                    _capture = null;
                }

                _framePool?.Dispose();
                _isPoolReady = false;

                _sdkLog.Information($"[SDK] USB 已停止 ID:{Id}");
            }
        });
    }

    #endregion

    #region --- 4. 核心逻辑：采集与分发 (Core Logic) ---

    /// <summary>
    /// 内部采集循环：逻辑完全对标大华的 ProcessRealData + SafeOnDecodingCallBack
    /// </summary>
    private void InternalCaptureLoop(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            try
            {
                if (_capture == null || !_capture.IsOpened()) break;

                // 1. 探测当前分辨率
                int currentWidth = (int)_capture.FrameWidth;
                int currentHeight = (int)_capture.FrameHeight;

                if (currentWidth <= 0 || currentHeight <= 0)
                {
                    Thread.Sleep(10);
                    continue;
                }

                // 2. 模拟大华的“心跳”统计
                MarkFrameReceived(0);

                // 3. 逻辑对标：SafeOnDecodingCallBack 中的“防死锁重建”
                if (!_isPoolReady || Width != currentWidth || Height != currentHeight)
                {
                    bool lockTaken = false;
                    try
                    {
                        Monitor.TryEnter(_initLock, 50, ref lockTaken);
                        if (lockTaken)
                        {
                            if (!_isPoolReady || Width != currentWidth || Height != currentHeight)
                            {
                                _sdkLog.Information($"[Res] USB分辨率变更: {Width}x{Height} -> {currentWidth}x{currentHeight}");
                                _framePool?.Dispose();

                                Width = currentWidth;
                                Height = currentHeight;

                                // 重建帧池 (对标大华参数: 3, 5)
                                _framePool = new FramePool(currentWidth, currentHeight, MatType.CV_8UC3, 3, 5);
                                _isPoolReady = true;
                            }
                        }
                        else continue;
                    }
                    finally { if (lockTaken) Monitor.Exit(_initLock); }
                }

                // 4. [流控决策] 复用基类控制器
                // 注意：这里 decision 的类型取决于你基类的返回定义，通常为 StreamDecision
                var decision = Controller.MakeDecision(Environment.TickCount64, (int)RealFps);

                if (!decision.IsCaptured)
                {
                    _capture.Grab(); // 仅抓取不解码，保持底层缓冲区最新
                    continue;
                }

                // 5. 执行数据处理
                ExecuteFrameProcessing(decision);
            }
            catch (Exception ex)
            {
                _sdkLog.Error(ex, $"[SDK] USB 采集循环异常 ID:{Id}");
                Thread.Sleep(500); // 异常规避
            }
        }
    }

    /// <summary>
    /// 帧处理逻辑：对标大华的 SafeOnDecodingCallBack 内部逻辑
    /// </summary>
    [HandleProcessCorruptedStateExceptions]
    [SecurityCritical]
    private void ExecuteFrameProcessing(dynamic decision) // 使用 dynamic 规避特定的类定义编译问题
    {
        SmartFrame? smartFrame = null;
        try
        {
            smartFrame = _framePool?.Get();
            if (smartFrame == null) return;

            // [核心操作：零拷贝思想] 
            // 直接将 USB 原始 BGR 数据读入 SmartFrame 分配好的内存中
            if (_capture != null && _capture.Read(smartFrame.InternalMat))
            {
                // 🛡️ [空结果防御]
                if (smartFrame.InternalMat.Empty())
                {
                    _sdkLog.Warning($"[SDK] USB 解码后 Mat 为空. ID:{Id}");
                    return;
                }

                Cv2.CvtColor(smartFrame.InternalMat, smartFrame.InternalMat, ColorConversionCodes.BGR2RGB);

                // 填充订阅者
                foreach (var appId in decision.TargetAppIds)
                    smartFrame.SubscriberIds.Enqueue(appId);

                // 发送到全局路由 (Router 内部必须 AddRef)
                GlobalPipelineRouter.Enqueue(Id, smartFrame, decision);
            }
        }
        catch (Exception ex)
        {
            _sdkLog.Error(ex, $"[SDK] USB 帧转换流程异常. ID:{Config.Id}");
            AddAuditLog($"[SDK] USB 处理异常: {ex.Message}");
        }
        finally
        {
            // ♻️ [引用闭环] 对标大华的 finally Dispose
            smartFrame?.Dispose();
        }
    }

    #endregion

    #region --- 5. 其它实现 ---

    protected override void OnApplyOptions(DynamicStreamOptions options) { }
    protected override Task<DeviceMetadata> OnFetchMetadataAsync() => Task.FromResult(new DeviceMetadata());

    #endregion
}