namespace SHH.CameraSdk;

/// <summary>
/// 海康播放库 PlayCtrl.dll 的封装
/// 完全参考官方 WinPlayCtrl.cs 定义，提供解码、播放、端口管理等核心能力
/// </summary>
public static class HikPlayMethods
{
    #region --- 基础配置 (Basic Configuration) ---

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

    #endregion

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

    /// <summary> 最大支持的通道数 </summary>
    public const int PLAYM4_MAX_SUPPORTS = 500;

    // 流模式常量
    public const int STREAME_REALTIME = 0; // 实时流模式
    public const int STREAME_FILE = 1;    // 文件流模式

    // 帧类型常量（音频/视频）
    public const int T_AUDIO16 = 101; // 16位音频帧
    public const int T_AUDIO8 = 100;  // 8位音频帧
    public const int T_UYVY = 1;      // UYVY格式视频帧
    public const int T_YV12 = 3;      // YV12格式视频帧（常用）
    public const int T_RGB32 = 7;     // RGB32格式视频帧

    // 显示缓冲区大小常量
    public const int MAX_DIS_FRAMES = 50; // 最大显示缓冲帧数
    public const int MIN_DIS_FRAMES = 1;  // 最小显示缓冲帧数

    // 源缓冲区大小常量（单位：字节）
    public const int SOURCE_BUF_MAX = 1024 * 100000; // 最大源缓冲区（100MB）
    public const int SOURCE_BUF_MIN = 1024 * 50;    // 最小源缓冲区（50KB）

    // 错误码常量（PlayCtrl.dll 返回错误标识）
    public const int PLAYM4_NOERROR = 0;               // 无错误
    public const int PLAYM4_PARA_OVER = 1;             // 参数超出范围
    public const int PLAYM4_ORDER_ERROR = 2;           // 函数调用顺序错误
    public const int PLAYM4_TIMER_ERROR = 3;           // 定时器初始化错误
    public const int PLAYM4_DEC_VIDEO_ERROR = 4;       // 视频解码错误
    public const int PLAYM4_DEC_AUDIO_ERROR = 5;       // 音频解码错误
    public const int PLAYM4_ALLOC_MEMORY_ERROR = 6;    // 内存分配错误
    public const int PLAYM4_OPEN_FILE_ERROR = 7;       // 打开文件错误
    public const int PLAYM4_CREATE_OBJ_ERROR = 8;      // 创建对象错误
    public const int PLAYM4_CREATE_DDRAW_ERROR = 9;    // 创建DirectDraw错误
    public const int PLAYM4_CREATE_OFFSCREEN_ERROR = 10;// 创建离屏表面错误
    public const int PLAYM4_BUF_OVER = 11;             // 缓冲区溢出
    public const int PLAYM4_CREATE_SOUND_ERROR = 12;   // 创建音频设备错误
    public const int PLAYM4_SET_VOLUME_ERROR = 13;     // 设置音量错误
    public const int PLAYM4_SUPPORT_FILE_ONLY = 14;    // 仅支持文件流
    public const int PLAYM4_SUPPORT_STREAM_ONLY = 15;  // 仅支持实时流
    public const int PLAYM4_SYS_NOT_SUPPORT = 16;      // 系统不支持该功能
    public const int PLAYM4_FILEHEADER_UNKNOWN = 17;   // 文件头格式未知
    public const int PLAYM4_VERSION_INCORRECT = 18;    // 版本不匹配
    public const int PLAYM4_INIT_DECODER_ERROR = 19;   // 解码器初始化错误
    public const int PLAYM4_CHECK_FILE_ERROR = 20;     // 校验文件错误
    public const int PLAYM4_INIT_TIMER_ERROR = 21;     // 初始化定时器错误
    public const int PLAYM4_BLT_ERROR = 22;            // 图像绘制错误
    public const int PLAYM4_UPDATE_ERROR = 23;         // 更新显示错误

    // PTZ控制命令常量（保留自定义逻辑，官方示例未包含）
    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; // 光圈缩小
    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;   // 云台自动扫描

    #endregion

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

    /// <summary>
    /// 帧信息结构体：存储解码后帧的宽高、帧率、序号等关键信息
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct FRAME_INFO
    {
        public int nWidth;      // 帧宽度（像素）
        public int nHeight;     // 帧高度（像素）
        public int nStamp;      // 时间戳
        public int nType;       // 帧类型（对应 T_XXX 常量）
        public int nFrameRate;  // 帧率（fps）
        public uint dwFrameNum; // 帧序号
    }

    /// <summary>
    /// 帧位置结构体：存储文件流中帧的位置、时间等信息
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct FRAME_POS
    {
        public int nFilePos;           // 文件中的位置偏移
        public int nFrameNum;          // 帧序号
        public int nFrameTime;         // 帧时间（毫秒）
        public int nErrorFrameNum;     // 错误帧数
        public IntPtr pErrorTime;      // 错误时间数组指针
        public int nErrorLostFrameNum; // 丢失的错误帧数
        public int nErrorFrameSize;    // 错误帧大小
    }

    /// <summary>
    /// 帧类型结构体：存储帧数据缓冲区、大小等信息
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct FRAME_TYPE
    {
        [MarshalAs(UnmanagedType.LPStr)]
        public string pDataBuf; // 帧数据缓冲区指针
        public int nSize;       // 缓冲区大小（字节）
        public int nFrameNum;   // 帧序号
        public bool bIsAudio;   // 是否为音频帧
        public int nReserved;   // 保留字段（置0）
    }

    #endregion

    #region --- 委托定义 (Delegates) ---

    /// <summary>
    /// 解码回调委托 (对应官方 DECCBFUN)
    /// 功能：解码完成后触发，返回解码后的帧数据
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="pBuf">解码后数据缓冲区指针</param>
    /// <param name="nSize">缓冲区大小（字节）</param>
    /// <param name="pFrameInfo">帧信息结构体（引用传递）</param>
    /// <param name="nReserved1">保留字段1（置0）</param>
    /// <param name="nReserved2">保留字段2（置0）</param>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void DECCBFUN(
        int nPort,
        IntPtr pBuf,
        int nSize,
        ref FRAME_INFO pFrameInfo,
        int nReserved1,
        int nReserved2
    );

    /// <summary>
    /// 显示回调委托 (对应官方 DISPLAYCBFUN)
    /// 功能：帧数据准备显示时触发，用于自定义渲染逻辑
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="pBuf">显示数据缓冲区指针</param>
    /// <param name="nSize">缓冲区大小（字节）</param>
    /// <param name="nWidth">显示宽度（像素）</param>
    /// <param name="nHeight">显示高度（像素）</param>
    /// <param name="nStamp">时间戳</param>
    /// <param name="nType">数据类型（对应 T_XXX 常量）</param>
    /// <param name="nReserved">保留字段（置0）</param>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void DISPLAYCBFUN(
        int nPort,
        IntPtr pBuf,
        int nSize,
        int nWidth,
        int nHeight,
        int nStamp,
        int nType,
        int nReserved
    );

    /// <summary>
    /// 文件结束回调委托
    /// 功能：文件流播放完成时触发
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="pUser">用户自定义数据指针</param>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public delegate void FILEENDCALLBACK(int nPort, IntPtr pUser);

    #endregion

    #region --- API 导入 (Dll Imports) ---

    /// <summary>
    /// 获取闲置的播放端口。
    /// <para>[警告] 此函数非线程安全，且端口资源有限（最多500个）。</para>
    /// <para>高并发场景下必须加全局锁，防止端口分配冲突。</para>
    /// </summary>
    /// <param name="nPort">输出参数：获取到的闲置端口号（输出-1表示失败）</param>
    /// <returns>获取成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_GetPort(ref int nPort);

    /// <summary>
    /// 释放播放端口
    /// 功能：不再使用端口时调用，避免端口资源泄漏
    /// </summary>
    /// <param name="nPort">要释放的端口号</param>
    /// <returns>释放成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_FreePort(int nPort);

    /// <summary>
    /// 打开流
    /// 功能：初始化端口的流缓冲区，准备接收流数据
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="pFileHeadBuf">文件头数据缓冲区指针（实时流可为空）</param>
    /// <param name="nSize">缓冲区大小（字节）</param>
    /// <param name="nBufPoolSize">流缓冲区池大小（字节）</param>
    /// <returns>打开成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_OpenStream(int nPort, IntPtr pFileHeadBuf, uint nSize, uint nBufPoolSize);

    /// <summary>
    /// 关闭流
    /// 功能：停止接收流数据，释放流缓冲区资源
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <returns>关闭成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_CloseStream(int nPort);

    /// <summary>
    /// 开始播放
    /// 功能：启动解码和显示流程，绑定到指定窗口句柄
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="hWnd">显示窗口句柄（IntPtr.Zero 表示不绑定窗口）</param>
    /// <returns>启动成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_Play(int nPort, IntPtr hWnd);

    /// <summary>
    /// 停止播放
    /// 功能：停止解码和显示，释放播放相关资源
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <returns>停止成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_Stop(int nPort);

    /// <summary>
    /// 输入流数据
    /// 功能：向播放端口推送原始流数据，供解码使用
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="pBuf">流数据缓冲区指针</param>
    /// <param name="nSize">数据大小（字节）</param>
    /// <returns>输入成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_InputData(int nPort, IntPtr pBuf, uint nSize);

    /// <summary>
    /// 设置解码回调 (Ex版本)
    /// 功能：绑定解码完成后的回调函数，用于获取解码后的帧数据
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="DecCBFun">解码回调函数委托</param>
    /// <param name="pDest">目标缓冲区指针（可为空）</param>
    /// <param name="nDestSize">目标缓冲区大小（字节）</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_SetDecCallBackEx(int nPort, DECCBFUN DecCBFun, IntPtr pDest, int nDestSize);

    /// <summary>
    /// 设置流打开模式
    /// 功能：指定端口接收的流类型（实时流/文件流）
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="nMode">流模式（对应 STREAME_XXX 常量）</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_SetStreamOpenMode(int nPort, uint nMode);

    /// <summary>
    /// 设置显示缓冲区数量
    /// 功能：调整显示缓冲帧数，平衡流畅度与延迟
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="nNum">缓冲帧数（范围：MIN_DIS_FRAMES ~ MAX_DIS_FRAMES）</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_SetDisplayBuf(int nPort, uint nNum);

    /// <summary>
    /// 设置叠加模式
    /// 功能：配置图像叠加方式及透明色
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="bOverlay">是否启用叠加（1=启用，0=禁用）</param>
    /// <param name="colorKey">透明色键值</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_SetOverlayMode(int nPort, int bOverlay, uint colorKey);

    /// <summary>
    /// 获取最后一次错误码
    /// 功能：API 调用失败后，获取具体错误原因（对应 PLAYM4_XXX 错误常量）
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <returns>错误码（0 表示无错误）</returns>
    [DllImport(DllName)]
    public static extern uint PlayM4_GetLastError(int nPort);

    /// <summary>
    /// 设置视频解码模式
    /// 功能：切换硬解码/软解码模式（补充：用于硬件加速优化）
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <param name="nMode">解码模式（0=软解码，1=硬解码，具体值参考官方文档）</param>
    /// <returns>设置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_SetDecVideoMode(int nPort, int nMode);

    /// <summary>
    /// 获取源缓冲区剩余空间
    /// 功能：查询端口流缓冲区的剩余可用空间（字节）
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <returns>剩余空间大小（字节）</returns>
    [DllImport(DllName)]
    public static extern uint PlayM4_GetSourceBufferRemain(int nPort);

    /// <summary>
    /// 重置源缓冲区
    /// 功能：清空端口流缓冲区中的未解码数据
    /// </summary>
    /// <param name="nPort">播放端口号</param>
    /// <returns>重置成功返回 true，失败返回 false</returns>
    [DllImport(DllName)]
    public static extern bool PlayM4_ResetSourceBuffer(int nPort);

    /// <summary>
    /// [新增] 开启硬件解码
    /// </summary>
    [DllImport(DllName)]
    public static extern bool PlayM4_SetHardWareDecode(int nPort, int nMode);

    #endregion
}