package com.usky.sas.common.dahua;

import cn.hutool.core.util.StrUtil;
import com.usky.sas.common.exception.BusinessException;
import com.usky.sas.common.global.GlobalMemoryMap;
import com.usky.sas.common.hik.OsSelect;
import com.usky.sas.service.impl.SasDeviceServiceImpl;
import com.sun.jna.Callback;
import com.sun.jna.Memory;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class InitNetSDKLib {
    private static final Logger log = LoggerFactory.getLogger(InitNetSDKLib.class);
    static Map<String, DahuaNvrInfo> dhNvrUser;
    public static Map<String, NetSDKLib> dhSDKHashMap;
    public static NetSDKLib dhNetSDK;

    public InitNetSDKLib() {
    }

    private static boolean createSDKInstance() {
        if (dhNetSDK == null) {
            synchronized(NetSDKLib.class) {
                String strDllPath = "";

                try {
                    if (OsSelect.isWindows()) {
                        strDllPath = "D:\\文档和图片\\工作文档\\厂家协议\\海康\\设备网络SDK_JAVA_Win64_IS_V3.060.0000003.0.R.251127\\General_NetSDK_ChnEng_JAVA_Win64_IS_V3.060.0000003.0.R.251127\\libs\\win64\\dhnetsdk.dll";
                    } else if (OsSelect.isLinux()) {
                        strDllPath = "/home/uskycloud_c01/conf/libdhnetsdk.so";
                    }

                    dhNetSDK = (NetSDKLib)Native.loadLibrary(strDllPath, NetSDKLib.class);
                    log.info("初始化NetSDKLib成功============");
                    dhNetSDK.CLIENT_Init((Callback)null, (Pointer)null);
                    dhNetSDK.CLIENT_SetAutoReconnect((Callback)null, (Pointer)null);
                    dhNetSDK.CLIENT_SetConnectTime(10000, 1);
                    dhSDKHashMap.put("dhNetSDK", dhNetSDK);
                    NetSDKLib.LOG_SET_PRINT_INFO setLog = new NetSDKLib.LOG_SET_PRINT_INFO();
                    File path = new File("./dhsdklog/");
                    if (!path.exists()) {
                        path.mkdir();
                    }

                    String logPath = path.getAbsoluteFile().getParent() + "\\dhsdklog\\" + getDate() + ".log";
                    setLog.nPrintStrategy = 0;
                    setLog.bSetFilePath = 1;
                    System.arraycopy(logPath.getBytes(), 0, setLog.szLogFilePath, 0, logPath.getBytes().length);
                    setLog.bSetPrintStrategy = 1;
                    boolean bLogopen = dhNetSDK.CLIENT_LogOpen(setLog);
                    if (!bLogopen) {
                        log.error("打开日志失败");
                    }
                } catch (Exception ex) {
                    log.error("初始化失败，loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }

        return true;
    }

    public static String getDate() {
        SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = simpleDate.format(new Date()).replace(" ", "_").replace(":", "-");
        return date;
    }

    public static Long login(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) {
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstInParam.nPort = m_nPort;
        pstInParam.szIP = m_strIp.getBytes();
        pstInParam.szPassword = m_strPassword.getBytes();
        pstInParam.szUserName = m_strUser.getBytes();
        NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
        Long m_hLoginHandle = dhNetSDK.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        if (m_hLoginHandle == 0L) {
            log.error("设备:{}:{}登录失败，原因：{}", new Object[]{m_strIp, m_nPort, dhNetSDK.CLIENT_GetLastError()});
            throw new BusinessException("请检查设备IP、端口、用户名、密码等配置是否正确！", -1);
        } else {
            log.info("设备:{}:{}登陆成功，句柄：{}", new Object[]{m_strIp, m_nPort, m_hLoginHandle});
            return m_hLoginHandle;
        }
    }

    public static DahuaNvrInfo nvrLogin(String m_strIp, int m_nPort, String m_strUser, String m_strPassword, String mac) {
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstInParam.nPort = m_nPort;
        pstInParam.szIP = m_strIp.getBytes();
        pstInParam.szPassword = m_strPassword.getBytes();
        pstInParam.szUserName = m_strUser.getBytes();
        NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
        Long m_hLoginHandle = dhNetSDK.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        if (m_hLoginHandle == 0L) {
            log.error("设备:{}:{}登录失败，原因：{}", new Object[]{m_strIp, m_nPort, dhNetSDK.CLIENT_GetLastError()});
            throw new BusinessException("请检查设备IP、端口、用户名、密码等配置是否正确！", -1);
        } else {
            log.info("设备:{}:{}登陆成功，句柄：{}", new Object[]{m_strIp, m_nPort, m_hLoginHandle});
            DahuaNvrInfo dahuaNvrInfo = new DahuaNvrInfo();
            dahuaNvrInfo.setLoginHandle(m_hLoginHandle);
            dahuaNvrInfo.setMaxChannelNum(pstOutParam.stuDeviceInfo.byChanNum);
            dhNvrUser.put(mac, dahuaNvrInfo);
            return dahuaNvrInfo;
        }
    }

    public static List<RemoteDeviceInfo> getNvrChannel(String m_strIp, int m_nPort, String m_strUser, String m_strPassword) {
        NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY pstInParam = new NetSDKLib.NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY();
        pstInParam.nPort = m_nPort;
        pstInParam.szIP = m_strIp.getBytes();
        pstInParam.szPassword = m_strPassword.getBytes();
        pstInParam.szUserName = m_strUser.getBytes();
        NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY pstOutParam = new NetSDKLib.NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY();
        Long m_hLoginHandle = dhNetSDK.CLIENT_LoginWithHighLevelSecurity(pstInParam, pstOutParam);
        if (m_hLoginHandle == 0L) {
            log.error("设备:{}:{}登录失败，原因：{}", new Object[]{m_strIp, m_nPort, dhNetSDK.CLIENT_GetLastError()});
            throw new BusinessException("请检查NVR设备IP、端口、用户名、密码等配置是否正确！", -1);
        } else {
            log.info("设备:{}:{}登陆成功，句柄：{}", new Object[]{m_strIp, m_nPort, m_hLoginHandle});
            DahuaNvrInfo dahuaNvrInfo = new DahuaNvrInfo();
            dahuaNvrInfo.setLoginHandle(m_hLoginHandle);
            dahuaNvrInfo.setMaxChannelNum(pstOutParam.stuDeviceInfo.byChanNum);
            dhNvrUser.put(m_strIp, dahuaNvrInfo);
            List<RemoteDeviceInfo> list = new ArrayList();
            int byChanNum = pstOutParam.stuDeviceInfo.byChanNum;
            if (byChanNum != 0) {
                NetSDKLib.NET_MATRIX_CAMERA_INFO[] cameras = new NetSDKLib.NET_MATRIX_CAMERA_INFO[byChanNum];

                for(int i = 0; i < byChanNum; ++i) {
                    NetSDKLib.NET_MATRIX_CAMERA_INFO camera = new NetSDKLib.NET_MATRIX_CAMERA_INFO();
                    NetSDKLib.NET_REMOTE_DEVICE device = new NetSDKLib.NET_REMOTE_DEVICE();
                    camera.stuRemoteDevice = device;
                    cameras[i] = camera;
                }

                NetSDKLib.NET_IN_MATRIX_GET_CAMERAS inMatrixGetCameras = new NetSDKLib.NET_IN_MATRIX_GET_CAMERAS();
                inMatrixGetCameras.dwSize = inMatrixGetCameras.size();
                NetSDKLib.NET_OUT_MATRIX_GET_CAMERAS outMatrixGetCameras = new NetSDKLib.NET_OUT_MATRIX_GET_CAMERAS();
                outMatrixGetCameras.dwSize = outMatrixGetCameras.size();
                outMatrixGetCameras.nMaxCameraCount = byChanNum;
                outMatrixGetCameras.pstuCameras = new Memory((long)(cameras[0].size() * byChanNum));
                outMatrixGetCameras.pstuCameras.clear((long)(cameras[0].size() * byChanNum));
                SetStructArrToPointerData(cameras, outMatrixGetCameras.pstuCameras);
                boolean getCameras = dhNetSDK.CLIENT_MatrixGetCameras(m_hLoginHandle, inMatrixGetCameras, outMatrixGetCameras, 5000);
                if (getCameras) {
                    GetPointerDataToStructArr(outMatrixGetCameras.pstuCameras, cameras);

                    for(int i = 0; i < outMatrixGetCameras.nRetCameraCount; ++i) {
                        int isRemoteDevice = cameras[i].bRemoteDevice;
                        if (isRemoteDevice == 1) {
                            NetSDKLib.NET_REMOTE_DEVICE remoteDevice = cameras[i].stuRemoteDevice;
                            String deviceName = (new String(remoteDevice.szDevName)).trim();
                            String ipAddr = (new String(remoteDevice.szIp)).trim();
                            if (StrUtil.isNotBlank(ipAddr) && !ipAddr.equals("0.0.0.0") && !ipAddr.equals("192.168.0.0") && StrUtil.isNotBlank(deviceName)) {
                                RemoteDeviceInfo info = new RemoteDeviceInfo();
                                info.setChannel(cameras[i].nUniqueChannel + 1);
                                info.setIpAddr(ipAddr);
                                info.setNote(deviceName);
                                list.add(info);
                            }
                        }
                    }
                }
            }

            return list;
        }
    }

    public static Integer getIpcChannel(Long loginHandle, String ipAddr, int byChanNum) {
        if (byChanNum != 0) {
            NetSDKLib.NET_MATRIX_CAMERA_INFO[] cameras = new NetSDKLib.NET_MATRIX_CAMERA_INFO[byChanNum];

            for(int i = 0; i < byChanNum; ++i) {
                NetSDKLib.NET_MATRIX_CAMERA_INFO camera = new NetSDKLib.NET_MATRIX_CAMERA_INFO();
                NetSDKLib.NET_REMOTE_DEVICE device = new NetSDKLib.NET_REMOTE_DEVICE();
                camera.stuRemoteDevice = device;
                cameras[i] = camera;
            }

            NetSDKLib.NET_IN_MATRIX_GET_CAMERAS inMatrixGetCameras = new NetSDKLib.NET_IN_MATRIX_GET_CAMERAS();
            inMatrixGetCameras.dwSize = inMatrixGetCameras.size();
            NetSDKLib.NET_OUT_MATRIX_GET_CAMERAS outMatrixGetCameras = new NetSDKLib.NET_OUT_MATRIX_GET_CAMERAS();
            outMatrixGetCameras.dwSize = outMatrixGetCameras.size();
            outMatrixGetCameras.nMaxCameraCount = byChanNum;
            outMatrixGetCameras.pstuCameras = new Memory((long)(cameras[0].size() * byChanNum));
            outMatrixGetCameras.pstuCameras.clear((long)(cameras[0].size() * byChanNum));
            SetStructArrToPointerData(cameras, outMatrixGetCameras.pstuCameras);
            boolean getCameras = dhNetSDK.CLIENT_MatrixGetCameras(loginHandle, inMatrixGetCameras, outMatrixGetCameras, 5000);
            if (getCameras) {
                GetPointerDataToStructArr(outMatrixGetCameras.pstuCameras, cameras);

                for(int i = 0; i < outMatrixGetCameras.nRetCameraCount; ++i) {
                    int isRemoteDevice = cameras[i].bRemoteDevice;
                    if (isRemoteDevice == 1) {
                        NetSDKLib.NET_REMOTE_DEVICE remoteDevice = cameras[i].stuRemoteDevice;
                        String ip = (new String(remoteDevice.szIp)).trim();
                        if (ip.equals(ipAddr)) {
                            return cameras[i].nUniqueChannel;
                        }
                    }
                }
            }
        }

        return null;
    }

    public static void SetStructArrToPointerData(Structure[] pJavaStuArr, Pointer pNativeData) {
        long offset = 0L;

        for(int i = 0; i < pJavaStuArr.length; ++i) {
            SasDeviceServiceImpl.SetStructDataToPointer(pJavaStuArr[i], pNativeData, offset);
            offset += (long)pJavaStuArr[i].size();
        }

    }

    public static void GetPointerDataToStruct(Pointer pNativeData, long OffsetOfpNativeData, Structure pJavaStu) {
        pJavaStu.write();
        Pointer pJavaMem = pJavaStu.getPointer();
        pJavaMem.write(0L, pNativeData.getByteArray(OffsetOfpNativeData, pJavaStu.size()), 0, pJavaStu.size());
        pJavaStu.read();
    }

    public static void GetPointerDataToStructArr(Pointer pNativeData, Structure[] pJavaStuArr) {
        long offset = 0L;

        for(int i = 0; i < pJavaStuArr.length; ++i) {
            GetPointerDataToStruct(pNativeData, offset, pJavaStuArr[i]);
            offset += (long)pJavaStuArr[i].size();
        }

    }

    static {
        dhNvrUser = GlobalMemoryMap.dhNvrUser;
        dhSDKHashMap = new ConcurrentHashMap();
        dhNetSDK = (NetSDKLib)dhSDKHashMap.get("dhNetSDK");
        createSDKInstance();
    }
}
