package com.tuoheng.admin.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tuoheng.admin.common.ServiceExceptionEnum;
import com.tuoheng.admin.entity.domain.*;
import com.tuoheng.admin.entity.request.*;
import com.tuoheng.admin.entity.vo.MissionVO;
import com.tuoheng.admin.entity.vo.QuestionCountVO;
import com.tuoheng.admin.entity.vo.QuestionTypeCountVO;
import com.tuoheng.admin.entity.vo.QuestionVO;
import com.tuoheng.admin.enums.*;
import com.tuoheng.admin.mapper.*;
import com.tuoheng.admin.service.IQuestionService;
import com.tuoheng.admin.service.IQuestionTypeService;
import com.tuoheng.admin.service.warning.IWarningService;
import com.tuoheng.admin.service.warning.WarningServiceImpl;
import com.tuoheng.admin.utils.GaodeUtil;
import com.tuoheng.admin.utils.TimeUtil;
import com.tuoheng.common.common.BaseServiceImpl;
import com.tuoheng.common.exception.ServiceException;
import com.tuoheng.common.utils.JsonResult;
import com.tuoheng.common.utils.StringUtils;
import com.tuoheng.system.utils.ShiroUtils;
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.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 巡检问题表 服务实现类
 *
 * @author qiujinyang
 * @since 2022-08-03
 */
@Service
@Slf4j
public class QuestionServiceImpl extends BaseServiceImpl<QuestionMapper, Question> implements IQuestionService {

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private QuestionTypeMapper questionTypeMapper;

    @Autowired
    private ThMissionMapper missionMapper;

    @Autowired
    private ThInspectionMapper inspectionMapper;

    @Autowired
    private WorkOrderQuestionMapper workOrderQuestionMapper;

    @Autowired
    private IQuestionTypeService questionTypeService;

    @Autowired
    private WarningMapper warningMapper;

    @Autowired
    private IWarningService iWarningService;

    private final static SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    @Transactional(readOnly = true)
    public IPage<QuestionVO> queryPage(QuestionQuery query) throws ParseException {
        if (null == query.getPage() || null == query.getLimit()) {
            throw new ServiceException(ServiceExceptionEnum.PARAMETER_IS_NULL);
        }
        // 获取分页数据
        IPage<Question> page = new Page<>(query.getPage(), query.getLimit());

        LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<Question>()
                .eq(Question::getTenantId, ShiroUtils.getTenantId())//xz
                .eq(ObjectUtil.isNotEmpty(query.getMissionId()), Question::getMissionId, query.getMissionId())
                .like(ObjectUtil.isNotEmpty(query.getName()), Question::getMissionName, query.getName())
                .eq(ObjectUtil.isNotEmpty(query.getType()), Question::getType, query.getType())
                .eq(ObjectUtil.isNotEmpty(query.getStatus()), Question::getStatus, query.getStatus())
                .eq(Question::getMark, MarkTypeEnum.VALID.getCode()).orderByDesc(Question::getCreateTime);
        if (ObjectUtil.isNotEmpty(query.getStartTime()) && ObjectUtil.isNotEmpty(query.getEndTime())) {
            query.setStartTime(query.getStartTime() + " 00:00:00");
            query.setEndTime(query.getEndTime() + " 23:59:59");
            questionLambdaQueryWrapper.between(Question::getCreateTime, dateformat.parse(query.getStartTime()), dateformat.parse(query.getEndTime()));
        }
        IPage<Question> pageData = questionMapper.selectPage(page, questionLambdaQueryWrapper);
        List<Question> questions = pageData.getRecords();
        List<QuestionVO> questionVOList = new ArrayList<>();
        questions.forEach(question -> {
            QuestionVO questionVO = new QuestionVO();
            BeanUtils.copyProperties(question, questionVO);
            LambdaQueryWrapper<WorkOrderQuestion> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(WorkOrderQuestion::getTenantId, question.getTenantId())//xz
                    .eq(WorkOrderQuestion::getQuestionId, question.getId());
            WorkOrderQuestion workOrderQuestion = workOrderQuestionMapper.selectOne(lambdaQueryWrapper);
            if (workOrderQuestion != null) {
                questionVO.setWordOrderStatus(1);
                questionVO.setHandleStatus(workOrderQuestion.getStatus());
            } else {
                questionVO.setWordOrderStatus(0);
                questionVO.setHandleStatus(0);
            }
            questionVOList.add(questionVO);
        });
        IPage<QuestionVO> resultPage = new Page<>();
        resultPage.setCurrent(pageData.getCurrent());
        resultPage.setPages(pageData.getPages());
        resultPage.setSize(pageData.getSize());
        resultPage.setTotal(pageData.getTotal());
        resultPage.setRecords(questionVOList);
        return resultPage;

    }

    @Override
    public List<Question> distributed(QuestionQuery query) {
        List<ThMission> thMissions = missionMapper.selectList(new LambdaQueryWrapper<ThMission>()
                        .eq(ThMission::getTenantId, ShiroUtils.getTenantId())//xz
                        .eq(ThMission::getMark, MarkTypeEnum.VALID.getCode())
                        .in(ThMission::getStatus, Arrays.asList(TaskStatusEnum.FLIGHT.getCode(), TaskStatusEnum.FAIL.getCode(), TaskStatusEnum.COMPLETE.getCode()))
                        .orderByDesc(ThMission::getUpdateTime));
        return getQuestions(query, thMissions);
    }

    private List<Question> getQuestions(QuestionQuery query, List<ThMission> thMissions) {
        if (thMissions.size() == 0) {
            return new ArrayList<>();
        }
        try {
            LambdaQueryWrapper<Question> questionLambdaQueryWrapper = new LambdaQueryWrapper<Question>()
                    .eq(ObjectUtil.isNotEmpty(query.getType()), Question::getType, query.getType())
                    .eq(Question::getStatus, QuestionStatusEnum.CONFIRM.getCode())
                    .eq(Question::getTenantId, ShiroUtils.getTenantId())//xz
                    .eq(Question::getMark, MarkTypeEnum.VALID.getCode()).orderByDesc(Question::getCreateTime);

            if (ObjectUtil.isNotEmpty(query.getStartTime()) && ObjectUtil.isNotEmpty(query.getEndTime())) {
                query.setStartTime(query.getStartTime() + " 00:00:00");
                query.setEndTime(query.getEndTime() + " 23:59:59");
                questionLambdaQueryWrapper.between(Question::getCreateTime, dateformat.parse(query.getStartTime()), dateformat.parse(query.getEndTime()));
            }

            if ((ObjectUtil.isNotEmpty(query.getStartTime()) && ObjectUtil.isNotEmpty(query.getEndTime()))
                    || StringUtils.isNotEmpty(query.getMissionName())) {
                questionLambdaQueryWrapper.like(StringUtils.isNotEmpty(query.getMissionName()), Question::getMissionName, query.getMissionName());
            } else {
                //只需要取最上面的那一条
                questionLambdaQueryWrapper.eq(Question::getMissionId, thMissions.get(0).getId());
            }
            return questionMapper.selectList(questionLambdaQueryWrapper);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("查询出错！");
            return null;
        }
    }

    @Override
    public JsonResult<Boolean> check(QuestionStatusRequest entity) {
        //已经生成工单的问题无法修改
        for (Integer id : entity.getId()) {
            List<WorkOrderQuestion> workOrderQuestions = workOrderQuestionMapper.selectList(new LambdaQueryWrapper<WorkOrderQuestion>()
                            .eq(WorkOrderQuestion::getTenantId, ShiroUtils.getTenantId())//xz
                            .eq(WorkOrderQuestion::getQuestionId, id));
            if (StringUtils.isNotEmpty(workOrderQuestions)) {
                return JsonResult.error("问题已生成工单，无法修改！");
            }
        }


        //根据ID的数量来判断是否是批量确认和忽略
        Question question = new Question(UpdateOrCreateEnum.UPDATE.getCode());
        question.setStatus(entity.getStatus());
        int update;
        Integer qId;
        if (entity.getId().length > 1) {
            qId = entity.getId()[0];
            //批量
            update = questionMapper.update(question, new LambdaUpdateWrapper<Question>().in(Question::getId, Arrays.asList(entity.getId())));
        } else {
            //查询巡检问题分类
            List<QuestionType> questionTypeList = questionTypeMapper.selectList(new LambdaQueryWrapper<QuestionType>()
                    .eq(QuestionType::getCode, entity.getType())
                    .eq(QuestionType::getMark, 1));
            if (StringUtils.isNotEmpty(questionTypeList)) {
                question.setQuestionName(questionTypeList.get(0).getContent());
                question.setQuestionDesc(questionTypeList.get(0).getContent());
            }
            //单个
            qId = entity.getId()[0];
            question.setId(qId);
            question.setType(entity.getType());
            update = questionMapper.updateById(question);
        }

        Integer missionId = questionMapper.selectById(qId).getMissionId();
        ThMission thMission = new ThMission(UpdateOrCreateEnum.UPDATE.getCode());
        thMission.setReportStatus(ReportStatusEnum.UPDATE.getCode());
        thMission.setId(missionId);
        missionMapper.updateById(thMission);


        return JsonResult.success(update > 0);
    }

    @Override
    public JsonResult<List<QuestionCountVO>> analyze(Integer missionId) {
        List<QuestionCountVO> resultMap = questionMapper.analyze(missionId, ShiroUtils.getTenantId());
        return JsonResult.success(resultMap);
    }

    @Override
    public JsonResult<Map<String, Integer>> analyzeController(Integer missionId) {
        List<QuestionCountVO> questionCountVoList = questionMapper.analyze(missionId, ShiroUtils.getTenantId());
        Map<String, Integer> resultMap = new HashMap<>();
        for (QuestionCountVO questionCountVo : questionCountVoList) {
            setInfo(resultMap, questionCountVo, QuestionStatusEnum.CONFIRM.getCode(), QuestionStatusEnum.CONFIRM.name().toLowerCase());
            setInfo(resultMap, questionCountVo, QuestionStatusEnum.NEGLECT.getCode(), QuestionStatusEnum.NEGLECT.name().toLowerCase());
            setInfo(resultMap, questionCountVo, QuestionStatusEnum.NOTREVIEWED.getCode(), QuestionStatusEnum.NOTREVIEWED.name().toLowerCase());
        }
        int sum = 0;
        if (!resultMap.containsKey(QuestionStatusEnum.CONFIRM.name().toLowerCase())) {
            resultMap.put(QuestionStatusEnum.CONFIRM.name().toLowerCase(), 0);
        } else {
            sum += resultMap.get(QuestionStatusEnum.CONFIRM.name().toLowerCase());
        }

        if (!resultMap.containsKey(QuestionStatusEnum.NEGLECT.name().toLowerCase())) {
            resultMap.put(QuestionStatusEnum.NEGLECT.name().toLowerCase(), 0);
        } else {
            sum += resultMap.get(QuestionStatusEnum.NEGLECT.name().toLowerCase());
        }
        resultMap.remove(QuestionStatusEnum.NEGLECT.name().toLowerCase());
        resultMap.put(QuestionStatusEnum.CONFIRM.name().toLowerCase(), sum);

        if (!resultMap.containsKey(QuestionStatusEnum.NOTREVIEWED.name().toLowerCase())) {
            resultMap.put(QuestionStatusEnum.NOTREVIEWED.name().toLowerCase(), 0);
        }
        return JsonResult.success(resultMap);
    }

    private static void setInfo(Map<String, Integer> resultMap, QuestionCountVO questionCountVo, Integer code, String name) {
        if (questionCountVo.getStatus().equals(code)) {
            if (resultMap.containsKey(name)) {
                Integer current = resultMap.get(name);
                current = current + questionCountVo.getQuantity();
                resultMap.put(name, current);
            } else {
                resultMap.put(name, questionCountVo.getQuantity());
            }
        }
    }

    @Override
    public JsonResult<List<QuestionTypeCountVO>> analyzeType(Integer missionId) {
        List<QuestionTypeCountVO> questionTypeCountList = questionMapper.analyzeType
                (missionId, ShiroUtils.getTenantId());

        //id
        //name
        //code
        //type
        //content

        //添加问题的分类
        List<QuestionType> questionTypeList = new ArrayList<>();
        try {
            questionTypeList = questionTypeService.getQuestionType();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Map<String, String> codeMap = new HashMap<>();
        for (QuestionType questionType : questionTypeList) {
            codeMap.put(questionType.getCode(), questionType.getContent());
        }
        for (QuestionTypeCountVO questionTypeCountVO : questionTypeCountList) {
            questionTypeCountVO.setContent(codeMap.get(questionTypeCountVO.getType()));
        }
        return JsonResult.success(questionTypeCountList);
    }

    @Override
    public JsonResult process(String requestId, CallbackRequest callbackRequest) throws ServiceException {

        ThMission mission = getThMission(requestId);
        Boolean aBoolean = saveQuestion(callbackRequest, mission);
        //如果任务已经完成就修改任务状态
        ThMission thMissionUpdate = new ThMission(UpdateOrCreateEnum.UPDATE.getCode());

        thMissionUpdate.setProgressbar(callbackRequest.getProgress());
        if (aBoolean) {
            setComplate(callbackRequest, mission, thMissionUpdate);
        } else {
            setTaskStatusEnum(thMissionUpdate, TaskStatusEnum.FAIL, mission);
        }
        return JsonResult.success();
    }

    private void setTaskStatusEnum(ThMission thMissionUpdate, TaskStatusEnum statusEnum, ThMission mission) {
        thMissionUpdate.setStatus(statusEnum.getCode());
        thMissionUpdate.setId(mission.getId());
        thMissionUpdate.setExecutionEndTime(new Date());
        missionMapper.updateById(thMissionUpdate);
    }

    private void setComplate(CallbackRequest callbackRequest, ThMission mission, 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());
            }

            setTaskStatusEnum(thMissionUpdate, TaskStatusEnum.COMPLETE, mission);
        } else if (callbackRequest.getAnalyseStatus() == AiAnalyseStatusEnum.FAILED.getCode()) {
            setTaskStatusEnum(thMissionUpdate, TaskStatusEnum.FAIL, mission);
        } else {
            thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.RUNNING.getCode());
            setTaskStatusEnum(thMissionUpdate, TaskStatusEnum.FLIGHT, mission);
        }

    }

    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 =  this.saveBatch(questionList);
        //保存问题数据时调用saveWarningData方法保存预警数据入库
        this.saveWarningData(questionList);
        log.info("预警表数据入库结束, {}", flag);
        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.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);
                }
                warningList.add(warning);
            }
        }
        return iWarningService.saveBatch(warningList);
    }

    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) {
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(), "正在执行的任务不存在！");
        }
        return thMissions.get(0);
    }


    /**
     * 获取飞行坐标
     *
     * @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);
    }

}
