package com.sz.admin.monitor.sdk.hkSdk;

import cn.hutool.core.date.DateUtil;
import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import com.sz.admin.monitor.common.CommonKit;
import com.sz.admin.monitor.pojo.po.Camera;
import com.sz.admin.monitor.pojo.po.Nvr;
import com.sz.admin.monitor.pojo.po.RecordFile;
import com.sz.admin.monitor.sdk.AbstractNVR;
import com.sz.admin.monitor.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.sz.admin.monitor.sdk.hkSdk.HCNetSDK.NET_DVR_CHECK_USER_STATUS;

/**
 * ClassName: HKNVR
 * Package: com.sz.admin.monitor.hik
 * Description:
 */
@Component
@Slf4j
public class HkNVR  extends AbstractNVR {
    static HCNetSDK hCNetSDK = null;
    static FExceptionCallBack_Imp fExceptionCallBack;//异常回调
    private final VcrlUserIdContainer vcrlUserIdContainer;
    // Linux系统下的SDK路径
    private String hkSdkLibPath = "/home/rytec/sdk/libsHK/";
    // 抓图的保存前置路径
    private  String pathPrefix="D:\\work\\images\\";
    // 录像的保存前置路径
    private String recordPic = "D:\\work\\";

    public HkNVR(VcrlUserIdContainer vcrlUserIdContainer) {
        super();
        this.vcrlUserIdContainer = vcrlUserIdContainer;
    }

    @Override
    public HCNetSDK registerPlugin() {
        if (hCNetSDK == null) {
            if (!createSDKInstance()) {
                System.out.println("Load SDK fail");
                return null;
            }
        }
        //linux系统建议调用以下接口加载组件库
        if (osSelect.isLinux()) {
            HCNetSDK.BYTE_ARRAY ptrByteArray1 = new HCNetSDK.BYTE_ARRAY(256);
            HCNetSDK.BYTE_ARRAY ptrByteArray2 = new HCNetSDK.BYTE_ARRAY(256);
            //这里是库的绝对路径，请根据实际情况修改，注意改路径必须有访问权限
            String strPath1 = hkSdkLibPath + "libcrypto.so.1.1";
            String strPath2 = hkSdkLibPath + "libssl.so.1.1";

            System.arraycopy(strPath1.getBytes(), 0, ptrByteArray1.byValue, 0, strPath1.length());
            ptrByteArray1.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(3, ptrByteArray1.getPointer());

            System.arraycopy(strPath2.getBytes(), 0, ptrByteArray2.byValue, 0, strPath2.length());
            ptrByteArray2.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(4, ptrByteArray2.getPointer());

            String strPathCom = hkSdkLibPath;
            HCNetSDK.NET_DVR_LOCAL_SDK_PATH struComPath = new HCNetSDK.NET_DVR_LOCAL_SDK_PATH();
            System.arraycopy(strPathCom.getBytes(), 0, struComPath.sPath, 0, strPathCom.length());
            struComPath.write();
            hCNetSDK.NET_DVR_SetSDKInitCfg(2, struComPath.getPointer());
        }
        //SDK初始化，一个程序进程只需要调用一次
        hCNetSDK.NET_DVR_Init();
        if (fExceptionCallBack == null) {
            fExceptionCallBack = new FExceptionCallBack_Imp();
        }
        Pointer pUser = null;
        if (!hCNetSDK.NET_DVR_SetExceptionCallBack_V30(0, 0, fExceptionCallBack, pUser)) {
            return null;
        }
        System.out.println("设置异常消息回调成功");

        //启用SDK写日志
//        hCNetSDK.NET_DVR_SetLogToFile(3, "./sdkLog", false);
        return hCNetSDK;
    }

    @Override
    public int loginVcr(String ipAddress, String port, String userName, String password) {
        return login_V40(ipAddress, Short.parseShort(port), userName, password);
    }

    @Override
    public boolean ptzControl(int luerId, int iChannel, String ptzCommand, String dwStop, int dwSpeed) {
        //带速度的云台控制操作(不用启动图象预览)
        return hCNetSDK.NET_DVR_PTZControlWithSpeed_Other(luerId, iChannel, Integer.parseInt(ptzCommand), Integer.parseInt(dwStop), dwSpeed);
    }

    @Override
    public boolean ptzPreset(int luerId, int iChannel, int ptzPresetCmd, String dwPresetIndex) {
       //云台预置点操作(不用启动预览)
        boolean b = hCNetSDK.NET_DVR_PTZPreset_Other(luerId, iChannel, ptzPresetCmd, Integer.parseInt(dwPresetIndex));
        if(!b){
            log.error("调用(设置)预置点失败，错误码:{}", hCNetSDK.NET_DVR_GetLastError());
        }
        return b;
    }

    @Override
    public boolean ptzPreset(int luerId, int iChannel, int ptzPresetCmd, String dwPresetIndex, String pointName) {
        boolean b = hCNetSDK.NET_DVR_PTZPreset_Other(luerId, iChannel, ptzPresetCmd, Integer.parseInt(dwPresetIndex));
        if(!b){
            log.error("调用(设置)预置点失败，错误码:{}", hCNetSDK.NET_DVR_GetLastError());
        }
//        else {
//            if(!ptzPresetCmd.equals("39")){
//                boolean b1 = setPresetName(luerId, iChannel, Integer.parseInt(dwPresetIndex), pointName);
//                try {
//                    String r = IsapiPtzPreset.renamePreset("192.168.2.205", 1, 2, "admin", "rytec.2020", "acxfsvdgfvgfvcgmmmmmmmmmmmmmmmmmmm");
//                } catch (Exception e) {
//                    throw new RuntimeException(e);
//                }
//            }
//        }
        return b;
    }

    @Override
    public String capturePic(int luerId, int iChannel,String fileName) {
        return captureP(luerId, iChannel,fileName);
    }
    /**
     * 动态库加载
     *
     *
     * @return
     */
    private boolean createSDKInstance() {
        if (hCNetSDK == null) {
            synchronized (HCNetSDK.class) {
                String strDllPath = "";
                try {
                    if (osSelect.isWindows())
                    //win系统加载SDK库路径
                    {
                        strDllPath = CommonKit.class.getClassLoader().getResource("").getPath().substring(1) + "lib\\win\\HCNetSDK.dll";
                    } else if (osSelect.isLinux())
                    //Linux系统加载SDK库路径
                    {
                        strDllPath = System.getProperty("user.dir") + "/intelligent-inspection-NVRSDK/libs/HKSDK/libhcnetsdk.so";
                       // strDllPath = hkSdkLibPath + "libhcnetsdk.so";
                    }
                    hCNetSDK = (HCNetSDK) Native.loadLibrary(strDllPath, HCNetSDK.class);

                } catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }
    /**
     * 异常消息回调
     */
    static class FExceptionCallBack_Imp implements HCNetSDK.FExceptionCallBack {
        @Override
        public void invoke(int dwType, int lUserID, int lHandle, Pointer pUser) {
            log.error("异常事件类型:" + dwType);
        }
    }
    /**
     * 设备登录
     *
     * @param ip   设备IP
     * @param port SDK端口，默认设备的8000端口
     * @param user 设备用户名
     * @param psw  设备密码
     */
    public int login_V40(String ip, short port, String user, String psw) {

        //设置连接时间
        hCNetSDK.NET_DVR_SetConnectTime(5000, 1);
        //设置重连时间
        hCNetSDK.NET_DVR_SetReconnect(120000, true);
        hCNetSDK.NET_DVR_SetLogToFile(3, "/home/rytec/data/logs/", true);//日志

        HCNetSDK.NET_DVR_USER_LOGIN_INFO loginInfo = new HCNetSDK.NET_DVR_USER_LOGIN_INFO();
        HCNetSDK.NET_DVR_DEVICEINFO_V40 devInfo = new HCNetSDK.NET_DVR_DEVICEINFO_V40();

        System.arraycopy(ip.getBytes(StandardCharsets.US_ASCII),
            0, loginInfo.sDeviceAddress, 0, ip.length());
        System.arraycopy(user.getBytes(StandardCharsets.US_ASCII),
            0, loginInfo.sUserName, 0, user.length());
        System.arraycopy(psw.getBytes(StandardCharsets.US_ASCII),
            0, loginInfo.sPassword, 0, psw.length());

        loginInfo.wPort = port;
        loginInfo.bUseAsynLogin = false;

        loginInfo.write();
        devInfo.write();

        int iUserID = hCNetSDK.NET_DVR_Login_V40(loginInfo, devInfo);
        devInfo.read();
        if (iUserID < 0) {
            log.error("{}登录失败，错误码为{}", ip, hCNetSDK.NET_DVR_GetLastError());
        } else {
            log.info("{}:设备登录成功！", ip);
        }
        return iUserID;
    }
    /**
     * 抓图
     *
     * @param lUserId
     * @param lchannel
     * @return
     */
    public String captureP(int lUserId, int lchannel, String fileName) {
        HCNetSDK.NET_DVR_JPEGPARA jpegPara = new HCNetSDK.NET_DVR_JPEGPARA();
        jpegPara.wPicSize = (short) 0xFF; // 用当前分辨率
        jpegPara.wPicQuality = 0;        // 0-最好
        jpegPara.write();

        String path = pathPrefix + fileName;

        // 如果文件名/路径可能包含中文，按 SDK 要求改编码（例如 GBK）
        byte[] pathBytes = path.getBytes(StandardCharsets.UTF_8);

        byte[] cStr = new byte[pathBytes.length + 1];
        System.arraycopy(pathBytes, 0, cStr, 0, pathBytes.length);
        cStr[pathBytes.length] = 0;

        boolean ok = hCNetSDK.NET_DVR_CaptureJPEGPicture(lUserId, lchannel, jpegPara, cStr);
        if (!ok) {
            int err = hCNetSDK.NET_DVR_GetLastError();
            log.error("抓图失败，错误码：{}", err);
            return "抓图失败，错误码:" + err;
        }
        return path;
    }
    /**
     * 设备登出
     *
     * @param luserId
     * @return
     */
    public Integer loginOut(int luserId,String ip) {
        boolean b = hCNetSDK.NET_DVR_Logout_V30(luserId);
        if (!b) {
            return hCNetSDK.NET_DVR_GetLastError();
        }
        log.info(ip+"-设备登出成功");
        return 0;
    }
    /**
     * 获取IP通道
     */
    public List<Camera> getIPChannelInfo(int iUserID, Long id) throws UnsupportedEncodingException {
        List<Camera> ipChannelList = new ArrayList<>();
        IntByReference ibrBytesReturned = new IntByReference(0);//获取IP接入配置参数
        HCNetSDK.NET_DVR_IPPARACFG_V40 m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG_V40();
        m_strIpparaCfg.write();
        //lpIpParaConfig 接收数据的缓冲指针
        Pointer lpIpParaConfig = m_strIpparaCfg.getPointer();
        boolean bRet = hCNetSDK.NET_DVR_GetDVRConfig(iUserID, HCNetSDK.NET_DVR_GET_IPPARACFG_V40, 0, lpIpParaConfig, m_strIpparaCfg.size(), ibrBytesReturned);
        m_strIpparaCfg.read();
//        System.out.println("起始数字通道号：" + m_strIpparaCfg.dwStartDChan);

        for (int iChannum = 0; iChannum < m_strIpparaCfg.dwDChanNum; iChannum++) {
            Camera camera = new Camera();
            int channum = iChannum + m_strIpparaCfg.dwStartDChan;
            HCNetSDK.NET_DVR_PICCFG_V40 strPicCfg = new HCNetSDK.NET_DVR_PICCFG_V40();
            strPicCfg.dwSize = strPicCfg.size();
            strPicCfg.write();
            Pointer pStrPicCfg = strPicCfg.getPointer();
            NativeLong lChannel = new NativeLong(channum);
            IntByReference pInt = new IntByReference(0);
            boolean b_GetPicCfg = hCNetSDK.NET_DVR_GetDVRConfig(iUserID, HCNetSDK.NET_DVR_GET_PICCFG_V40, lChannel.intValue(),
                pStrPicCfg, strPicCfg.size(), pInt);
            strPicCfg.read();
            m_strIpparaCfg.struStreamMode[iChannum].read();
            if (m_strIpparaCfg.struStreamMode[iChannum].byGetStreamType == 0) {
                m_strIpparaCfg.struStreamMode[iChannum].uGetStream.setType(HCNetSDK.NET_DVR_IPCHANINFO.class);
                m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.read();

//                System.out.println("--------------第" + (iChannum + 1) + "个通道------------------");
                int channel = m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byIPID + m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byIPIDHigh * 256;
//                System.out.println("channel:" + channel);
                if (channel > 0) {
//                    System.out.println("ip： " + new String(m_strIpparaCfg.struIPDevInfo[channel - 1].struIP.sIpV4).trim());
                    camera.setIpAddress(new String(m_strIpparaCfg.struIPDevInfo[channel - 1].struIP.sIpV4).trim());
                }
//                System.out.println("name： " + new String(strPicCfg.sChanName, "GBK").trim());
                camera.setName(new String(strPicCfg.sChanName, "GBK").trim());
                // 通道号
                camera.setChannelId(channum);
                // 所属 NVR
                camera.setNvrId(id);
                // 用于区分海康，大华的通道
                camera.setChannelDriver(0);
                // 云台类型 0-枪机  1-球体
                camera.setType(1);
                //  可见光 红外
                camera.setVideoType(Integer.valueOf(m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byChannel));
                if (m_strIpparaCfg.struStreamMode[iChannum].uGetStream.struChanInfo.byEnable == 1) {
                    camera.setStatus(1); // 1-在线
//                    System.out.println("IP通道" + channum + "在线");
                } else {
                    camera.setStatus(0); // 0-离线
//                    System.out.println("IP通道" + channum + "不在线");
                }
            }
            if (camera.getIpAddress() != null) {
                ipChannelList.add(camera);
            }
        }
        return ipChannelList;
    }
    /**
     * 3Dptz功能
     *
     * @param lUserID
     * @param lChannel
     * @param threeDPtz
     * @return
     */
    public boolean threeDPositioning(int lUserID, int lChannel, ThreeDPtz threeDPtz) {
        HCNetSDK.NET_DVR_POINT_FRAME point_frame = new HCNetSDK.NET_DVR_POINT_FRAME();
        point_frame.xTop = (int) (threeDPtz.getxTop() * 255 / threeDPtz.getRealPlayWndWidth());
        point_frame.xBottom = (int) (threeDPtz.getxBottom() * 255 / threeDPtz.getRealPlayWndWidth());
        point_frame.yTop = (int) (threeDPtz.getyTop() * 255 / threeDPtz.getRealPlayWndHeight());
        point_frame.yBottom = (int) (threeDPtz.getyBottom() * 255 / threeDPtz.getRealPlayWndHeight());
        point_frame.write();
        boolean b = hCNetSDK.NET_DVR_PTZSelZoomIn_EX(lUserID, lChannel, point_frame);

        if(!b){
            log.error("3Dptz功能错误码：{}", hCNetSDK.NET_DVR_GetLastError());
        }
        return b;
    }
    /**
     * 云台守望
     * @return
     */
    public static HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG getWatchCfg(HCNetSDK sdk, int userId, int channel) {
        HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG cfg = new HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG();
        cfg.dwSize = cfg.size();
        cfg.write();

        IntByReference bytesReturned = new IntByReference(0);
        boolean ok = sdk.NET_DVR_GetDVRConfig(
            userId,
            HCNetSDK.NET_DVR_GET_PTZ_PARKACTION_CFG,
            channel,
            cfg.getPointer(),
            cfg.size(),
            bytesReturned
        );

        if (!ok) {
            System.out.println("GET 守望配置失败 err=" + sdk.NET_DVR_GetLastError());
            return null;
        }

        cfg.read();
        return cfg;
    }
    // 开启守望位：无操作 idleSeconds 秒后 → 回到 presetNo 预置点
    public boolean enableParkActionToPreset(int userId, int channel, int watchTime, int presetId) {
        HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG cfg = new HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG();
        cfg.dwSize = cfg.size();

        cfg.byEnable = 1;
        cfg.byOneTouchSwitch = 0;
        cfg.dwParkTime = watchTime;

        cfg.wActionType = 5;
        cfg.wID = (short) presetId;

        cfg.write();

        boolean ok = hCNetSDK.NET_DVR_SetDVRConfig(
            userId,
            HCNetSDK.NET_DVR_SET_PTZ_PARKACTION_CFG,
            channel,
            cfg.getPointer(),
            cfg.size()
        );

        if (!ok) {
            System.out.println("SET 开启守望失败 err=" + hCNetSDK.NET_DVR_GetLastError());
            return false;
        }
        return true;
    }
    // 关闭守望位
    public boolean disableParkAction(int userId, int channel) {
        HCNetSDK.NET_DVR_PTZ_PARKACTION_CFG cfg = getWatchCfg(hCNetSDK, userId, channel);
        if (cfg == null) return false;

        cfg.byEnable = 0;
        cfg.write();

        boolean ok = hCNetSDK.NET_DVR_SetDVRConfig(
            userId,
            HCNetSDK.NET_DVR_SET_PTZ_PARKACTION_CFG,
            channel,
            cfg.getPointer(),
            cfg.size()
        );

        if (!ok) {
            System.out.println("SET 关闭守望失败 err=" + hCNetSDK.NET_DVR_GetLastError());
            return false;
        }
        return true;
    }
    /**
     * 设备在线状态监测
     */
    public int getDeviceStatus(Nvr nvr) {
        Integer userId = (Integer) vcrlUserIdContainer.getlUserId(nvr.getId().intValue());
        if (userId == null) {
            int loginVcr = this.loginVcr(
                nvr.getIp(),
                String.valueOf(nvr.getPort()),
                nvr.getAccount(),
                nvr.getPassword()
            );
            if (loginVcr < 0) {
                return 0;
            }
            vcrlUserIdContainer.addData(nvr.getId().intValue(), loginVcr);
            return 1;
        }

        boolean online = hCNetSDK.NET_DVR_RemoteControl(
            userId, NET_DVR_CHECK_USER_STATUS, Pointer.NULL, 0
        );

        if (!online) {
            this.loginOut(userId, nvr.getIp());
            int loginVcr = this.loginVcr(
                nvr.getIp(),
                String.valueOf(nvr.getPort()),
                nvr.getAccount(),
                nvr.getPassword()
            );
            if (loginVcr == -1) {
                return 0;
            }
            vcrlUserIdContainer.addData(nvr.getId().intValue(), loginVcr);
        }
        return 1;
    }
    private static Map<String, Integer> realPlayV40Map = new ConcurrentHashMap();

    /**
     *   录像功能
     * @param userId 用户ID
     * @param channelNumber 通道号
     * @param isRecord 是否录像
     * @param fileName 文件名
     * @return
     */
    public String videotaped(Integer userId, Integer channelNumber, boolean isRecord, String fileName) {

        String key = userId + "_" + channelNumber;
        Integer realPlayV40 = realPlayV40Map.get(key);
        if (realPlayV40 == null) {
            HCNetSDK.NET_DVR_PREVIEWINFO netDvrPreviewinfo = new HCNetSDK.NET_DVR_PREVIEWINFO();
            netDvrPreviewinfo.read();
            netDvrPreviewinfo.lChannel = channelNumber;
            netDvrPreviewinfo.dwStreamType = 0;
            netDvrPreviewinfo.dwLinkMode = 0;
            netDvrPreviewinfo.bBlocked = 1;
            netDvrPreviewinfo.bPassbackRecord = 0;
            netDvrPreviewinfo.byProtoType = 1;
            netDvrPreviewinfo.byVideoCodingType = 0;
            netDvrPreviewinfo.write();
            realPlayV40 = hCNetSDK.NET_DVR_RealPlay_V40(userId, netDvrPreviewinfo, null, null);
            realPlayV40Map.put(key, realPlayV40);
        }
        String path = recordPic + fileName;
        if (isRecord) {
            hCNetSDK.NET_DVR_SaveRealData(realPlayV40, path);
            return "";
        } else {
            hCNetSDK.NET_DVR_StopSaveRealData(realPlayV40);
            return path;
        }
    }

    /**
     *   在NVR设备上按时间范围搜索录像文件
     * @param userId
     * @param channelNumber
     * @param startTime
     * @param endTime
     * @return
     * @throws UnsupportedEncodingException
     */
    public List<RecordFile> findRecordFile(Integer userId, Integer channelNumber, LocalDateTime startTime, LocalDateTime endTime) throws UnsupportedEncodingException {
        HCNetSDK.NET_DVR_FILECOND_V40 netDvrFilecondV40 = new HCNetSDK.NET_DVR_FILECOND_V40();
        netDvrFilecondV40.read();
        netDvrFilecondV40.lChannel = channelNumber;
        netDvrFilecondV40.dwFileType = 0xff;
        HCNetSDK.NET_DVR_TIME startDvrTime = new HCNetSDK.NET_DVR_TIME();
        startDvrTime.dwYear= startTime.getYear();        //年
        startDvrTime.dwMonth=startTime.getMonthValue();        //月
        startDvrTime.dwDay=startTime.getDayOfMonth();        //日
        startDvrTime.dwHour=startTime.getHour();        //时
        startDvrTime.dwMinute=startTime.getMinute();        //分
        startDvrTime.dwSecond=startTime.getSecond();        //秒
        HCNetSDK.NET_DVR_TIME endDvrTime = new HCNetSDK.NET_DVR_TIME();
        endDvrTime.dwYear= endTime.getYear();        //年
        endDvrTime.dwMonth=endTime.getMonthValue();        //月
        endDvrTime.dwDay=endTime.getDayOfMonth();        //日
        endDvrTime.dwHour=endTime.getHour();        //时
        endDvrTime.dwMinute=endTime.getMinute();        //分
        endDvrTime.dwSecond=endTime.getSecond();        //秒
        netDvrFilecondV40.struStartTime = startDvrTime;
        netDvrFilecondV40.struStopTime = endDvrTime;
//        netDvrFilecondV40.byAudioFile = 0;
        netDvrFilecondV40.write();
        int i = hCNetSDK.NET_DVR_FindFile_V40(userId, netDvrFilecondV40);
        if (i<-1){
            return null;
        }
        List<RecordFile> recordFiles = new ArrayList<>();
        RecordFile recordFile = null;
        while (true) {
            HCNetSDK.NET_DVR_FINDDATA_V40 netDvrFileDataV40 = new HCNetSDK.NET_DVR_FINDDATA_V40();
            netDvrFileDataV40.read();
            int iRet = hCNetSDK.NET_DVR_FindNextFile_V40(i, netDvrFileDataV40);
            if (iRet == 1000){
                recordFile = new RecordFile();
                recordFile.setFileName(new String(netDvrFileDataV40.sFileName,StandardCharsets.UTF_8));
//                System.out.println(new String(netDvrFileDataV40.sFileName, StandardCharsets.UTF_8));
                recordFile.setStartTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStartTime.toStringTime(),"yyyy/MM/ddHH:mm:ss"));
                recordFile.setStopTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStopTime.toStringTime(),"yyyy/MM/ddHH:mm:ss"));
                recordFile.setFileSize(netDvrFileDataV40.dwFileSize);
                recordFiles.add(recordFile);
            }else if(iRet == 1003) {
                System.out.println("没有更多文件");
                hCNetSDK.NET_DVR_FindClose_V30(i);
                return recordFiles;
            }

        }
    }
    /**
     * 获取nvr的硬盘问题
     * @return
     */
    public Map<String,String> getDevCfg(String ip,int port,String user,String psw) {
        Map<String,String> map = new HashMap<>();
        try {
            HikHdd.HddSummary sum = HikHdd.fetchHddSummaryHttp(ip, port, user, psw);
            map.put("totalTiB", String.format("%.2f", sum.totalTiB())+"TiB");
            map.put("usedTiB",  String.format("%.2f", sum.usedTiB())+"TiB");
            map.put("deviceNumber",String.valueOf(sum.diskCount));
            map.put("noOkCount",String.valueOf(sum.diskCount-sum.okCount));
        } catch (Exception e) {
            log. error("无法访问到{}录像机，网络不可达", ip);
        }
        return map;
    }
    /**
     * 获取通道录像起止时间
     */
    public List<RecordFile> getChannelyRecordTime(int luserId,int channel,LocalDateTime startTime,LocalDateTime endTime){
        long daysBetween = ChronoUnit.DAYS.between(startTime, endTime);
        if(Math.abs(daysBetween) > 90){
            long exceededDays = daysBetween - 90;
            startTime = startTime.plusDays(exceededDays);
        }
        HCNetSDK.NET_DVR_FILECOND_V40 netDvrFilecondV40 = new HCNetSDK.NET_DVR_FILECOND_V40();
        netDvrFilecondV40.read();
        netDvrFilecondV40.lChannel = channel;
        netDvrFilecondV40.dwFileType = 0xff;
        HCNetSDK.NET_DVR_TIME startDvrTime = new HCNetSDK.NET_DVR_TIME();
        startDvrTime.dwYear= startTime.getYear();        //年
        startDvrTime.dwMonth=startTime.getMonthValue();        //月
        startDvrTime.dwDay=startTime.getDayOfMonth();        //日
        startDvrTime.dwHour=startTime.getHour();        //时
        startDvrTime.dwMinute=startTime.getMinute();        //分
        startDvrTime.dwSecond=startTime.getSecond();        //秒
        HCNetSDK.NET_DVR_TIME endDvrTime = new HCNetSDK.NET_DVR_TIME();
        endDvrTime.dwYear= endTime.getYear();        //年
        endDvrTime.dwMonth=endTime.getMonthValue();        //月
        endDvrTime.dwDay=endTime.getDayOfMonth();        //日
        endDvrTime.dwHour=endTime.getHour();        //时
        endDvrTime.dwMinute=endTime.getMinute();        //分
        endDvrTime.dwSecond=endTime.getSecond();        //秒
        netDvrFilecondV40.struStartTime = startDvrTime;
        netDvrFilecondV40.struStopTime = endDvrTime;
        netDvrFilecondV40.write();
        int i = hCNetSDK.NET_DVR_FindFile_V40(luserId, netDvrFilecondV40);
        int i1 = hCNetSDK.NET_DVR_GetLastError();
        if(i == -1){
            log.error("获取分段录像文件失败，海康错误码："+i1);
        }
        List<RecordFile> recordFiles = new ArrayList<>();
        RecordFile recordFile = null;
        try {
            while (true) {
                HCNetSDK.NET_DVR_FINDDATA_V40 netDvrFileDataV40 = new HCNetSDK.NET_DVR_FINDDATA_V40();
                netDvrFileDataV40.read();
                int iRet = hCNetSDK.NET_DVR_FindNextFile_V40(i, netDvrFileDataV40);
                int i2 = hCNetSDK.NET_DVR_GetLastError();
                if(iRet == -1){
                    log.error("获取分段录像文件信息失败，海康错误码：{}", i2);
                    break;
                }
                if (iRet == 1000){
                    recordFile = new RecordFile();
                    recordFile.setStartTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStartTime.toStringTime(),"yyyy/MM/ddHH:mm:ss"));
                    recordFile.setStopTime(DateUtil.parseLocalDateTime(netDvrFileDataV40.struStopTime.toStringTime(),"yyyy/MM/ddHH:mm:ss"));
                    recordFiles.add(recordFile);
                }else if(iRet == 1003) {
                    log.info("已获取全部分段录像文件信息");
                    break;
                }else if(iRet == 1001){
                    log.info("此摄像机在此时间段没有录像");
                    break;
                }else {
                    break;
                }
            }
        }finally {
            hCNetSDK.NET_DVR_FindClose_V30(i);
        }

        return recordFiles;
    }
    public boolean checkCameraThree(int luerId){
        return Hik3DptzChecker.isSupport3DPTZ(hCNetSDK, luerId);
    }
    // 返回最后操作的错误码
    public int getLastError()
    {
        return hCNetSDK.NET_DVR_GetLastError();
    }

    // 定义获取 PTZ 坐标的专用函数
    public Map<String, Integer> NET_DVR_GetPTZPos(int userId, int channelId) {
        HCNetSDK.NET_DVR_PTZPOS ptzPos = new HCNetSDK.NET_DVR_PTZPOS();
        ptzPos.wAction = 1; // 某些老设备要求填1
        ptzPos.write();     // 关键：将 Java 字段的值写入内存 (初始化)

        // 2. 准备返回长度变量
        IntByReference lpBytesReturned = new IntByReference(0);
        boolean result = hCNetSDK.NET_DVR_GetDVRConfig(
                userId,
                HCNetSDK.NET_DVR_GET_PTZPOS, // 命令号 292
                channelId,                   // NVR 通道通常是 33
                ptzPos.getPointer(),                      // 接收数据的结构体
                ptzPos.size(),               // 结构体大小
                lpBytesReturned              // SDK 告诉你实际写了多少字节
        );
        if (!result) {
            System.err.println("获取坐标失败，错误码: " + hCNetSDK.NET_DVR_GetLastError());
            return null; // 或者抛出异常
        }
        ptzPos.read();
        int pan = ptzPos.wPanPos & 0xFFFF;
        int tilt = ptzPos.wTiltPos & 0xFFFF;
        int zoom = ptzPos.wZoomPos & 0xFFFF;
        Map<String, Integer> map = new HashMap<>();
        map.put("pan", pan);
        map.put("tilt", tilt);
        map.put("zoom", zoom);
        return map;
    }
}
