package com.cico.nest.lcdp.boot.core.qxsd.application.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.event.EventDetailPageReqVO;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.event.EventHisRespVO;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.EventDetailService;
import com.cico.nest.lcdp.boot.core.qxsd.domain.event.EventStatus;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.common.constatnt.XlwConstants;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.EventDetailMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.EventHisMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.EventDetailDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.EventHisDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.mqtt.handler.QxsdTrafficEventReportHandler;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.mqtt.handler.dto.QxsdEventMQReportDTO;
import com.cico.nest.lcdp.framework.common.exception.ServiceException;
import com.cico.nest.lcdp.framework.common.pojo.PageResult;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static com.cico.nest.lcdp.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;

/**
 * 事件详情 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class EventDetailServiceImpl implements EventDetailService {

    @Resource
    private EventDetailMapper eventDetailMapper;

    @Resource
    private EventHisMapper eventHisMapper;

    @Value("${qxsd.xlw.images}")
    private String xlwImagesPath;

    @Value("${qxsd.static-resource.event-images}")
    private String staticResourceEventImagesPath;

    @Value("${qxsd.static-resource.bayonet-images}")
    private String staticResourceBayonetImagesPath;
    @Value("${qxsd.static-resource.event-his-video}")
    private String staticResourceEventHisVideoPath;
    @Resource
    private QxsdTrafficEventReportHandler qxsdEventReportHandler;
    private final ExecutorService executor = Executors.newFixedThreadPool(5);


    @Override
    public EventDetailDO getEventDetail(String id) {
        EventDetailDO eventDetailDO = eventDetailMapper.selectById(id);
        if(Objects.nonNull(eventDetailDO)){
            LambdaQueryWrapper<EventDetailDO>  updateWrapper = Wrappers.lambdaQuery();
            updateWrapper.eq(EventDetailDO::getId,id);
            EventDetailDO updateEventDO = new EventDetailDO();
            updateEventDO.setId(id);
            if(EventStatus.disposing_await.type == eventDetailDO.getEventStatus()){
                updateEventDO.setEventStatus(EventStatus.disposing_await_read.type);
                eventDetailMapper.update(updateEventDO,updateWrapper);
            }
        }
        return eventDetailDO;
    }

    @Override
    public PageResult<EventDetailDO> getEventDetailPage(EventDetailPageReqVO pageReqVO) {
        return eventDetailMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dispelEvent(String id,String dispelCause,String processingOperationsName) {
        EventDetailDO eventDetailDO = eventDetailMapper.selectById(id);
        if(Objects.isNull(eventDetailDO)){
            throw new ServiceException(INTERNAL_SERVER_ERROR.getCode(),"事件不存在");
        }
        if(EventStatus.disposing_end.type == eventDetailDO.getEventStatus()){
            throw new ServiceException(INTERNAL_SERVER_ERROR.getCode(),"事件已结束不能消除");
        }
        if (eventDetailDO.getEventSource() != XlwConstants.EVENT_SOURCE_XLW){
            //事件来源是隧道管控的，在隧道系统页面进行结束消除。
            return;
        }
        eventDetailDO.setEventStatus(EventStatus.disposing_end.type);
        eventDetailDO.setDispelCause(dispelCause);
        eventDetailDO.setProcessingType(2);
        eventDetailDO.setProcessingOperationsName(processingOperationsName);
        eventDetailDO.setProcessingTime(new Date());
        eventDetailMapper.updateById(eventDetailDO);
    }

    @Override
    public void reporEventToSdgk(EventDetailDO eventDetailDO){
        if (eventDetailDO.getIsRepeat()==1){
            //已经是重复的事件了，不上报
            throw new ServiceException(INTERNAL_SERVER_ERROR.getCode(),"重复的事件不上报。");
        }
        //异步推送全息隧道事件到隧道管控系统
        executor.submit(()-> {
            QxsdEventMQReportDTO eventMQReportDTO = QxsdEventMQReportDTO.convert2MQ(eventDetailDO);
            qxsdEventReportHandler.sendTo(eventMQReportDTO);

        });
        eventDetailDO.setEventStatus(EventStatus.disposing_process.type);
        eventDetailDO.setReportTime(new Date());
        eventDetailMapper.updateById(eventDetailDO);
    }

    @Override
    public EventHisRespVO getEventHisDetail(String eventId) {
        EventHisDO eventHis = eventHisMapper.selectByEventId(eventId);
        EventHisRespVO respVO = new EventHisRespVO();
        EventDetailDO eventDetailDO = eventDetailMapper.selectById(eventId);
        if(Objects.isNull(eventDetailDO)){
            return respVO;
        }
        if(Objects.isNull(eventHis)){
            //取实时的事件图片
            List<String> eventImagesPath = eventDetailDO.getEventImagesPath();
            if(CollUtil.isNotEmpty(eventImagesPath)){
                respVO.setEventImagesPath(eventImagesPath.stream().filter(e->e.startsWith("/")).map(e->xlwImagesPath.concat(e)).toList());
            }
        }else{
            BeanUtils.copyProperties(eventHis,respVO);
            respVO.setExistHisData(true);
            List<String> eventImagesPath = eventHis.getEventImagesPath();
            if(CollUtil.isNotEmpty(eventImagesPath)){
                respVO.setEventImagesPath(eventHis.getEventImagesPath().stream().filter(e->!e.contains("error")).map(e -> staticResourceEventImagesPath.concat(e)).toList());
            }
            JSONArray bayonetImage = eventHis.getBayonetImage();
            if(CollUtil.isNotEmpty(bayonetImage)){
                List<Map> bayonetImagePath = new ArrayList<>();
                List<Map> bayonetImageList = bayonetImage.toList(Map.class);
                for(Map map:bayonetImageList){
                    Map imagePathMap = new HashMap();
                    for(Object key:map.keySet()){
                        List<String> imagePath = (List<String>) map.get(key);
                        imagePath = imagePath.stream().filter(e->!e.contains("error")).map(e->staticResourceBayonetImagesPath.concat(e)).toList();
                        imagePathMap.put("imagePath",imagePath);
                        imagePathMap.put("carPlate",key);
                    }
                    bayonetImagePath.add(imagePathMap);
                }
                respVO.setBayonetImage(bayonetImagePath);
            }
            respVO.setHisVehicleInfo(eventHis.getHisVehicleInfo());
            respVO.setCameraIndexCode(eventHis.getCameraIndexCode());
            //视频
            String videoPath = eventHis.getVideoPath();
            if(StrUtil.isNotBlank(videoPath) && !videoPath.contains("error")){
                respVO.setVideoPath(staticResourceEventHisVideoPath + videoPath);
            }
        }
        return respVO;
    }

    @Override
    public boolean judgeSameEvent(String tunnelId, String thirdEventId, Integer eventType, Integer milestone, Date happenTime,int eventSource) {
        //* 不同来源的同一个隧道洞里同种事件类型，位置前后20米，时间前后20秒，范围内，属于同一事件
        Integer startMillstone=null ;
        Integer endMillstone=null;
        if (milestone!=null){
            startMillstone = milestone-20;
            endMillstone = milestone+20;
        }
        Date startDate = null;
        Date endDate = null;
        if (happenTime !=null){
            startDate = new Date(happenTime.getTime()-20000);
            endDate = new Date(happenTime.getTime()+20000);
        }
        List<EventDetailDO> res = eventDetailMapper.getSameEvents(tunnelId, thirdEventId, eventType,startMillstone,endMillstone,startDate,endDate,eventSource);
        return CollUtil.isNotEmpty(res);
    }

}
