namespace SHH.CameraSdk;

/// <summary>
/// 海康 HCNetSDK.dll 原生方法封装（静态部分类）
/// 功能：包含设备登录、预览、PTZ控制、异常回调等核心 SDK 接口定义
/// 注意：所有 API 均直接映射海康原生 DLL 函数，参数顺序与类型需严格匹配官方文档
/// </summary>
public static partial class HikNativeMethods
{
    #region --- 基础配置 (Basic Configuration) ---

    /// <summary>
    /// HCNetSDK.dll 动态库路径
    /// 说明：确保项目中该路径与实际文件位置一致，否则会导致 DllImport 调用失败
    /// </summary>
    private const string DllName = "Drivers\\Hikvision\\HCNetSDK.dll";

    #endregion

    #region --- 结构体定义 (Structures) ---

    /// <summary>
    /// 设备信息结构体 (NET_DEVICEINFO_V30)
    /// 功能：存储设备序列号、通道数、协议类型、能力集等核心信息
    /// 注：登录设备成功后通过 NET_DVR_Login_V30 接口返回
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct NET_DEVICEINFO_V30
    {
        /// <summary> 设备序列号（长度48字节） </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)]
        public byte[] sSerialNumber;

        /// <summary> 报警输入个数 </summary>
        public byte byAlarmInPortNum;

        /// <summary> 报警输出个数 </summary>
        public byte byAlarmOutPortNum;

        /// <summary> 硬盘个数 </summary>
        public byte byDiskNum;

        /// <summary> 设备类型：1-DVR，2-ATM DVR，3-DVS 等 </summary>
        public byte byDVRType;

        /// <summary> 模拟通道个数 </summary>
        public byte byChanNum;

        /// <summary> 起始通道号（目前从1开始） </summary>
        public byte byStartChan;

        /// <summary> 语音通道数 </summary>
        public byte byAudioChanNum;

        /// <summary> 最大数字通道个数（低8位） </summary>
        public byte byIPChanNum;

        /// <summary> 零通道编码个数 </summary>
        public byte byZeroChanNum;

        /// <summary> 主码流传输协议类型：0-私有协议，1-RTSP，2-同时支持两者 </summary>
        public byte byMainProto;

        /// <summary> 子码流传输协议类型：0-私有协议，1-RTSP，2-同时支持两者 </summary>
        public byte bySubProto;

        /// <summary> 基础能力集（位掩码），位与结果为1表示支持对应功能 </summary>
        /// <remarks>
        /// bySupport & 0x1: 支持智能搜索<br/>
        /// bySupport & 0x2: 支持备份<br/>
        /// bySupport & 0x4: 支持压缩参数能力获取<br/>
        /// bySupport & 0x8: 支持多网卡<br/>
        /// bySupport & 0x10: 支持远程SADP<br/>
        /// bySupport & 0x20: 支持Raid卡功能<br/>
        /// bySupport & 0x40: 支持IPSAN目录查找<br/>
        /// bySupport & 0x80: 支持RTP over RTSP
        /// </remarks>
        public byte bySupport;

        /// <summary> 能力集扩充（位掩码），位与结果为1表示支持对应功能 </summary>
        /// <remarks>
        /// bySupport1 & 0x1: 支持SNMP v30<br/>
        /// bySupport1 & 0x2: 支持区分回放和下载<br/>
        /// bySupport1 & 0x4: 支持布防优先级<br/>
        /// bySupport1 & 0x8: 智能设备支持布防时间段扩展<br/>
        /// bySupport1 & 0x10: 支持多磁盘数（超过33个）<br/>
        /// bySupport1 & 0x20: 支持RTSP over HTTP<br/>
        /// bySupport1 & 0x80: 支持车牌新报警信息（2012-9-28），且支持NET_DVR_IPPARACFG_V40结构体
        /// </remarks>
        public byte bySupport1;

        /// <summary> 能力集扩充（位掩码），位与结果为1表示支持对应功能 </summary>
        /// <remarks>
        /// bySupport2 & 0x1: 解码器支持通过URL取流解码<br/>
        /// bySupport2 & 0x2: 支持FTP V40<br/>
        /// bySupport2 & 0x4: 支持ANR<br/>
        /// bySupport2 & 0x8: 支持CCD的通道参数配置<br/>
        /// bySupport2 & 0x10: 支持布防报警回传信息（仅抓拍机报警，新老报警结构）<br/>
        /// bySupport2 & 0x20: 支持单独获取设备状态子项<br/>
        /// bySupport2 & 0x40: 是码流加密设备
        /// </remarks>
        public byte bySupport2;

        /// <summary> 设备型号 </summary>
        public ushort wDevType;

        /// <summary> 能力集扩充（位掩码），位与结果为1表示支持对应功能 </summary>
        /// <remarks>
        /// bySupport3 & 0x1: 支持多码流<br/>
        /// bySupport3 & 0x4: 支持按组配置（通道图像参数、报警输入参数等）<br/>
        /// bySupport3 & 0x8: 支持TCP/UDP/多播预览的延时预览字段<br/>
        /// bySupport3 & 0x10: 支持获取报警主机主要状态（V40）<br/>
        /// bySupport3 & 0x20: 支持通过DDNS域名解析取流
        /// </remarks>
        public byte bySupport3;

        /// <summary> 多码流支持标识（按位表示） </summary>
        /// <remarks>0-不支持，1-支持；bit1-码流3，bit2-码流4，bit7-主码流，bit8-子码流</remarks>
        public byte byMultiStreamProto;

        /// <summary> 起始数字通道号（0表示无效） </summary>
        public byte byStartDChan;

        /// <summary> 起始数字对讲通道号（0表示无效） </summary>
        public byte byStartDTalkChan;

        /// <summary> 数字通道个数（高8位） </summary>
        public byte byHighDChanNum;

        /// <summary> 能力集扩充（位掩码），位与结果为1表示支持对应功能 </summary>
        public byte bySupport4;

        /// <summary> 支持语种能力（按位表示） </summary>
        /// <remarks>
        /// byLanguageType = 0: 老设备<br/>
        /// byLanguageType & 0x1: 支持中文<br/>
        /// byLanguageType & 0x2: 支持英文
        /// </remarks>
        public byte byLanguageType;

        /// <summary> 音频输入通道数 </summary>
        public byte byVoiceInChanNum;

        /// <summary> 音频输入起始通道号 </summary>
        public byte byStartVoiceInChanNo;

        /// <summary> 保留字段（必须置0） </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
        public byte[] byRes3;

        /// <summary> AES算法加密/解密能力 </summary>
        public byte byMirrorCap;

        /// <summary> 起始数字通道号（扩展） </summary>
        public ushort wStartIPChanNo;

        /// <summary> 保留字段（必须置0） </summary>
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)]
        public byte[] byRes;
    }

    /// <summary>
    /// 预览参数结构体 (NET_DVR_PREVIEWINFO)
    /// 功能：配置实时预览的通道、码流类型、连接方式等参数
    /// 注：用于 NET_DVR_RealPlay_V40 接口的输入参数
    /// </summary>
    [StructLayoutAttribute(LayoutKind.Sequential)]
    public struct NET_DVR_PREVIEWINFO
    {
        /// <summary> 通道号（模拟通道从1开始） </summary>
        public Int32 lChannel;

        /// <summary> 码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推 </summary>
        public uint dwStreamType;

        /// <summary> 连接方式：0-TCP，1-UDP，2-多播，3-RTP，4-RTP/RTSP，5-RTSP/HTTP </summary>
        public uint dwLinkMode;

        /// <summary> 播放窗口句柄 </summary>
        /// <remarks>IntPtr.Zero 表示不让 SDK 直接渲染，仅获取原始流数据</remarks>
        public IntPtr hPlayWnd;

        /// <summary> 取流模式：0-非阻塞，1-阻塞（阻塞模式超时5秒返回） </summary>
        /// <remarks>阻塞模式不适合轮询取流操作</remarks>
        public bool bBlocked;

        /// <summary> 是否启用回放录像：0-不启用，1-启用 </summary>
        public bool bPassbackRecord;

        /// <summary> 预览模式：0-正常预览，1-延迟预览 </summary>
        public byte byPreviewMode;

        /// <summary> 流ID（lChannel为0xffffffff时启用，长度32字节） </summary>
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = STREAM_ID_LEN, ArraySubType = UnmanagedType.I1)]
        public byte[] byStreamID;

        /// <summary> 应用层协议类型：0-私有协议，1-RTSP协议 </summary>
        public byte byProtoType;

        /// <summary> 保留字段（必须置0） </summary>
        public byte byRes1;

        /// <summary> 码流编解码类型：0-通用编码数据，1-热成像原始数据（含温度加密信息） </summary>
        public byte byVideoCodingType;

        /// <summary> 播放库最大缓冲帧数（范围1-50，0表示默认1帧） </summary>
        public uint dwDisplayBufNum;

        /// <summary> NPQ模式：0-直连，1-过流媒体 </summary>
        public byte byNPQMode;

        /// <summary> 保留字段（必须置0） </summary>
        [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 215, ArraySubType = UnmanagedType.I1)]
        public byte[] byRes;
    }

    /// <summary>
    /// 时间结构体 (NET_DVR_TIME)
    /// [Fix Bug P: 结构体炸弹] 修复结构体对齐问题，避免栈内存覆盖导致随机崩溃
    /// </summary>
    /// <remarks>
    /// 原问题：ushort/byte 混合定义导致结构体总大小不足16字节，SDK写入时覆盖栈变量<br/>
    /// 修复方案：使用 Pack=4 对齐，成员类型统一为 uint（4字节），与 C++ DWORD 匹配
    /// </remarks>
    [StructLayout(LayoutKind.Sequential, Pack = 4)]
    public struct NET_DVR_TIME
    {
        public uint dwYear;   // 年份
        public uint dwMonth;  // 月份（1-12）
        public uint dwDay;    // 日期（1-31）
        public uint dwHour;   // 小时（0-23）
        public uint dwMinute; // 分钟（0-59）
        public uint dwSecond; // 秒（0-59）
    }

    #endregion

    #region --- 常量定义 (Constants) ---

    /// <summary> 流ID长度（32字节） </summary>
    public const int STREAM_ID_LEN = 32;

    /// <summary> 数据类型常量：系统头数据 </summary>
    public const int NET_DVR_SYSHEAD = 1;

    /// <summary> 数据类型常量：视频流数据（H.264/H.265） </summary>
    public const int NET_DVR_STREAMDATA = 2;

    /// <summary> 数据类型常量：音频数据 </summary>
    public const int NET_DVR_AUDIOSTREAMDATA = 3;

    /// <summary> 命令常量：获取时间配置 </summary>
    public const uint NET_DVR_GET_TIMECFG = 118;

    /// <summary> 命令常量：设置时间 </summary>
    public const int NET_DVR_SET_TIMECFG = 119;

    #endregion

    #region --- PTZ 控制相关 (PTZ Control) ---

    /// <summary> PTZ命令常量：镜头控制 </summary>
    public const uint ZOOM_IN = 11;    // 焦距变大（拉近）
    public const uint ZOOM_OUT = 12;   // 焦距变小（拉远）
    public const uint FOCUS_NEAR = 13; // 焦点前调
    public const uint FOCUS_FAR = 14;  // 焦点后调
    public const uint IRIS_OPEN = 15;  // 光圈扩大
    public const uint IRIS_CLOSE = 16; // 光圈缩小

    /// <summary> PTZ命令常量：方向控制 </summary>
    public const uint TILT_UP = 21;    // 云台上仰
    public const uint TILT_DOWN = 22;  // 云台下俯
    public const uint PAN_LEFT = 23;   // 云台左转
    public const uint PAN_RIGHT = 24;  // 云台右转
    public const uint UP_LEFT = 25;    // 上左移动
    public const uint UP_RIGHT = 26;   // 上右移动
    public const uint DOWN_LEFT = 27;  // 下左移动
    public const uint DOWN_RIGHT = 28; // 下右移动
    public const uint PAN_AUTO = 29;   // 自动扫描

    /// <summary> PTZ命令常量：辅助功能 </summary>
    public const uint LIGHT_PWRON = 2; // 接通灯光电源
    public const uint WIPER_PWRON = 3; // 接通雨刷开关

    #endregion

    #region --- 异常回调相关 (Exception Callback) ---

    /// <summary> 异常类型常量 </summary>
    public const int EXCEPTION_EXCHANGE = 0x8000;    // 用户交互时异常
    public const int EXCEPTION_AUDIOEXCHANGE = 0x8001; // 语音对讲异常
    public const int EXCEPTION_ALARM = 0x8002;       // 报警异常
    public const int EXCEPTION_PREVIEW = 0x8003;     // 网络预览异常
    public const int EXCEPTION_SERIAL = 0x8004;      // 透明通道异常
    public const int EXCEPTION_RECONNECT = 0x8005;   // 预览时重连成功

    /// <summary>
    /// 异常消息回调委托
    /// 功能：SDK 发生异常时触发，返回异常类型、用户ID、相关句柄等信息
    /// </summary>
    /// <param name="dwType">异常类型（对应 EXCEPTION_XXX 常量）</param>
    /// <param name="lUserID">用户ID（NET_DVR_Login_V30 返回值）</param>
    /// <param name="lHandle">异常关联句柄（预览句柄/报警句柄等）</param>
    /// <param name="pUser">用户自定义数据指针</param>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void EXCEPTION_CALLBACK(uint dwType, int lUserID, int lHandle, IntPtr pUser);

    #endregion

    #region --- 预览回调相关 (Preview Callback) ---

    /// <summary>
    /// 预览数据回调委托
    /// 功能：实时预览时触发，返回原始流数据（系统头/视频流/音频流）
    /// </summary>
    /// <param name="lRealHandle">预览句柄（NET_DVR_RealPlay_V40 返回值）</param>
    /// <param name="dwDataType">数据类型（对应 NET_DVR_XXX 数据类型常量）</param>
    /// <param name="pBuffer">数据缓冲区指针</param>
    /// <param name="dwBufSize">缓冲区大小（字节）</param>
    /// <param name="pUser">用户自定义数据指针</param>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void REALDATACALLBACK(Int32 lRealHandle, UInt32 dwDataType, IntPtr pBuffer, UInt32 dwBufSize, IntPtr pUser);

    #endregion

    #region --- SDK 基础接口 (Basic SDK Interfaces) ---

    /// <summary>
    /// 初始化 SDK
    /// 功能：调用所有其他 SDK 接口的前提，必须先初始化再使用
    /// </summary>
    /// <returns>初始化成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_Init();

    /// <summary>
    /// 释放 SDK 资源
    /// 功能：程序退出前调用，释放 SDK 占用的非托管资源（网络连接、内存等）
    /// </summary>
    /// <returns>释放成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_Cleanup();

    /// <summary>
    /// 获取最后一次操作的错误码
    /// 功能：API 调用失败后，通过此接口获取具体错误原因
    /// </summary>
    /// <returns>错误码（需结合海康官方文档查询含义）</returns>
    [DllImport(DllName)]
    public static extern uint NET_DVR_GetLastError();

    /// <summary>
    /// 设置网络连接超时时间和连接尝试次数
    /// </summary>
    /// <param name="dwWaitTime">超时时间（毫秒），推荐 3000ms</param>
    /// <param name="dwTryTimes">连接尝试次数，推荐 1 次</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_SetConnectTime(uint dwWaitTime, uint dwTryTimes);

    /// <summary>
    /// 设置自动重连功能
    /// </summary>
    /// <param name="dwInterval">重连间隔（毫秒），推荐 10000ms</param>
    /// <param name="bEnableRecon">是否启用重连：0-禁用，1-启用</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_SetReconnect(uint dwInterval, bool bEnableRecon);

    #endregion

    #region --- 设备登录/登出接口 (Device Login/Logout) ---

    /// <summary>
    /// 用户注册设备（登录）
    /// 功能：建立与设备的连接，获取用户ID（后续接口调用的核心标识）
    /// </summary>
    /// <param name="sDVRIP">设备IP地址</param>
    /// <param name="wDVRPort">设备端口号（海康默认8000）</param>
    /// <param name="sUserName">登录用户名（默认 admin）</param>
    /// <param name="sPassword">登录密码</param>
    /// <param name="lpDeviceInfo">输出参数：设备信息结构体</param>
    /// <returns>登录成功返回用户ID（非负整数），失败返回 -1</returns>
    [DllImport(DllName)]
    public static extern int NET_DVR_Login_V30(string sDVRIP, Int32 wDVRPort, string sUserName, string sPassword, ref NET_DEVICEINFO_V30 lpDeviceInfo);

    /// <summary>
    /// 用户注销（登出）
    /// 功能：断开与设备的连接，释放用户ID关联的资源
    /// </summary>
    /// <param name="lUserID">用户ID（NET_DVR_Login_V30 返回值）</param>
    /// <returns>登出成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_Logout(int lUserID);

    #endregion

    #region --- 预览控制接口 (Preview Control) ---

    /// <summary>
    /// 实时预览（V40版本，支持回调）
    /// 功能：启动设备实时取流，通过回调获取原始流数据
    /// </summary>
    /// <param name="lUserID">用户ID（NET_DVR_Login_V30 返回值）</param>
    /// <param name="lpPreviewInfo">预览参数结构体</param>
    /// <param name="fRealDataCallBack_V30">流数据回调函数</param>
    /// <param name="pUser">用户自定义数据指针</param>
    /// <returns>预览成功返回预览句柄（非负整数），失败返回 -1</returns>
    [DllImport(DllName)]
    public static extern int NET_DVR_RealPlay_V40(int lUserID, ref NET_DVR_PREVIEWINFO lpPreviewInfo, REALDATACALLBACK fRealDataCallBack_V30, IntPtr pUser);

    /// <summary>
    /// 停止预览
    /// 功能：停止实时取流，释放预览句柄关联的资源
    /// </summary>
    /// <param name="lRealHandle">预览句柄（NET_DVR_RealPlay_V40 返回值）</param>
    /// <returns>停止成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_StopRealPlay(int lRealHandle);

    /// <summary>
    /// 强制生成I帧
    /// 功能：主动触发设备发送I帧，优化视频流解码延时
    /// </summary>
    /// <param name="lUserID">用户ID</param>
    /// <param name="lChannel">通道号</param>
    /// <returns>操作成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_MakeKeyFrame(int lUserID, int lChannel);

    #endregion

    #region --- PTZ 控制接口 (PTZ Control Interfaces) ---

    /// <summary>
    /// 云台控制（带速度）
    /// 功能：控制云台旋转、镜头缩放、光圈调节等操作
    /// </summary>
    /// <param name="lUserID">用户ID</param>
    /// <param name="lChannel">通道号</param>
    /// <param name="dwPTZCommand">PTZ控制命令（对应 PTZ 命令常量）</param>
    /// <param name="dwStop">启停标识：0-开始，1-停止</param>
    /// <param name="dwSpeed">控制速度（1-7，数值越大速度越快）</param>
    /// <returns>操作成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_PTZControlWithSpeed_Other(int lUserID, int lChannel, uint dwPTZCommand, uint dwStop, uint dwSpeed);

    #endregion

    #region --- 异常回调接口 (Exception Callback Interfaces) ---

    /// <summary>
    /// 设置连接超时时间和重连策略（兼容旧版本）
    /// </summary>
    /// <param name="dwInterval">重连间隔（毫秒），建议 3000</param>
    /// <param name="bEnableRecon">是否启用重连：1-启用，0-禁用</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_SetReconnect(uint dwInterval, int bEnableRecon);

    /// <summary>
    /// 注册异常、重连等消息的回调函数
    /// 功能：绑定异常回调委托，接收 SDK 层面的异常通知
    /// </summary>
    /// <param name="nMessage">消息类型（0 表示所有消息）</param>
    /// <param name="hWnd">窗口句柄（可为 IntPtr.Zero）</param>
    /// <param name="fExceptionCallBack">异常回调函数委托</param>
    /// <param name="pUser">用户自定义数据指针</param>
    /// <returns>注册成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_SetExceptionCallBack_V30(uint nMessage, IntPtr hWnd, EXCEPTION_CALLBACK fExceptionCallBack, IntPtr pUser);

    #endregion

    #region --- 通用配置接口 (General Configuration Interfaces) ---

    /// <summary>
    /// 获取设备配置
    /// 功能：通用接口，根据命令号获取设备特定配置（如时间配置、通道参数等）
    /// </summary>
    /// <param name="lUserID">用户ID</param>
    /// <param name="dwCommand">配置命令号（如 NET_DVR_GET_TIMECFG）</param>
    /// <param name="lChannel">通道号（-1 表示设备级配置）</param>
    /// <param name="lpOutBuffer">输出缓冲区指针（存储配置数据）</param>
    /// <param name="dwOutBufferSize">输出缓冲区大小（字节）</param>
    /// <param name="lpBytesReturned">输出参数：实际返回的数据大小（字节）</param>
    /// <returns>获取成功返回 true，失败返回 false</returns>
    [DllImport(DllName, CallingConvention = CallingConvention.StdCall)]
    public static extern bool NET_DVR_GetDVRConfig(
        int lUserID,
        uint dwCommand,
        int lChannel,
        IntPtr lpOutBuffer,
        uint dwOutBufferSize,
        ref uint lpBytesReturned);

    #endregion


    [DllImport(DllName)]
    public static extern bool NET_DVR_SetDVRConfig(int lUserID, uint dwCommand, int lChannel, System.IntPtr lpInBuffer, uint dwInBufferSize);

    /// <summary>
    /// 设备重启
    /// </summary>
    /// <param name="lUserID"></param>
    /// <returns></returns>
    [DllImport(DllName)]
    public static extern bool NET_DVR_RebootDVR(int lUserID);
}