package com.tuoheng.admin.service.third.dsp;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.tuoheng.admin.entity.domain.*;
import com.tuoheng.admin.entity.request.CallbackRequest;
import com.tuoheng.admin.enums.*;
import com.tuoheng.admin.mapper.QuestionMapper;
import com.tuoheng.admin.mapper.ThInspectionMapper;
import com.tuoheng.admin.mapper.ThMissionMapper;
import com.tuoheng.admin.service.IQuestionTypeService;
import com.tuoheng.admin.service.third.UpdateEmergencyMissionStatusService;
import com.tuoheng.admin.service.warning.IWarningService;
import com.tuoheng.admin.utils.GaodeUtil;
import com.tuoheng.common.exception.ServiceException;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class DspCallBackService {

    @Autowired
    private ThMissionMapper missionMapper;

    @Autowired
    private ThInspectionMapper inspectionMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private IQuestionTypeService questionTypeService;

    @Autowired
    private IWarningService warningService;

    @Autowired
    private UpdateEmergencyMissionStatusService updateEmergencyMissionStatusService;

    public JsonResult process(String requestId, CallbackRequest callbackRequest) throws ServiceException {
        ThMission mission = this.getThMission(requestId);

        // 保存DSP分析出来的问题
        this.saveQuestion(callbackRequest, mission);

        // 修改分析状态
        ThMission thMissionUpdate = new ThMission(UpdateOrCreateEnum.UPDATE.getCode());
        thMissionUpdate.setId(mission.getId());
        thMissionUpdate.setProgressbar(callbackRequest.getProgress());
        this.setAnalyseData(callbackRequest, thMissionUpdate);
        Integer count = missionMapper.updateById(thMissionUpdate);
        if (count <= 0) {
            log.info("DSP分析，修改分析状态失败");
        }

        updateEmergencyMissionStatusService.updateStatus(mission, null);

        return JsonResult.success();
    }

    /**
     * 获取任务
     *
     * @param requestId
     * @return
     */
    private ThMission getThMission(String requestId) {
        LambdaQueryWrapper<ThMission> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ThMission::getMark, MarkTypeEnum.VALID.getCode())
                .eq(ThMission::getRequestId, requestId)
//                          .eq(ThMission::getStatus, TaskStatusEnum.FLIGHT.getCode())
                .orderByDesc(ThMission::getExecutionStartTime);
        List<ThMission> thMissions = missionMapper.selectList(lambdaQueryWrapper);
        if (ObjectUtil.isEmpty(thMissions) || thMissions.size() == 0) {
            log.info("任务不存在!!");
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "任务不存在!!");
        }
        return thMissions.get(0);
    }

    /**
     * 设置dsp回调返回的数据
     * 1、DSP分析状态
     * 2、DSP分析完成，设置视频地址
     *
     * @param callbackRequest
     * @param thMissionUpdate
     */
    private void setAnalyseData(CallbackRequest callbackRequest, ThMission thMissionUpdate) {
        if (callbackRequest.getAnalyseStatus() == AiAnalyseStatusEnum.SUCCESS.getCode() || callbackRequest.getAnalyseStatus() == AiAnalyseStatusEnum.SUCCESS_TIMEOUT.getCode()) {
            //这边存回放的视频地址
            thMissionUpdate.setVideoUrl(callbackRequest.getVideoUrl());
            thMissionUpdate.setAiVideoUrl(callbackRequest.getAiVideoUrl());
            if (callbackRequest.getAnalyseStatus() == AiAnalyseStatusEnum.SUCCESS_TIMEOUT.getCode()) {
                thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.SUCCESS_TIMEOUT.getCode());
            } else {
                thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.SUCCESS.getCode());
            }
        } else if (callbackRequest.getAnalyseStatus() == AiAnalyseStatusEnum.FAILED.getCode()) {
            thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.FAILED.getCode());
        } else {
            thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.RUNNING.getCode());
        }
    }

    private Boolean saveQuestion(CallbackRequest callbackRequest, ThMission mission) {
        List<CallbackRequest.QuestionFilesDTO> questionFiles = callbackRequest.getQuestionFiles();
        //获取当前飞行坐标，存问题的经纬度
        List<ThInspection> flightDataList = getThInspections(mission);
        List<Question> questionList = getQuestionList(mission, questionFiles, flightDataList);
        if (questionList.size() == 0) {
            return true;
        }
        boolean flag = false;
        for (Question question : questionList) {
            questionMapper.insert(question);
        }
        //保存问题数据时调用saveWarningData方法保存预警数据入库
        Boolean aBoolean = this.saveWarningData(questionList);
        log.info("预警表数据入库结束, {}", aBoolean);
        return flag;
    }

    private List<ThInspection> getThInspections(ThMission mission) {
        return inspectionMapper.selectList(new LambdaQueryWrapper<ThInspection>()
                .eq(ThInspection::getMissionId, mission.getId())
                .eq(ThInspection::getMark, MarkTypeEnum.VALID.getCode())
                .orderByDesc(ThInspection::getCreateTime));
    }

    private List<Question> getQuestionList(ThMission mission, List<CallbackRequest.QuestionFilesDTO> questionFiles, List<ThInspection> flightDataList) {
        List<Question> questionList = new ArrayList<>();
        if (ObjectUtil.isEmpty(questionFiles)) {
            return questionList;
        }

        List<QuestionType> questionType = questionTypeService.getQuestionType();
        Map<String, QuestionType> typeMap = new HashMap<>();
        for (QuestionType type : questionType) {
            typeMap.put(type.getCode(), type);
        }
        for (CallbackRequest.QuestionFilesDTO questionFile : questionFiles) {
            Question question = new Question(UpdateOrCreateEnum.CREATE.getCode());
            BeanUtils.copyProperties(questionFile, question);
            ThInspection flightDataByTime = getFlightDataByTime(flightDataList, questionFile.getAnalyseTime().getTime());
            question.setMissionId(mission.getId());
            question.setTenantId(mission.getTenantId());
            question.setMissionName(mission.getName());
            question.setLat(flightDataByTime.getLat());
            question.setLng(flightDataByTime.getLng());
            //待确认
            question.setStatus(QuestionStatusEnum.NOTREVIEWED.getCode());
            //问题类型
            QuestionType questionTypeInfo = typeMap.get(questionFile.getQuestionCode());
            question.setType(ObjectUtil.isNotEmpty(questionTypeInfo) ? questionTypeInfo.getCode() : "");
            question.setQuestionName(ObjectUtil.isNotEmpty(questionTypeInfo) ? questionTypeInfo.getContent() : "");
            question.setQuestionDesc(ObjectUtil.isNotEmpty(questionTypeInfo) ? questionTypeInfo.getDescription() : "");
            questionList.add(question);
        }
        return questionList;
    }

    //根据获取的问题列表问题类型code为002004,添加数据入库到预警表
    private Boolean saveWarningData(List<Question> questionList) {
        log.info("预警表数据入库开始...");
        List<Warning> warningList = new ArrayList<>();
        List<QuestionType> questionType = questionTypeService.getQuestionType();
        Map<String, QuestionType> typeMap = new HashMap<>();
        for (QuestionType type : questionType) {
            typeMap.put(type.getCode(), type);
        }
        //调用添加问题列表接口
        for (Question question : questionList) {
            Warning warning = new Warning();
            //问题类型为火灾隐患时添加数据
            if (question.getType().equals(QuestionTypeEnum.Q4.getCode()) || question.getType().equals(QuestionTypeEnum.Q3.getCode())) {
                warning.setTenantId(question.getTenantId());
                warning.setMissionId(question.getMissionId());
                warning.setDiscoveryWay(DiscoveryWayEnum.UAV_PATROL.getCode());
                warning.setStatus(WarningStatusEnum.WAIT_CONFIRM.getCode());
                warning.setQuestionId(question.getId());
                warning.setCreateUser(question.getCreateUser());
                warning.setCreateTime(question.getCreateTime());
                warning.setMark(MarkTypeEnum.VALID.getCode());
                if (StringUtils.isNotEmpty(question.getLng()) && StringUtils.isNotEmpty(question.getLat())) {
                    String gaodeAddress = GaodeUtil.getGaodeAddress(question.getLng(), question.getLat());
                    warning.setLocation(gaodeAddress);
                }

                ThMission thMission = missionMapper.selectById(question.getMissionId());
                if (thMission.getType() == AccidentTaskEnum.ACCIDENT_TASK.getCode()) {
                    warning.setFlag(FlagEnum.ACCIDENT.getCode());
                } else {
                    // 该巡检任务存在应急任务，将后面发现的预警直接设置为不展示
                    ThMission emergencyMission = missionMapper.selectOne(new LambdaQueryWrapper<ThMission>()
                            .eq(ThMission::getEmergencyDataMissionId, question.getMissionId())
                            .eq(ThMission::getMark, MarkEnum.VALID.getCode()));
                    if (ObjectUtils.isNotEmpty(emergencyMission)) {
                        warning.setFlag(FlagEnum.ACCIDENT.getCode());
                    } else {
                        warning.setFlag(FlagEnum.INSPECTION_ACCIDENT.getCode());
                    }
                }
                warningList.add(warning);
            }
        }
        return warningService.saveBatch(warningList);
    }

    /**
     * 获取飞行坐标
     *
     * @param inspectionList 飞行坐标集合
     * @param time           当前时间
     * @return 当前飞行对象
     */
    private ThInspection getFlightDataByTime(List<ThInspection> inspectionList, long time) {
        if (CollectionUtils.isEmpty(inspectionList)) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "获取无人机飞行坐标失败！");
        }
        List<ThInspection> inspectionData = new ArrayList<>();
        for (ThInspection thInspection : inspectionList) {
            if (thInspection.getUpdateTime().getTime() <= time) {
                inspectionData.add(thInspection);
            }
        }
        if (CollectionUtils.isEmpty(inspectionData)) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "获取无人机飞行坐标失败！");
        }
        return inspectionData.get(0);
    }
}
