using Ayay.SerilogLogs;
using Serilog;

namespace SHH.CameraSdk;

/// <summary>
/// [驱动支持层] 海康 SDK 全局资源管理器 (V3.3.1 修复版)
/// <para>核心修复：</para>
/// <para>1. [Bug S] 引用计数保护：增加下溢检测，防止异常销毁流程导致的计数器错乱。</para>
/// <para>2. [Bug C] 禁用内部重连：确保 SDK 不会背着上层偷偷重连，彻底消除僵尸连接。</para>
/// </summary>
public static class HikSdkManager
{
    #region --- 全局状态与锁 (Global States & Locks) ---

    /// <summary>
    /// 全局引用计数器。
    /// 只有当计数从 0 变 1 时才进行物理初始化，从 1 变 0 时才物理卸载。
    /// </summary>
    private static int _referenceCount = 0;

    /// <summary>
    /// 静态同步锁。
    /// 用于保护 _referenceCount 的原子操作，防止多线程并发 Start/Stop 时导致的初始化冲突。
    /// </summary>
    private static readonly object _lock = new();

    /// <summary>
    /// 播放库预热状态标记。
    /// 用于避免重复执行硬件探测（首次预热后后续直接返回）。
    /// </summary>
    private static bool _isWarmedUp = false;

    #endregion

    #region --- SDK 初始化与卸载 (SDK Initialization & Uninstallation) ---

    /// <summary>
    /// 全局初始化海康 SDK 环境。
    /// <para>此方法是幂等的，内部会自动增加引用计数，支持多线程并发调用。</para>
    /// </summary>
    /// <returns>初始化成功返回 true；若 SDK 核心组件（HCNetSDK.dll）加载失败则返回 false。</returns>
    public static bool Initialize()
    {
        lock (_lock)
        {
            // 引用计数为 0 时执行物理初始化（仅首次调用时触发）
            if (_referenceCount == 0)
            {
                // [物理初始化] 调用海康核心 DLL 接口，初始化 SDK 基础环境
                if (!HikNativeMethods.NET_DVR_Init()) return false;

                // --- 工业级可靠性设置（注释保留，按需启用）---
                //// 1. 登录超时设置 (3000ms)：
                //// 在高并发场景下，快速失败比无限重试更有利于系统调度。
                //HikNativeMethods.NET_DVR_SetConnectTime(3000, 1);

                //// 2. [Fix Bug C: 双重重连冲突] 
                //// 设计思路：禁用海康 SDK 内部的自动重连机制（bEnableRecon = false）。
                //// 理由：SDK 内部重连是非透明的，无法与我们的上层协调器 (Coordinator) 状态机完美对齐。
                //// 统一由外层协调器负责“检测断线 -> 销毁旧句柄 -> 重新登录”，确保状态的一致性。
                //HikNativeMethods.NET_DVR_SetReconnect(10000, false);
            }

            // 引用计数递增，记录当前活跃的 SDK 使用者数量
            _referenceCount++;
            return true;
        }
    }

    /// <summary>
    /// 全局卸载海康 SDK 环境。
    /// <para>当所有相机实例都停止并释放后（引用计数归 0），会真正释放非托管资源。</para>
    /// </summary>
    public static void Uninitialize()
    {
        lock (_lock)
        {
            // [Fix Bug S: 引用计数溢出保护]
            // 确保不会因为意外的多次调用导致计数器变为负数，避免逻辑异常
            if (_referenceCount > 0)
            {
                _referenceCount--;

                // 引用计数归 0 时执行物理卸载，关闭 SDK 所有隐形线程与资源
                if (_referenceCount == 0)
                {
                    //// [物理卸载] 释放 SDK 占用的非托管资源（如网络连接、内存缓冲区）
                    //HikNativeMethods.NET_DVR_Cleanup();
                }
            }
        }
    }

    #endregion

    #region --- 播放库预热 (PlayCtrl Warm-up) ---

    /// <summary>
    /// [核心策略] 强制冷启动诱发
    /// 职责：在系统真正取流前，强行触发一次 PlayCtrl.dll 的硬件探测（声卡、显卡、DirectDraw）
    /// 目的：规避首次取流时的 12-18 秒延迟，提前完成硬件初始化
    /// </summary>
    public static void ForceWarmUp()
    {
        // 已预热过则直接返回，避免重复执行
        if (_isWarmedUp) return;

        Log.ForContext("SourceContext", LogModules.Core)
            .Debug($"正在进行播放库硬件探测预热，请稍候...");

        Stopwatch sw = Stopwatch.StartNew();
        int tempPort = -1;

        // 第一次调用 PlayM4_GetPort：触发 PlayCtrl.dll 底层硬件初始化（耗时主要集中在这里）
        if (HikPlayMethods.PlayM4_GetPort(ref tempPort))
        {
            // 必须释放临时端口，避免端口资源泄漏（PlayCtrl.dll 端口数量有限）
            HikPlayMethods.PlayM4_FreePort(tempPort);
        }

        sw.Stop();
        _isWarmedUp = true;

        Log.ForContext("SourceContext", LogModules.Core)
            .Debug($"预热完成！耗时: {sw.ElapsedMilliseconds}ms.");
    }

    #endregion
}