package com.sz.admin.monitor.task;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.sz.admin.monitor.enums.AlarmReportEnums;
import com.sz.admin.monitor.mapper.CameraAlarmMapper;
import com.sz.admin.monitor.mapper.CameraMapper;
import com.sz.admin.monitor.mapper.NvrMapper;
import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto;
import com.sz.admin.monitor.pojo.po.Camera;
import com.sz.admin.monitor.pojo.po.CameraAlarm;
import com.sz.admin.monitor.pojo.po.Nvr;
import com.sz.admin.monitor.pojo.po.Preset;
import com.sz.admin.monitor.pojo.vo.camerasnapshot.CameraSnapshotVO;
import com.sz.admin.monitor.sdk.ManageNVR;
import com.sz.admin.monitor.service.CameraService;
import com.sz.admin.monitor.service.CameraSnapshotService;
import com.sz.admin.monitor.service.ForwardService;
import com.sz.admin.monitor.service.PresetService;
import com.sz.admin.monitor.utils.ImageNameUtils;
import com.sz.admin.monitor.utils.OffsetCalculator;
import com.sz.admin.monitor.utils.RobustImageMatcherUtil;
import com.sz.admin.system.pojo.dto.sysmessage.Message;
import com.sz.admin.system.service.SysMessageService;
import com.sz.core.common.entity.SocketMessage;
import com.sz.core.common.entity.TransferMessage;
import com.sz.core.common.enums.MessageTransferScopeEnum;
import com.sz.core.common.enums.SocketChannelEnum;
import com.sz.redis.WebsocketRedisService;
import com.sz.security.core.util.LoginUtils;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ClassName: ScheduleTask
 * Package: com.sz.admin.monitor.task
 * Description:  周期任务类
 */
@Component
@Slf4j
public class ScheduledTask {
    @Resource
    private PresetService presetService;
    @Resource
    private CameraService cameraService;
    @Resource
    private ManageNVR manageNVR;
    @Resource
    private NvrMapper nvrMapper;
    @Resource
    private CameraSnapshotService cameraSnapshotService;
    @Resource
    private CameraAlarmMapper cameraAlarmMapper;
    @Resource
    private WebsocketRedisService websocketRedisService;
    @Resource
    private  SysMessageService sysMessageService;
    @Resource
    private ForwardService forwardService;


   // @Scheduled(cron = "0/5 * * * * ?")
    public void test()
    {
        SocketMessage bean = new SocketMessage();
        Map<String, Object> data = new HashMap<>();
        data.put("title", "移位报警");
        data.put("content", "摄像头[" +33 + "]发生异常，请及时处理！");
        bean.setData(JSON.toJSONString(data));
        bean.setChannel(SocketChannelEnum.MESSAGE);
        bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT);
        TransferMessage msg = new TransferMessage();
        msg.setMessage(bean);
        msg.setFromUser("system");
        msg.setToPushAll(true);
        websocketRedisService.sendServiceToWs(msg);
    }
    // 定期检查
    @Scheduled(cron = "0/20 * * * * ?")
    @SneakyThrows
    public void executeInspection() {
        // 从摄像头表中获取设置了抓图对比和在线的摄像头
        List<Camera> cameraList = cameraService.selectListByInspection();
        // 然后根据摄像头id查询设置为标准位的预置位，
        List<Long> cameraIds = cameraList.stream().map(Camera::getId).toList();
        if(CollectionUtil.isEmpty(cameraIds))
        {
            // 如果为空，则表示没有摄像头开启巡检功能，直接返回
            return;
        }
        List<Preset> presetList = presetService.selectByCameraIds(cameraIds);
        for (Preset preset : presetList) {
            // 调用SDK让摄像头回归到该预置位
            boolean ok = manageNVR.ptzPresets(preset.getCameraId().intValue(), 39, String.valueOf(preset.getPresetId()), preset.getPresetName());
            // 延时5秒
            Thread.sleep(5000);
            if (ok) {
                // 抓取一张图片
                 String filename = ImageNameUtils.generateFileName("CAPTURE",preset.getCameraId());
                //String image2 = "D:\\work\\images\\CAPTURE_367_20260212092406664_2d117293.jpg";
               // String image2 = "D:\\work\\images\\CAPTURE_19_20260302152457977_db33f5a8.jpg";
                 String image2 = manageNVR.capturePic(preset.getCameraId().intValue(), filename);
                // 从图片表中，根据预置位，摄像机id，类型为巡检为条件查询出基准图
                CameraSnapshotVO cameraSnapshotVO = cameraSnapshotService.selectByCameraIdAndPresetIndex(preset.getCameraId(), preset.getPresetId());
                if (cameraSnapshotVO == null || cameraSnapshotVO.getImagePath() == null) {
                    log.warn("摄像机[{}] 未设置基准图，无法对比", preset.getCameraId());
                    continue;
                }
                // 调用图片对比算法，校验摄像头是否移位
                // 基准图
                String image1 = cameraSnapshotVO.getImagePath();
                // 对比
                Map<String, Object> map = RobustImageMatcherUtil.calculateOffset(image1, image2);
                log.info("图片对比结果：{}", map);
                // 判断结果并报警
                handleAnalysisResult(preset, cameraSnapshotVO.getImagePath(), image2, map);
            }
        }

    }

    //判断结果并报警
    private void handleAnalysisResult(Preset preset, String imagePath, String image2, Map<String, Object> map) throws IOException {
        int value = (int) map.get("value");
        if (value == 1) {
            // 发生了偏移，需要保存报警信息等人工处理
            Camera camera = cameraService.getById(preset.getCameraId());
            CameraAlarm cameraAlarm = new CameraAlarm();
            cameraAlarm.setCameraId(camera.getId());
            // 设置告警区域
            // 根据摄像头查询它对应的nvr
            Nvr nvr = nvrMapper.selectOneById(camera.getNvrId());
            // 设置告警区域
            cameraAlarm.setAlarmAreaId(nvr.getStationId());
            cameraAlarm.setChannelId(camera.getChannelId());
            cameraAlarm.setCameraName(camera.getName());
            cameraAlarm.setPresetIndex(preset.getPresetId());
            // 标记为移位报警
            cameraAlarm.setAlarmType(1);
            cameraAlarm.setBaseImage(imagePath);
            cameraAlarm.setCaptureImage(image2);
            // 算法的结果
            cameraAlarm.setAlgoResult((String) map.get("description"));
            // 状态为未处理
            cameraAlarm.setStatus(0);
            cameraAlarmMapper.insert(cameraAlarm);
            log.info("生成移位报警: 通道{}, 偏移信息: {}", preset.getChannelId(), map.get("description"));
            // 向前端主动推送消息
            SocketMessage bean = new SocketMessage();
            Map<String, Object> data = new HashMap<>();
            data.put("title", "摄像头报警");
            data.put("content", "摄像头[" + preset.getCameraId() + "]发生移位，请及时处理！");
            bean.setData(JSON.toJSONString(data));
            bean.setChannel(SocketChannelEnum.MESSAGE);
            bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT);
            TransferMessage msg = new TransferMessage();
            msg.setMessage(bean);
            msg.setFromUser("system");
            msg.setToPushAll(true);
            websocketRedisService.sendServiceToWs(msg);
            // 统一处理报警信息后，将摄像头信息+报警信息上报给别人服务器
            BoxAlarmReportDto reportDto = new BoxAlarmReportDto();
            reportDto.setAlarmReportTime(LocalDateTime.now());
            reportDto.setAlarmReportType(AlarmReportEnums.DISPLACEMENT_ALARM.getAlarmDescription());
            reportDto.setDescription("摄像头发生移位");
            byte[] BaseFileContent = Files.readAllBytes(Paths.get(imagePath));
            reportDto.setBaseImage(Base64.getEncoder().encodeToString(BaseFileContent));
            byte[] CaptureFileContent = Files.readAllBytes(Paths.get(image2));
            reportDto.setCaptureImage(Base64.getEncoder().encodeToString(CaptureFileContent));
            reportDto.setUrl(preset.getPresetUrl());
            reportDto.setCameraName(camera.getName());
            reportDto.setCameraId(camera.getId());
            reportDto.setCameraNo(camera.getCameraNo());
            forwardService.enrichAndForward(reportDto);
        }
    }

}
