package com.usky.sas.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.sas.common.UnityVideoInfo;
import com.usky.sas.common.enums.ProtocolEnum;
import com.usky.sas.common.enums.SystemTypeCodeEnum;
import com.usky.sas.common.exception.BusinessException;
import com.usky.sas.common.util.ZLMediaKitUtils;
import com.usky.sas.common.dahua.DahuaVideoStreamService;
import com.usky.sas.common.entity.DeviceVideoInfo;
import com.usky.sas.common.entity.DahuaNvrInfo;
import com.usky.sas.common.enums.DeviceTypeEnum;
import com.usky.sas.mqtt.MqttService;
//import com.usky.sas.common.hik.HCNetSDK;
//import com.usky.sas.common.hik.InitHCNetSDK;
//import com.usky.sas.common.hik.VideoResolutionUtils;
//import com.usky.sas.common.hik.HikVideoStreamService;
//import com.usky.sas.common.dahua.InitNetSDKLib;
import com.usky.sas.common.util.GetIpUtils;
import com.usky.sas.common.onvif.StandardOnvifService;
import com.usky.sas.domain.*;
import com.usky.sas.mapper.*;
import com.usky.sas.mqtt.MqttService;
import com.usky.sas.service.SasHomepageService;
import com.usky.sas.service.SasIntelligentService;
import com.usky.sas.service.vo.EventDetailResponse;
import com.usky.sas.service.vo.HomepageAlertHistoryRequest;
import com.usky.sas.service.vo.HomepageInfoResponse;
import com.usky.sas.service.vo.IntelligentEventItem;
import com.usky.sas.service.vo.IntelligentEventPageRequest;
import com.usky.sas.service.vo.SystemResourceResponse;
import com.usky.sas.service.vo.VideoStreamVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.File;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

@Service
public class SasHomepageServiceImpl implements SasHomepageService {

    @Autowired
    private ZLMediaKitUtils zlMediaKitUtils;

    @Value("${media-kit.port:10000}")
    private Integer mediaPort;

    @Value("${media-kit.http.port:80}")
    private Integer mediaHttpPort;

    @Value("${media-kit.secret:secret}")
    private String mediaKitSecret;

    private Map<String, UnityVideoInfo> unityVideoInfo = new ConcurrentHashMap<>();
    private Map<String, DeviceVideoInfo> hikVideoInfo = new ConcurrentHashMap<>();
    private Map<String, Integer> loginHikNvrUser = new ConcurrentHashMap<>();
    private Map<String, DahuaNvrInfo> dhNvrUser = new ConcurrentHashMap<>();

    private long globalSsrc = 0;

    @Autowired
    private StandardOnvifService standardOnvifService;

    @Autowired
    private SasDeviceMapper sasDeviceMapper;

    @Autowired
    private SasCollectionEventMapper sasCollectionEventMapper;

    @Autowired
    private SasSnapEventMapper sasSnapEventMapper;

    @Autowired
    private SasIntelligentService sasIntelligentService;

    @Autowired
    private SasConfigMapper sasConfigMapper;

    @Autowired
    private SasUsbEventMapper sasUsbEventMapper;

    @Autowired
    private SasEntranceEventMapper sasEntranceEventMapper;

    @Autowired
    private SasParkingEventMapper sasParkingEventMapper;

    @Autowired
    private SasAlarsasEventMapper sasAlarsasEventMapper;

    @Autowired
    private SasPatrolEventMapper sasPatrolEventMapper;

    @Autowired
    private SasPerceptionEventMapper sasPerceptionEventMapper;

    @Autowired
    private SasAcquisitionEventMapper sasAcquisitionEventMapper;

    @Autowired
    private SasRoadblockEventMapper sasRoadblockEventMapper;

    @Autowired
    private SasPersonMapper sasPersonMapper;

    @Autowired
    private SasCredentialTypeCodeMapper sasCredentialTypeCodeMapper;

    @Autowired
    private SasSystemConfigMapper sasSystemConfigMapper;

    @Autowired
    private SasGisMapper sasGisMapper;

    @Autowired
    private SasPicMapper sasPicMapper;

    @Autowired
    private SasSnapTypeCodeMapper sasSnapTypeCodeMapper;

    @Autowired
    private SasUsbEventCodeMapper sasUsbEventCodeMapper;

    @Autowired
    private SasEntranceEventCodeMapper sasEntranceEventCodeMapper;

    @Autowired
    private SasPeopleTypeCodeMapper sasPeopleTypeCodeMapper;

    @Autowired
    private SasCarTypeCodeMapper sasCarTypeCodeMapper;

    @Autowired
    private SasPlateTypeCodeMapper sasPlateTypeCodeMapper;

    @Autowired
    private SasParkingEventCodeMapper sasParkingEventCodeMapper;

    @Autowired
    private SasPlateColorMapper sasPlateColorMapper;

    @Autowired
    private SasAlarsasEventCodeMapper sasAlarsasEventCodeMapper;

    @Autowired
    private SasPatrolEventCodeMapper sasPatrolEventCodeMapper;

    @Autowired
    private SasPerceptionEventCodeMapper sasPerceptionEventCodeMapper;

    @Autowired
    private SasAcquisitionEventCodeMapper sasAcquisitionEventCodeMapper;

    @Autowired
    private SasCollectionEventCodeMapper sasCollectionEventCodeMapper;

    @Autowired
    private SasRoadblockEventCodeMapper sasRoadblockEventCodeMapper;

    @Autowired
    private MqttService mqttService;

    @Override
    public HomepageInfoResponse getHomepageInfo(String ipAddr) {
        List<SasDevice> devices = sasDeviceMapper.selectList(new LambdaQueryWrapper<SasDevice>().eq(SasDevice::getDeviceType, SystemTypeCodeEnum.video.getCode()).like(StrUtil.isNotBlank(ipAddr), SasDevice::getIpAddr, ipAddr));

        HomepageInfoResponse resp = new HomepageInfoResponse();
        resp.setCameras(devices.stream().map(this::toCameraItem).collect(Collectors.toList()));

        HomepageInfoResponse.Statistics stat = new HomepageInfoResponse.Statistics();
        stat.setTotalDevices((long) devices.size());
        stat.setOnlineDevices(devices.stream().filter(this::isOnline).count());

        LocalDateTime startOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
        LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);

        LambdaQueryWrapper<SasCollectionEvent> wrapper = Wrappers.lambdaQuery();
        wrapper.between(SasCollectionEvent::getTriggerTime, startOfDay, endOfDay);

        long todayEvents = sasCollectionEventMapper.selectCount(wrapper);
        stat.setTodayEvents(todayEvents);
        // 暂无单独报警事件表，这里先与今日事件数保持一致
        stat.setAlarmEvents(todayEvents);

        resp.setStatistics(stat);
        return resp;
    }

    private String toHexString(long ssrc) {
        return Long.toHexString(ssrc);
    }

    @Override
    public String getUnityVideoStream(String id, String deviceId, Integer channel, Integer deviceType) {
        SasDevice device = null;
        if (StrUtil.isNotBlank(id)) {
            device = sasDeviceMapper.selectById(id);
        } else {
            LambdaQueryWrapper<SasDevice> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(SasDevice::getDeviceId, deviceId);
            if (channel != null) {
                wrapper.eq(SasDevice::getChannel, channel);
            }
            if (deviceType != null) {
                wrapper.eq(SasDevice::getDeviceType, deviceType);
            }
            
            SasDevice eventDevice = sasDeviceMapper.selectOne(wrapper);
            if (eventDevice != null) {
                if (StrUtil.isNotBlank(eventDevice.getBindingIpc())) {
                    device = sasDeviceMapper.selectById(eventDevice.getBindingIpc());
                } else if (StrUtil.isNotBlank(eventDevice.getAlarsasGroupType())) {
                    List<SasDevice> deviceList = sasDeviceMapper.selectList(new LambdaQueryWrapper<SasDevice>()
                            .eq(SasDevice::getAlarsasGroupType, eventDevice.getAlarsasGroupType())
                            .eq(SasDevice::getDeviceType, SystemTypeCodeEnum.video.getCode()));
                    if (CollUtil.isNotEmpty(deviceList)) {
                        device = deviceList.get(0);
                    }
                }
            }
        }

        if (device == null) {
            return null;
        } else {
            Integer protocol = device.getVideoProtocol();
            if (protocol.equals(ProtocolEnum.ONVIF.getCode())) {
                UnityVideoInfo info = null;
                info = (UnityVideoInfo)this.unityVideoInfo.get(device.getDeviceId() + device.getDeviceType() + device.getChannel());
                if (info != null) {
                    boolean isExist = this.zlMediaKitUtils.streamIsExist(GetIpUtils.getServerIP(), this.mediaHttpPort, this.mediaKitSecret, info.getSsrc());
                    if (isExist) {
                        return info.getUrl();
                    }
                }

                String rtspUri = null;
                if (device.getVideoType().equals(DeviceTypeEnum.NVR.getCode())) {
                    rtspUri = this.standardOnvifService.getNvrRealTimeStreamUrl(device.getIpAddr(), device.getUsername(), device.getPassword(), device.getVideoSourceToken());
                } else {
                    rtspUri = this.standardOnvifService.getRealTimeStreamUrl(device.getIpAddr(), device.getUsername(), device.getPassword());
                }

                this.globalSsrc = this.globalSsrc >= 4294967295L ? 65535L : this.globalSsrc + 1L;
                String key = this.zlMediaKitUtils.addStreamProxy(this.mediaKitSecret, toHexString(this.globalSsrc), rtspUri, device.getUsername(), device.getPassword());
                UnityVideoInfo onvifVideoInfo = new UnityVideoInfo();
                onvifVideoInfo.setMacAddr(device.getDeviceId() + device.getChannel() + device.getDeviceType());
                onvifVideoInfo.setKey(key);
                onvifVideoInfo.setSsrc(toHexString(this.globalSsrc));
                onvifVideoInfo.setUrl("http://" + GetIpUtils.getServerIP() + ":" + this.mediaHttpPort + "/index/api/webrtc?app=rtp&stream=" + toHexString(this.globalSsrc) + "&type=play");
                this.unityVideoInfo.put(device.getDeviceId() + device.getChannel() + device.getDeviceType(), onvifVideoInfo);
                return "http://" + GetIpUtils.getServerIP() + ":" + this.mediaHttpPort + "/index/api/webrtc?app=rtp&stream=" + toHexString(this.globalSsrc) + "&type=play";
            } else if (protocol.equals(ProtocolEnum.HIK.getCode())) {
                UnityVideoInfo info = null;
                info = (UnityVideoInfo)this.unityVideoInfo.get(device.getDeviceId() + device.getDeviceType() + device.getChannel());
                if (info != null) {
                    boolean isExist = this.zlMediaKitUtils.streamIsExist(GetIpUtils.getServerIP(), this.mediaHttpPort, this.mediaKitSecret, info.getSsrc());
                    if (isExist) {
                        return info.getUrl();
                    }
                }

                this.globalSsrc = this.globalSsrc >= 4294967295L ? 65535L : this.globalSsrc + 1L;
                String rtspUrl = null;
                if (DeviceTypeEnum.IPC.getCode().equals(device.getDeviceType())) {
                    rtspUrl = String.format("rtsp://%s:%s@%s:554/Streaming/Channels/%d", device.getUsername(), device.getPassword(), device.getIpAddr(), device.getChannel());
                } else {
                    rtspUrl = String.format("rtsp://%s:%s@%s:554/Streaming/Channels/%d", device.getUsername(), device.getPassword(), device.getIpAddr(), device.getChannel() * 100 + 1);
                }

                String key = this.zlMediaKitUtils.addStreamUnityProxy(this.mediaKitSecret, toHexString(this.globalSsrc), rtspUrl);
                UnityVideoInfo hikVideoInfo = new UnityVideoInfo();
                hikVideoInfo.setUrl("http://" + GetIpUtils.getServerIP() + ":" + this.mediaHttpPort + "/index/api/webrtc?app=rtp&stream=" + toHexString(this.globalSsrc) + "&type=play");
                hikVideoInfo.setSsrc(toHexString(this.globalSsrc));
                hikVideoInfo.setMacAddr(device.getDeviceId() + device.getDeviceType() + device.getChannel());
                hikVideoInfo.setKey(key);
                this.unityVideoInfo.put(device.getDeviceId() + device.getDeviceType() + device.getChannel(), hikVideoInfo);
                return "http://" + GetIpUtils.getServerIP() + ":" + this.mediaHttpPort + "/index/api/webrtc?app=rtp&stream=" + toHexString(this.globalSsrc) + "&type=play";
            } else if (protocol.equals(ProtocolEnum.DA_HUA.getCode())) {
                UnityVideoInfo info = null;
                info = (UnityVideoInfo)this.unityVideoInfo.get(device.getDeviceId() + device.getDeviceType() + device.getChannel());
                if (info != null) {
                    boolean isExist = this.zlMediaKitUtils.streamIsExist(GetIpUtils.getServerIP(), this.mediaHttpPort, this.mediaKitSecret, info.getSsrc());
                    if (isExist) {
                        return info.getUrl();
                    }
                }

                this.globalSsrc = this.globalSsrc >= 4294967295L ? 65535L : this.globalSsrc + 1L;
                String rtspUrl = String.format("rtsp://%s:%s@%s:554/cam/realmonitor?channel=%d&subtype=0", device.getUsername(), device.getPassword(), device.getIpAddr(), device.getChannel());
                String key = this.zlMediaKitUtils.addStreamUnityProxy(this.mediaKitSecret, toHexString(this.globalSsrc), rtspUrl);
                UnityVideoInfo dahuaVideoInfo = new UnityVideoInfo();
                dahuaVideoInfo.setUrl("http://" + GetIpUtils.getServerIP() + ":" + this.mediaHttpPort + "/index/api/webrtc?app=rtp&stream=" + toHexString(this.globalSsrc) + "&type=play");
                dahuaVideoInfo.setSsrc(toHexString(this.globalSsrc));
                dahuaVideoInfo.setMacAddr(device.getDeviceId() + device.getDeviceType() + device.getChannel());
                dahuaVideoInfo.setKey(key);
                this.unityVideoInfo.put(device.getDeviceId() + device.getDeviceType() + device.getChannel(), dahuaVideoInfo);
                return "http://" + GetIpUtils.getServerIP() + ":" + this.mediaHttpPort + "/index/api/webrtc?app=rtp&stream=" + toHexString(this.globalSsrc) + "&type=play";
            } else {
                return null;
            }
        }
    }

//    @Override
//    public VideoStreamVo getUnityVideoBackStream(String id, String beginTime, String endTime, Integer handle, String oldMac) {
//        Date begin = DateUtil.parse(beginTime, "yyyy-MM-dd HH:mm:ss");
//        Date end = DateUtil.parse(endTime, "yyyy-MM-dd HH:mm:ss");
//        VideoStreamVo streamVo = null;
//        SasDevice device = null;
//        if (StrUtil.isNotBlank(id)) {
//            device = sasDeviceMapper.selectById(id);
//        }
//
//        if (device == null) {
//            return null;
//        } else if (device.getVideoProtocol().equals(ProtocolEnum.ONVIF.getCode())) {
//            return null;
//        } else {
//            if (device.getVideoProtocol().equals(ProtocolEnum.HIK.getCode())) {
//                Integer userId = null;
//                int bitrate = 0;
//                DeviceVideoInfo deviceVideoInfo = (DeviceVideoInfo)this.hikVideoInfo.get(device.getDeviceId() + device.getDeviceType() + device.getChannel());
//                if (deviceVideoInfo != null) {
//                    userId = deviceVideoInfo.getUserId();
//                } else if (device.getVideoType().equals(DeviceTypeEnum.NVR.getCode())) {
//                    userId = InitHCNetSDK.loginDevice(device.getRemoteIpcIpAddr(), device.getPort().shortValue(), device.getUsername(), device.getPassword());
//                    HCNetSDK.NET_DVR_MULTI_STREAM_COMPRESSIONCFG config = VideoResolutionUtils.getCompressionConfig(userId, 1, 0);
//                    bitrate = config.struStreamPara.dwVideoBitrate;
//                } else {
//                    userId = InitHCNetSDK.loginDevice(device.getIpAddr(), device.getPort().shortValue(), device.getUsername(), device.getPassword());
//                    HCNetSDK.NET_DVR_MULTI_STREAM_COMPRESSIONCFG config = VideoResolutionUtils.getCompressionConfig(userId, device.getChannel(), 0);
//                    bitrate = config.struStreamPara.dwVideoBitrate;
//                }
//
//                List<SasDevice> nvrDevices = sasDeviceMapper.selectList(new LambdaQueryWrapper<SasDevice>().eq(SasDevice::getVideoType, DeviceTypeEnum.NVR.getCode()));
//                Integer channel = null;
//                Integer loginNvr = null;
//                String macAddr = null;
//                if (CollUtil.isNotEmpty(nvrDevices)) {
//                    List<SasDevice> collect = nvrDevices.stream().filter((device1) -> this.loginHikNvrUser.containsKey(device1.getDeviceId() + device1.getDeviceType() + device1.getChannel())).collect(Collectors.toList());
//                    if (CollUtil.isNotEmpty(collect)) {
//                        for(SasDevice d : collect) {
//                            macAddr = d.getDeviceId() + d.getDeviceType() + d.getChannel();
//                            loginNvr = (Integer)this.loginHikNvrUser.get(macAddr);
//                            if (device.getVideoType().equals(DeviceTypeEnum.NVR.getCode())) {
//                                channel = InitHCNetSDK.getIPChannelInfo(loginNvr, device.getRemoteIpcIpAddr());
//                            } else {
//                                channel = InitHCNetSDK.getIPChannelInfo(loginNvr, device.getIpAddr());
//                            }
//
//                            if (channel != null) {
//                                break;
//                            }
//                        }
//                    } else {
//                        for(SasDevice nvrDevice : nvrDevices) {
//                            loginNvr = InitHCNetSDK.loginDevice(nvrDevice.getIpAddr(), nvrDevice.getPort().shortValue(), nvrDevice.getUsername(), nvrDevice.getPassword());
//                            if (loginNvr >= 0) {
//                                macAddr = nvrDevice.getDeviceId() + nvrDevice.getDeviceType() + nvrDevice.getChannel();
//                                this.loginHikNvrUser.put(macAddr, loginNvr);
//                                if (device.getVideoType().equals(DeviceTypeEnum.NVR.getCode())) {
//                                    channel = InitHCNetSDK.getIPChannelInfo(loginNvr, device.getRemoteIpcIpAddr());
//                                } else {
//                                    channel = InitHCNetSDK.getIPChannelInfo(loginNvr, device.getIpAddr());
//                                }
//
//                                if (channel != null) {
//                                    break;
//                                }
//                            }
//                        }
//                    }
//                }
//
//                if (channel == null) {
//                    throw new BusinessException("回放失败，NVR未找到当前设备回放", -1);
//                }
//
//                streamVo = HikVideoStreamService.playBackByTime(oldMac, macAddr, bitrate, loginNvr, channel, this.mediaPort, this.mediaHttpPort, begin, end);
//            }
//
//            if (!device.getVideoProtocol().equals(ProtocolEnum.DA_HUA.getCode())) {
//                return streamVo;
//            } else {
//                Integer ipcChannel = null;
//                List<SasDevice> nvrList = sasDeviceMapper.selectList(new LambdaQueryWrapper<SasDevice>().eq(SasDevice::getVideoProtocol, ProtocolEnum.DA_HUA.getCode()).eq(SasDevice::getVideoType, DeviceTypeEnum.NVR.getCode()));
//                if (CollUtil.isNotEmpty(nvrList)) {
//                    for(SasDevice nvrDevice : nvrList) {
//                        DahuaNvrInfo dahuaNvrInfo = (DahuaNvrInfo)this.dhNvrUser.get(nvrDevice.getDeviceId() + nvrDevice.getDeviceType() + nvrDevice.getChannel());
//                        if (dahuaNvrInfo != null) {
//                            if (device.getVideoType().equals(DeviceTypeEnum.NVR.getCode())) {
//                                ipcChannel = InitNetSDKLib.getIpcChannel(dahuaNvrInfo.getLoginHandle(), device.getRemoteIpcIpAddr(), dahuaNvrInfo.getMaxChannelNum());
//                            } else {
//                                ipcChannel = InitNetSDKLib.getIpcChannel(dahuaNvrInfo.getLoginHandle(), device.getIpAddr(), dahuaNvrInfo.getMaxChannelNum());
//                            }
//
//                            if (ipcChannel != null) {
//                                streamVo = DahuaVideoStreamService.playBackByTime(oldMac, device.getDeviceId() + device.getDeviceType() + device.getChannel(), dahuaNvrInfo.getLoginHandle(), ipcChannel, this.mediaPort, this.mediaHttpPort, begin, end);
//                                return streamVo;
//                            }
//                        } else {
//                            DahuaNvrInfo nvrLogin = InitNetSDKLib.nvrLogin(nvrDevice.getIpAddr(), nvrDevice.getPort(), nvrDevice.getUsername(), nvrDevice.getPassword(), nvrDevice.getDeviceId() + nvrDevice.getDeviceType() + nvrDevice.getChannel());
//                            if (device.getVideoType().equals(DeviceTypeEnum.NVR.getCode())) {
//                                ipcChannel = InitNetSDKLib.getIpcChannel(nvrLogin.getLoginHandle(), device.getRemoteIpcIpAddr(), nvrLogin.getMaxChannelNum());
//                            } else {
//                                ipcChannel = InitNetSDKLib.getIpcChannel(nvrLogin.getLoginHandle(), device.getIpAddr(), nvrLogin.getMaxChannelNum());
//                            }
//
//                            if (ipcChannel != null) {
//                                streamVo = DahuaVideoStreamService.playBackByTime(oldMac, device.getDeviceId() + device.getChannel() + device.getDeviceType(), nvrLogin.getLoginHandle(), ipcChannel, this.mediaPort, this.mediaHttpPort, begin, end);
//                                return streamVo;
//                            }
//                        }
//                    }
//                }
//
//                throw new BusinessException("回放失败：未找到大华NVR设备", -1);
//            }
//        }
//    }

    @Override
    public EventDetailResponse getEventDetail(String deviceType, String eventId) {
        if (StrUtil.isBlank(deviceType) || StrUtil.isBlank(eventId)) {
            return null;
        }

        switch (deviceType) {
            case "1001":
                return getSnapEventDetail(eventId);
            case "1003":
                return getUsbEventDetail(eventId);
            case "1005":
                return getEntranceEventDetail(eventId);
            case "1006":
                return getParkingEventDetail(eventId);
            case "1007":
                return getAlarmEventDetail(eventId);
            case "1008":
                return getPatrolEventDetail(eventId);
            case "1009":
                return getPerceptionEventDetail(eventId);
            case "1010":
                return getAcquisitionEventDetail(eventId);
            case "1011":
                return getCollectionEventDetail(eventId);
            case "1012":
                return getRoadblockEventDetail(eventId);
            default:
                return null;
        }
    }

    private EventDetailResponse getSnapEventDetail(String eventId) {
        SasSnapEvent event = sasSnapEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);

        SasPerson person = sasPersonMapper.selectById(event.getPersonCode());
        if (person != null) {
            SasSystemConfig systemConfig = sasSystemConfigMapper.selectOne(new LambdaQueryWrapper<SasSystemConfig>().last("limit 1"));
            SasCredentialTypeCode credentialTypeCode = sasCredentialTypeCodeMapper.selectById(person.getCredentialType());
            if (credentialTypeCode != null) {
                infoDetail.setCredentialType(credentialTypeCode.getName());
            }

            if (systemConfig != null && !Boolean.TRUE.equals(systemConfig.getMaskIdCardNo())) {
                infoDetail.setCredentialNo(person.getCredentialNo());
            }

            infoDetail.setName(person.getName());
        }

        setGisInfo(infoDetail, event.getGisId());
        infoDetail.setCreateTime(event.getCreateTime());
        setPicInfo(infoDetail, event.getEventPicId(), true);
        setPicInfo(infoDetail, event.getScenePicId(), false);

        SasSnapTypeCode code = sasSnapTypeCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.snap.getCode(), event.getNote());

        infoDetail.setDeviceType(SystemTypeCodeEnum.snap.getCode());
        return infoDetail;
    }

    private EventDetailResponse getUsbEventDetail(String eventId) {
        SasUsbEvent event = sasUsbEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());

        SasUsbEventCode code = sasUsbEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.usb.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.usb.getCode());
        return infoDetail;
    }

    private EventDetailResponse getEntranceEventDetail(String eventId) {
        SasEntranceEvent event = sasEntranceEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());

        SasCredentialTypeCode credentialTypeCode = sasCredentialTypeCodeMapper.selectById(event.getCertifiedType());
        if (credentialTypeCode != null) {
            infoDetail.setCertifiedTypeName(credentialTypeCode.getName());
        }

        SasSystemConfig systemConfig = sasSystemConfigMapper.selectOne(new LambdaQueryWrapper<SasSystemConfig>().last("limit 1"));
        if (systemConfig != null && !Boolean.TRUE.equals(systemConfig.getMaskIdCardNo())) {
            String masked = event.getCertifiedNo();
            if (StrUtil.isNotBlank(masked) && masked.length() > 8) {
                masked = IdcardUtil.hide(masked, 4, masked.length() - 4);
            }
            infoDetail.setCertifiedNo(masked);
        }

        setPicInfo(infoDetail, event.getPicId(), true);

        if (event.getEventCode() != null) {
            if (event.getEventCode() % 10 == 0) {
                SasEntranceEventCode code = sasEntranceEventCodeMapper.selectById(event.getEventCode());
                if (code != null) {
                    infoDetail.setEventCode(String.valueOf(code.getCode()));
                    infoDetail.setEventTypeName(code.getName());
                }
            } else if (event.getEventCode() % 10 == 1) {
                SasPeopleTypeCode code = sasPeopleTypeCodeMapper.selectById((event.getEventCode() - 1) / 10);
                if (code != null) {
                    infoDetail.setEventCode(String.valueOf(code.getCode()));
                    infoDetail.setEventTypeName(code.getName() + "进");
                }
            } else if (event.getEventCode() % 10 == 2) {
                SasPeopleTypeCode code = sasPeopleTypeCodeMapper.selectById((event.getEventCode() - 2) / 10);
                if (code != null) {
                    infoDetail.setEventCode(code.getCode());
                    infoDetail.setEventTypeName(code.getName() + "出");
                }
            }
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.entrance.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.entrance.getCode());
        return infoDetail;
    }

    private EventDetailResponse getParkingEventDetail(String eventId) {
        SasParkingEvent event = sasParkingEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());

        setGisInfo(infoDetail, event.getGisId());

        SasCarTypeCode carType = sasCarTypeCodeMapper.selectById(event.getCarType());
        if (carType != null) {
            infoDetail.setCarType(carType.getName());
        }

        SasPlateTypeCode plateTypeCode = sasPlateTypeCodeMapper.selectById(event.getPlateType());
        if (plateTypeCode != null) {
            infoDetail.setPlateType(plateTypeCode.getName());
        }

        setPicInfo(infoDetail, event.getEventPicId(), true);
        setPicInfo(infoDetail, event.getPlatePicId(), false);

        SasParkingEventCode code = sasParkingEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        SasPlateColor plateColor = sasPlateColorMapper.selectById(event.getPlateColor());
        if (plateColor != null) {
            infoDetail.setPlateColor(plateColor.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.parking.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.parking.getCode());
        return infoDetail;
    }

    private EventDetailResponse getAlarmEventDetail(String eventId) {
        SasAlarsasEvent event = sasAlarsasEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());
        setGisInfo(infoDetail, event.getGisId());
        setPicInfo(infoDetail, event.getPicId(), true);

        SasAlarsasEventCode code = sasAlarsasEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.alarm.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.alarm.getCode());
        return infoDetail;
    }

    private EventDetailResponse getPatrolEventDetail(String eventId) {
        SasPatrolEvent event = sasPatrolEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());
        setGisInfo(infoDetail, event.getGisId());
        setPicInfo(infoDetail, event.getPicId(), true);

        SasCredentialTypeCode credentialTypeCode = sasCredentialTypeCodeMapper.selectById(event.getCredentialType());
        if (credentialTypeCode != null) {
            infoDetail.setCredentialType(credentialTypeCode.getName());
        }

        SasSystemConfig systemConfig = sasSystemConfigMapper.selectOne(new LambdaQueryWrapper<SasSystemConfig>().last("limit 1"));
        if (systemConfig != null && !Boolean.TRUE.equals(systemConfig.getMaskIdCardNo())) {
            String masked = event.getCredentialNo();
            if (StrUtil.isNotBlank(masked) && masked.length() > 8) {
                masked = IdcardUtil.hide(masked, 4, masked.length() - 4);
            }
            infoDetail.setCredentialNo(masked);
        }

        SasPatrolEventCode code = sasPatrolEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.patrol.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.patrol.getCode());
        return infoDetail;
    }

    private EventDetailResponse getPerceptionEventDetail(String eventId) {
        SasPerceptionEvent event = sasPerceptionEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());
        setGisInfo(infoDetail, event.getGisId());
        setPicInfo(infoDetail, event.getPicId(), true);

        SasPerceptionEventCode code = sasPerceptionEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.perception.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.perception.getCode());
        return infoDetail;
    }

    private EventDetailResponse getAcquisitionEventDetail(String eventId) {
        SasAcquisitionEvent event = sasAcquisitionEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());
        setGisInfo(infoDetail, event.getGisId());
        setPicInfo(infoDetail, event.getPicId(), true);

        SasAcquisitionEventCode code = sasAcquisitionEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        infoDetail.setDeviceType(SystemTypeCodeEnum.acquisition.getCode());
        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.acquisition.getCode(), event.getNote());
        return infoDetail;
    }

    private EventDetailResponse getCollectionEventDetail(String eventId) {
        SasCollectionEvent event = sasCollectionEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());
        setGisInfo(infoDetail, event.getGisId());
        setPicInfo(infoDetail, event.getPicId(), true);
        setPicInfo(infoDetail, event.getScenePicId(), false);

        SasCollectionEventCode code = sasCollectionEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.collection.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.collection.getCode());
        return infoDetail;
    }

    private EventDetailResponse getRoadblockEventDetail(String eventId) {
        SasRoadblockEvent event = sasRoadblockEventMapper.selectById(eventId);
        if (event == null) return null;

        EventDetailResponse infoDetail = new EventDetailResponse();
        BeanUtil.copyProperties(event, infoDetail);
        infoDetail.setCreateTime(event.getCreateTime());
        setGisInfo(infoDetail, event.getGisId());
        setPicInfo(infoDetail, event.getPicId(), true);

        SasRoadblockEventCode code = sasRoadblockEventCodeMapper.selectById(event.getEventCode());
        if (code != null) {
            infoDetail.setEventTypeName(code.getName());
        }

        setDeviceInfo(infoDetail, event.getDeviceId(), event.getChannel(), SystemTypeCodeEnum.roadblock.getCode(), event.getNote());
        infoDetail.setDeviceType(SystemTypeCodeEnum.roadblock.getCode());
        return infoDetail;
    }

    private void setGisInfo(EventDetailResponse infoDetail, String gisId) {
        if (StrUtil.isBlank(gisId)) return;
        SasGis gis = sasGisMapper.selectById(gisId);
        if (gis != null) {
            EventDetailResponse.GisInfo gisInfo = new EventDetailResponse.GisInfo();
            BeanUtil.copyProperties(gis, gisInfo);
            infoDetail.setGisInfo(gisInfo);
        }
    }

    private void setPicInfo(EventDetailResponse infoDetail, String picId, boolean isEventUrl) {
        if (StrUtil.isBlank(picId)) return;
        SasPic pic = sasPicMapper.selectById(picId);
        if (pic != null && StrUtil.isNotBlank(pic.getUrl()) && StrUtil.isNotBlank(pic.getPath())) {
            if (isEventUrl) {
                infoDetail.setEventUrl(pic.getUrl() + pic.getPath());
            } else {
                infoDetail.setSceneUrl(pic.getUrl() + pic.getPath());
            }
        }
    }

    private void setDeviceInfo(EventDetailResponse infoDetail, String deviceId, Integer channel, Integer deviceType, String note) {
        LambdaQueryWrapper<SasDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SasDevice::getDeviceId, deviceId);
        if (channel != null) {
            wrapper.eq(SasDevice::getChannel, channel);
        }
        if (deviceType != null) {
            wrapper.eq(SasDevice::getDeviceType, deviceType);
        }
        
        SasDevice device = sasDeviceMapper.selectOne(wrapper);
        if (device != null) {
            if (StrUtil.isBlank(note)) {
                infoDetail.setNote(device.getNote());
            }
            infoDetail.setAddress(device.getAddress());
        }
    }

    private HomepageInfoResponse.CameraItem toCameraItem(SasDevice d) {
        HomepageInfoResponse.CameraItem c = new HomepageInfoResponse.CameraItem();
        c.setId(d.getId());
        c.setName(d.getDeviceId());
        c.setIpAddr(d.getIpAddr());
        c.setStatus(isOnline(d) ? "online" : "offline");
        if (d.getIpAddr() != null) {
            c.setLiveUrl("rtsp://" + d.getIpAddr() + ":554/stream");
        }
        c.setPlaybackUrl("http://192.168.10.151/playback");
        return c;
    }

    private boolean isOnline(SasDevice d) {
        if (d.getTriggerTime() == null) {
            return false;
        }
        long seconds = ChronoUnit.SECONDS.between(d.getTriggerTime(), LocalDateTime.now());
        return seconds <= 60;
    }

    @Override
    public CommonPage<IntelligentEventItem> getEventList(IntelligentEventPageRequest request) {
        return sasIntelligentService.queryEvents(request);
    }

    @Override
    public List<IntelligentEventItem> getRealtimeNotificationEvents() {
        LambdaQueryWrapper<SasSnapEvent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SasSnapEvent::getNotify, true);
        wrapper.orderByDesc(SasSnapEvent::getTriggerTime);
        wrapper.last("LIMIT 20");
        List<SasSnapEvent> list = sasSnapEventMapper.selectList(wrapper);
        if (list == null) {
            return Collections.emptyList();
        }
        return list.stream().map(this::snapToEventItem).collect(Collectors.toList());
    }

    @Override
    public CommonPage<IntelligentEventItem> getAlertHistory(HomepageAlertHistoryRequest request) {
        if (!"snap".equals(request.getEventType())) {
            return new CommonPage<>(Collections.emptyList(), 0L, request.getCurrent(), request.getSize());
        }
        Page<SasSnapEvent> page = new Page<>(request.getCurrent(), request.getSize());
        LambdaQueryWrapper<SasSnapEvent> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SasSnapEvent::getNotify, true);
        wrapper.orderByDesc(SasSnapEvent::getTriggerTime);
        page = sasSnapEventMapper.selectPage(page, wrapper);
        List<IntelligentEventItem> list = (page.getRecords() == null ? Collections.<SasSnapEvent>emptyList() : page.getRecords())
                .stream().map(this::snapToEventItem).collect(Collectors.toList());
        return new CommonPage<>(list, page.getTotal(), page.getCurrent(), page.getSize());
    }

    private IntelligentEventItem snapToEventItem(SasSnapEvent e) {
        IntelligentEventItem item = new IntelligentEventItem();
        item.setEventId(e.getEventId());
        item.setDeviceId(e.getDeviceId());
        item.setChannel(e.getChannel());
        item.setTriggerTime(e.getTriggerTime());
        item.setEventCode(e.getEventCode());
        item.setScenePicId(e.getScenePicId());
        item.setEventPicId(e.getEventPicId());
        item.setSimilarity(e.getSimilarity());
        item.setPersonCode(e.getPersonCode());
        item.setNotify(e.getNotify());
        item.setScene(e.getScene());
        return item;
    }

    @Override
    public SystemResourceResponse getSystemResource() {
        SystemResourceResponse response = new SystemResourceResponse();
        DecimalFormat df = new DecimalFormat("#0.00");

        // CPU信息
        SystemResourceResponse.CpuInfo cpu = new SystemResourceResponse.CpuInfo();
        Runtime runtime = Runtime.getRuntime();
        cpu.setCoreCount(runtime.availableProcessors());
        
        // 获取CPU使用率
        com.sun.management.OperatingSystemMXBean osBean = 
            (com.sun.management.OperatingSystemMXBean) java.lang.management.ManagementFactory.getOperatingSystemMXBean();
        double cpuUsage = osBean.getSystemCpuLoad() * 100;
        cpu.setUsageRate(df.format(cpuUsage) + "%");
        response.setCpu(cpu);

        // 内存信息
        SystemResourceResponse.MemoryInfo memory = new SystemResourceResponse.MemoryInfo();
        long maxMemory = runtime.maxMemory();
        long totalMemory = runtime.totalMemory();
        long freeMemory = runtime.freeMemory();
        long usedMemory = totalMemory - freeMemory;
        
        double totalMemoryGB = maxMemory / (1024.0 * 1024.0 * 1024.0);
        double usedMemoryGB = usedMemory / (1024.0 * 1024.0 * 1024.0);
        double freeMemoryGB = (maxMemory - usedMemory) / (1024.0 * 1024.0 * 1024.0);
        double memoryUsageRate = (usedMemory * 100.0) / maxMemory;
        
        memory.setTotalSize(df.format(totalMemoryGB) + " GB");
        memory.setUsedSize(df.format(usedMemoryGB) + " GB");
        memory.setFreeSize(df.format(freeMemoryGB) + " GB");
        memory.setUsageRate(df.format(memoryUsageRate) + "%");
        response.setMemory(memory);

        // 磁盘信息
        SystemResourceResponse.DiskInfo disk = new SystemResourceResponse.DiskInfo();
        File[] roots = File.listRoots();
        long totalSpace = 0;
        long usableSpace = 0;
        for (File root : roots) {
            totalSpace += root.getTotalSpace();
            usableSpace += root.getUsableSpace();
        }
        long usedSpace = totalSpace - usableSpace;
        
        double totalSpaceGB = totalSpace / (1024.0 * 1024.0 * 1024.0);
        double usedSpaceGB = usedSpace / (1024.0 * 1024.0 * 1024.0);
        double usableSpaceGB = usableSpace / (1024.0 * 1024.0 * 1024.0);
        double diskUsageRate = totalSpace > 0 ? (usedSpace * 100.0) / totalSpace : 0;
        
        disk.setTotalSize(df.format(totalSpaceGB) + " GB");
        disk.setUsedSize(df.format(usedSpaceGB) + " GB");
        disk.setFreeSize(df.format(usableSpaceGB) + " GB");
        disk.setUsageRate(df.format(diskUsageRate) + "%");
        response.setDisk(disk);

        // Agbox/MetaBus信息
        SystemResourceResponse.AgboxInfo agbox = new SystemResourceResponse.AgboxInfo();
        SasConfig config = sasConfigMapper.selectById(1);
        if (config != null) {
            agbox.setHost(config.getHost());
            agbox.setPort(config.getPort());
            agbox.setStatus(this.mqttService.getConnectionStatus());
            agbox.setEventListenStatus(this.mqttService.getListeningStatus());
        }
        response.setAgboxMetaBus(agbox);
        return response;
    }
}
