package com.sz.admin.monitor.service.impl;

import cn.hutool.core.lang.UUID;
import com.alibaba.fastjson.JSON;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.sz.admin.monitor.enums.AlarmReportEnums;
import com.sz.admin.monitor.mapper.AlgorithmTaskMapper;
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.AlarmReportDTO;
import com.sz.admin.monitor.pojo.dto.edgebox.BoxAlarmReportDto;
import com.sz.admin.monitor.pojo.po.AlgorithmTask;
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.vo.cameraalarm.CameraAlarmVO;
import com.sz.admin.monitor.pojo.vo.edgebox.AlarmReportVO;
import com.sz.admin.monitor.pojo.vo.edgebox.AlgorithmTaskVO;
import com.sz.admin.monitor.service.AlgorithmTaskService;
import com.sz.admin.monitor.service.ForwardService;
import com.sz.admin.monitor.utils.ImageNameUtils;
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.core.util.BeanCopyUtils;
import com.sz.core.util.JsonUtils;
import com.sz.redis.WebsocketRedisService;
import com.sz.security.core.util.LoginUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ClassName: AlgorithmTaskServiceImpl
 * Package: com.sz.admin.monitor.service.impl
 * Description:
 */
@Service
@Slf4j
public class AlgorithmTaskServiceImpl extends ServiceImpl<AlgorithmTaskMapper, AlgorithmTask> implements AlgorithmTaskService {
    @Resource
    private AlgorithmTaskMapper algorithmTaskMapper;
    @Resource
    private CameraMapper cameraMapper;
    @Resource
    private NvrMapper nvrMapper;
    @Resource
    private CameraAlarmMapper cameraAlarmMapper;
    @Resource
    private WebsocketRedisService websocketRedisService;
    @Resource
    private ForwardService forwardService;
    @Resource
    private SysMessageService sysMessageService;
    private final String IMAGE_ROOT_PATH = "D:/work/images/";
    @Override
    public AlgorithmTaskVO getAlgorithmTaskByCameraId(Long cameraId) {
        QueryWrapper wrapper = QueryWrapper.create()
            .select()
            .from(AlgorithmTask.class)
            .where(AlgorithmTask::getCameraId).eq(cameraId);
        AlgorithmTask algorithmTask = algorithmTaskMapper.selectOneByQuery(wrapper);
        if (algorithmTask == null) {
            return null;
        }
        return BeanCopyUtils.copy(algorithmTask, AlgorithmTaskVO.class);
    }
    private String saveBase64AsFile(String base64Image, Long cameraId) {
        byte[] imageBytes = Base64.getDecoder().decode(base64Image);
        String fileName = ImageNameUtils.generateFileName("ALARM", cameraId);
        File dir = new File(IMAGE_ROOT_PATH);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        File file = new File(IMAGE_ROOT_PATH + fileName);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            fos.write(imageBytes);
        }catch (Exception e)
        {
            log.error("保存图片失败", e);
            throw  new RuntimeException("保存图片失败");
        }
        return IMAGE_ROOT_PATH + fileName;
    }
    @Override
    public CameraAlarmVO alarmReport(AlarmReportDTO alarmReportDto) {
        CameraAlarm cameraAlarm = new CameraAlarm();
        // 根据告警的任务标识获取算法任务信息
        AlgorithmTask algorithmTask = algorithmTaskMapper.selectOneByQuery(QueryWrapper.create()
            .select()
            .from(AlgorithmTask.class)
            .where(AlgorithmTask::getAlgTaskSession).eq(alarmReportDto.getTaskSession()));
        // 根据算法任务信息获取摄像头信息
        Long cameraId = algorithmTask.getCameraId();
        cameraAlarm.setCameraId(cameraId);
        Camera camera = cameraMapper.selectOneById(cameraId);
        cameraAlarm.setChannelId(camera.getChannelId());
        cameraAlarm.setCameraNo(camera.getCameraNo());
        // 设置告警区域
        // 根据摄像头查询它对应的nvr
        Nvr nvr = nvrMapper.selectOneById(camera.getNvrId());
        // 设置告警区域
        cameraAlarm.setAlarmAreaId(nvr.getStationId());
        // 获取Base64的字符串
        String imageData = alarmReportDto.getImageData();
        cameraAlarm.setBaseImage(saveBase64AsFile(imageData, cameraId));
        String imageDataLabeled = alarmReportDto.getImageDataLabeled();
        cameraAlarm.setCaptureImage(saveBase64AsFile(imageDataLabeled, cameraId));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        cameraAlarm.setCreateTime(LocalDateTime.parse(alarmReportDto.getTime(), formatter));
        AlarmReportEnums alarmReportEnums = AlarmReportEnums.getAlarmReportEnums(alarmReportDto.getSummary());
        if (alarmReportEnums != null)
        {
            cameraAlarm.setAlarmType(alarmReportEnums.getAlarmCode());
            // 推送信息给前端
            SocketMessage bean = new SocketMessage();
            Map<String, Object> data = new HashMap<>();
            data.put("title", "摄像头报警");
            data.put("content", "摄像头[" + cameraId + "]发生报警,报警内容为：" + alarmReportEnums.getAlarmDescription()+",请及时处理");
            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.parse(alarmReportDto.getTime(), formatter));
            reportDto.setAlarmReportType(alarmReportEnums.getAlarmDescription());
            reportDto.setDescription(alarmReportDto.getResult().getDescription());
            reportDto.setBaseImage(imageData);
            reportDto.setCaptureImage(imageDataLabeled);
            reportDto.setUrl(algorithmTask.getUrl());
            reportDto.setCameraName(camera.getName());
            reportDto.setCameraId(cameraId);
            reportDto.setCameraNo(camera.getCameraNo());
            try {
                forwardService.enrichAndForward(reportDto);
            }catch ( Exception e)
            {
                log.error("报警信息上报失败", e);
            }
        }
        cameraAlarm.setAlgoResult(JsonUtils.toJsonString(alarmReportDto.getResult()));
        cameraAlarm.setStatus(0);
        cameraAlarm.setCameraName(camera.getName());
        cameraAlarm.setSummary(alarmReportDto.getSummary());
        cameraAlarm.setTaskDesc(alarmReportDto.getTaskDesc());
        cameraAlarm.setTaskSession(alarmReportDto.getTaskSession());
        cameraAlarm.setBoardIp(alarmReportDto.getBoardIp());
        // 保存到数据库
        cameraAlarmMapper.insert(cameraAlarm);
        return BeanCopyUtils.copy(cameraAlarm, CameraAlarmVO.class);
    }

    @Override
    public List<AlgorithmTaskVO> listByCameraIds(List<? extends Serializable> ids) {
        QueryWrapper wrapper = QueryWrapper.create()
            .select()
            .from(AlgorithmTask.class)
            .where(AlgorithmTask::getCameraId).in(ids);
        List<AlgorithmTask> algorithmTasks = algorithmTaskMapper.selectListByQuery(wrapper);
        return BeanCopyUtils.copyList(algorithmTasks, AlgorithmTaskVO.class);
    }
}
