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

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONArray;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.request.LocusDataRequest;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.HistoryService;
import com.cico.nest.lcdp.boot.core.qxsd.domain.gateway.HistoryGateway;
import com.cico.nest.lcdp.boot.core.qxsd.domain.vehicle.HistoryTunnelVehicle;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.EventHisMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelDetailMapper;
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.database.dataobject.TunnelDetailDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.TunnelDeviceDO;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.hk.HkVideoMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.http.xlw.dto.XlwHolographicTimeHistoryDTO;
import com.cico.nest.lcdp.framework.common.util.date.DateUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
import org.apache.commons.lang3.StringUtils;
import org.simpleframework.xml.Path;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zws
 * @date 2024/8/20
 */

@Service
@Slf4j
public class HistoryServiceImpl implements HistoryService {

    @Resource
    private HistoryGateway historyGateway;
    @Resource
    private EventHisMapper eventHisMapper;
    @Resource
    private TunnelDetailMapper tunnelDetailMapper;
    @Value("${spring.profiles.active}")
    private String activeProfile;
    /**
     * 事件完成时保存事件历史数据
     * v1 事件完成后被调用，his表做新增动作
     * v2 事件未完成或者完成都会被调用，未完成时保存卡口，及事件图片，完成时调用如果保存卡口 或者 事件图片 为空，再保存一次
     *    有可能第一次的执行还没结束，第二次又进来了，
     * @param eventDetailDO 事件信息
     */
    @Override
    public void saveEventHistoryData(EventDetailDO eventDetailDO) {
        // 为0需要更新其他信息
        boolean isEventEnd = Objects.equals(eventDetailDO.getThirdEventStatus(), 0);
        log.info("保存事件历史表,eventId:{},开始,三方事件状态是否结束={},",eventDetailDO.getId(),isEventEnd?"结束":"未结束");

        EventHisDO eventHisDO = new EventHisDO();
        eventHisDO.setEventId(eventDetailDO.getId());
        EventHisDO mysqlEventHisDO = eventHisMapper.selectByEventId(eventDetailDO.getId());
        if(Objects.nonNull(mysqlEventHisDO)){
            eventHisDO = mysqlEventHisDO;
        }else{
            eventHisMapper.insertOrUpdate(eventHisDO);
        }
        // todo 写入 vehicleInTunnelTime 字段 车辆入隧时间


        // 事件完成 && 字段为空 更新 轨迹数据 字段
        if( isEventEnd && CollectionUtils.isEmpty(eventHisDO.getHisVehicleInfo()) ){
            //轨迹数据
            this.getHisVehicleInfo( eventDetailDO, eventHisDO);
            log.info("保存事件历史表,eventId:{},【轨迹数据】完成",eventDetailDO.getId());
        }


        // 事件图片 不存在 更新 事件图片 字段
        if( CollectionUtils.isEmpty(eventHisDO.getEventImagesPath()) ){
            this.getEventImage( eventDetailDO, eventHisDO);
            log.info("保存事件历史表,eventId:{},【事件图片】完成",eventDetailDO.getId());
        }

        // 卡口图片 不存在 更新 卡口图片 字段 因为为空需去里面判断
//        if( CollectionUtils.isEmpty(eventHisDO.getBayonetImage()) ){
        this.getBayonetImage( eventDetailDO, eventHisDO);
            log.info("保存事件历史表,eventId:{},【卡口图片】完成",eventDetailDO.getId());
//        }


        // 事件完成 && 字段为空  || 存储是 包含"error" 更新 历史视频数据 字段
        if( isEventEnd && (StringUtils.isEmpty(eventHisDO.getVideoPath()) || eventHisDO.getVideoPath().indexOf("error")>-1 )){
            //历史视频数据 非 localhost 环境会下载，本地就不测试了 todo
            if(!"localhost1".equals(activeProfile)){
                this.getVideoPath( eventDetailDO, eventHisDO);
                log.info("保存事件历史表,eventId:{},【历史视频数据】完成",eventDetailDO.getId());
            }else{
                log.info("保存事件历史表,eventId:{},【历史视频数据】localhost环境不进行下载",eventDetailDO.getId());
            }
        }

        try {
            eventHisMapper.insertOrUpdate(eventHisDO);
            log.info("保存事件历史表,eventId:{},结束",eventDetailDO.getId());
        } catch (Exception e) {
            log.error("保存事件历史表,eventId:{},保存事件历史数据异常",eventDetailDO.getId(),e);
        }
    }

    private void getEventImage(EventDetailDO eventDetailDO,EventHisDO eventHisDO) {
        //保存事件图片
        try {
            List<String> eventImagesPathList = eventDetailDO.getEventImagesPath();
            List<String> eventImagesSavePath = new ArrayList<>();
            for(String urlPath : eventImagesPathList){
                if(urlPath.startsWith("/")){
                    String saveUrlPath = "";
                    try{
                        saveUrlPath = historyGateway.saveEventImage(urlPath);
                    }catch (Throwable e){
                        saveUrlPath = "error获取事件图片失败";
                        log.error("获取事件图片失败",e);
                    }
                    eventImagesSavePath.add(saveUrlPath);
                }
            }
            eventHisDO.setEventImagesPath(eventImagesSavePath);
        } catch (Exception e) {

        }
    }

    private void getHisVehicleInfo(EventDetailDO eventDetailDO,EventHisDO eventHisDO) {
        //获取轨迹数据
        try{
            List<HistoryTunnelVehicle> historyTunnelVehicleList = historyGateway.getVehicleInfo(
                    new LocusDataRequest()
                            .setTunnelId(eventDetailDO.getTunnelId())
                            .setStartTime(DateUtil.format(eventDetailDO.getEventStartTime(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
                            .setEndTime(DateUtil.format(eventDetailDO.getEventEndTime(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND))
            );
            eventHisDO.setHisVehicleInfo(JSONArray.from(historyTunnelVehicleList));
        }catch (Throwable e){
            eventHisDO.setHisVehicleInfo(JSONArray.from(new ArrayList<>()));
            log.error("获取轨迹数据失败",e);
        }
    }

    private void getVideoPath(EventDetailDO eventDetailDO,EventHisDO eventHisDO) {
        //获取历史视频数据
        try{
            Date eventStartTime = eventDetailDO.getEventStartTime();
            Date eventEndTime = eventDetailDO.getEventEndTime();
            long diffSecond = DateUtil.between(eventStartTime,eventEndTime, DateUnit.SECOND);
            if(Objects.nonNull(eventDetailDO.getDeviceMilestone())){
                String beginTime = DateUtil.format(DateUtil.offsetSecond(eventStartTime,-6),"yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
                String endTime = DateUtil.format(eventEndTime,"yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
                if(diffSecond > 24){
                    endTime = DateUtil.format(DateUtil.offsetSecond(eventStartTime,24),"yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
                    log.info("getVideoPath,时长:{}>24s,重新设置结束时间:{}",diffSecond,endTime);
                }
                log.info("获取历史视频,eventId:{},开始时间：{}，结束时间：{},时长:{}",eventDetailDO.getId(),beginTime,endTime,diffSecond);
                int direction = 100700;
                if("下行".equals(eventDetailDO.getDirection())){
                    direction = 100701;
                }
                TunnelDeviceDO tunnelDeviceDO = historyGateway.getDevice(eventDetailDO.getBaseTunnelCode()
                        ,eventDetailDO.getHoleId()
                        ,Integer.valueOf(eventDetailDO.getDeviceMilestone())
                        ,direction);
                if(Objects.isNull(tunnelDeviceDO)){
                    log.error("未找到对应摄像头，tunnelCode:{},holeId:{},deviceMilestone:{},direction:{}", eventDetailDO.getBaseTunnelCode(), eventDetailDO.getHoleId(), Integer.valueOf(eventDetailDO.getDeviceMilestone()), direction);
                    eventHisDO.setVideoPath("error未找到对应摄像头,事件桩号:" + eventDetailDO.getDeviceMilestone());
                    return;
                }
                //保存
                eventHisDO.setCameraIndexCode(tunnelDeviceDO.getCameraIndexCode());
                String videoUrl = historyGateway.saveVideo(tunnelDeviceDO.getCameraIndexCode()
                        ,beginTime
                        ,endTime
                        ,eventDetailDO.getId() + ".mp4");
                eventHisDO.setVideoPath("/" + videoUrl);
            }
        }catch (Throwable e){
            eventHisDO.setVideoPath("error获取历史视频失败");
            log.error("获取历史视频失败",e);
        }
    }


    private void getBayonetImage(EventDetailDO eventDetailDO,EventHisDO eventHisDO) {
        List<String> catPlateErrorList = Arrays.asList("人","未知","默A00000");
        Map<String,List<String>> map = new HashMap<>(8);
        if(CollectionUtils.isNotEmpty(eventHisDO.getBayonetImage())){
            for(Object o : eventHisDO.getBayonetImage()){
                Map<String,List<String>> tempMap = (Map<String,List<String>>)o;
                map.putAll(tempMap);
            }
        }
        //获取卡口图片
        try {
            List<String> carPlateList = eventDetailDO.getEventCarPlate();
            JSONArray jsonArray = new JSONArray();
            for(String carPlate : carPlateList){
                // 卡口图片存在，并且集合>0
                if(map.containsKey(carPlate) && CollectionUtils.isNotEmpty(map.get(carPlate))){
                    jsonArray.add(Map.of(carPlate,map.get(carPlate)));
                }else{
                    try{
                        if(catPlateErrorList.contains(carPlate)){
                            log.info("保存事件历史表,eventId:{},【卡口图片】carPlate={},定义为无卡口信息不进行查询",eventDetailDO.getId(),carPlate);
                            jsonArray.add(Map.of(carPlate,new ArrayList()));
                        }else{
                            List<String> bayonetImageList = historyGateway.saveBayonetImage(carPlate,eventDetailDO.getEventStartTime());
                            jsonArray.add(Map.of(carPlate,bayonetImageList));
                        }
                    }catch (Throwable e){
                        log.error("获取卡口图片失败",e);
                    }
                }
            }
            eventHisDO.setBayonetImage(jsonArray);
        } catch (Exception e) {

        }

    }



}
