package com.tuoheng.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
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.MissionRequest;
import com.tuoheng.admin.entity.request.MissionQuery;
import com.tuoheng.admin.entity.request.MissionStatusRequest;
import com.tuoheng.admin.entity.vo.AirWeatherVO;
import com.tuoheng.admin.entity.vo.MissionLiveVO;
import com.tuoheng.admin.entity.vo.MissionVO;
import com.tuoheng.admin.enums.*;
import com.tuoheng.admin.mapper.*;
import com.tuoheng.admin.service.IDspService;
import com.tuoheng.admin.service.IMissionService;
import com.tuoheng.admin.service.IThInspectionService;
import com.tuoheng.admin.utils.CodeUtil;
import com.tuoheng.admin.utils.TimeUtil;
import com.tuoheng.admin.utils.WeatherUtil;
import com.tuoheng.common.common.BaseServiceImpl;
import com.tuoheng.common.common.OperationEnum;
import com.tuoheng.common.config.CommonConfig;
import com.tuoheng.common.exception.ServiceException;
import com.tuoheng.common.utils.*;
import com.tuoheng.system.entity.User;
import com.tuoheng.system.mapper.UserMapper;
import com.tuoheng.system.utils.ShiroUtils;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;

/**
 * 巡检任务接口实现
 *
 * @author: qiujinyang
 * @date: 2022/8/3
 */
@Service
@Slf4j
public class MissionServiceImpl extends BaseServiceImpl<ThMissionMapper, ThMission> implements IMissionService {

    @Autowired
    private ThMissionMapper thMissionMapper;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private ThInspectionMapper inspectionMapper;

    @Autowired
    private ReportMapper reportMapper;

    @Autowired
    private IDspService dspService;

    @Autowired
    private UserMapper userMapper;

    @Resource
    @Lazy
    private IThInspectionService inspectionService;

    @Value("${tuoheng.dsp-callback-url:}")
    private String dspCallbackUrl;


    @Override
    public Integer addMission(MissionRequest addThMissionRequest) throws ServiceException {

        ThMission tm=new ThMission(UpdateOrCreateEnum.CREATE.getCode());
        tm.setCreateUser(ShiroUtils.getUserId());
        tm.setUpdateUser(ShiroUtils.getUserId());
        BeanUtils.copyProperties(addThMissionRequest,tm);

        //任务名称不能重复
        List<ThMission> thMissions = thMissionMapper.selectList(new LambdaQueryWrapper<ThMission>().eq(ThMission::getName, addThMissionRequest.getName())
                .eq(ThMission::getMark, MarkTypeEnum.VALID.getCode()));

        if(thMissions.size()>0){
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(),"任务名称不能重复!");
        }

        // 根据当前时间，生成任务编码
        String code = "XJRW" +CodeUtil.createCodeNo();
        tm.setCode(code);
        tm.setReportStatus(ReportStatusEnum.GENERATE.getCode());
        thMissionMapper.insert(tm);
        return tm.getId();
    }


    @Override
    public List<ThMission> getList(LambdaQueryWrapper<ThMission> lambdaQueryWrapper) {
        return thMissionMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public boolean updateStatus(MissionStatusRequest missionStatusRequest) throws ServiceException {

        //如果发送过来的状态是执行中，那么就说明之前是待执行，查询等待执行的数据，开始飞行
        if(AirPortTaskStatusEnum.FLIGHT.getCode()==missionStatusRequest.getStatus()){
            ThMission thMission = getRecentlyRecord(missionStatusRequest,TaskStatusEnum.WAIT.getCode());
            Assert.notNull(thMission, "飞行任务不能为空！");
            ThMission thMissionUpdate = setStatus(missionStatusRequest, thMission,AirPortTaskStatusEnum.FLIGHT);
            //开始分析
            try {
                JSONObject jsonObject  = startAI(missionStatusRequest);
                thMissionUpdate.setRequestId(jsonObject.getJSONObject("data").getString("requestId"));
                thMissionUpdate.setAipullUrl(jsonObject.getJSONObject("data").getString("aipullUrl"));
                thMissionUpdate.setAipushUrl(jsonObject.getJSONObject("data").getString("aipushUrl"));
                thMissionUpdate.setPlayUrl(jsonObject.getJSONObject("data").getString("playUrl"));
                thMissionUpdate.setAiplayUrl(jsonObject.getJSONObject("data").getString("aiplayUrl"));
                thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.WAITING.getCode());
            }catch (ServiceException e){
                //如果调用DSP失败就直接失败！
                log.error("调用DSP数据失败：{}",e.getMessage());
                thMissionUpdate.setStatus(TaskStatusEnum.FAIL.getCode());
                thMissionMapper.updateById(thMissionUpdate);
                throw new ServiceException(HttpStatus.BAD_REQUEST.value(),"任务分析失败！");
            }
            log.info("修改飞行状态：{}",JSONObject.toJSONString(thMissionUpdate));
            return thMissionMapper.updateById(thMissionUpdate) > 0;
        }else if(AirPortTaskStatusEnum.WAIT.getCode()==missionStatusRequest.getStatus()){
            //硬件停止后，停止AI分析
            return stopAI(missionStatusRequest);
        }else{
            throw new ServiceException(ServiceExceptionEnum.TASK_NOT_STATUS);
        }
    }

    private JSONObject startAI(MissionStatusRequest missionStatusRequest) throws ServiceException {
        //任务调用完成之后，调用发送通道，请求DSP需要分析
        //调用DSP接口
        JSONObject request = new JSONObject();
        JSONArray configList = new JSONArray();
        JSONObject instConfigMode = new JSONObject();
        instConfigMode.put("ename","service_mode");
        instConfigMode.put("evalue","1");
        configList.add(instConfigMode);
        JSONObject instConfigUrl = new JSONObject();
        instConfigUrl.put("ename","callback_url");
        instConfigUrl.put("evalue",dspCallbackUrl);
        configList.add(instConfigUrl);
        request.put("serviceInstConfigList",configList);

        JSONArray reqList = new JSONArray();

        JSONObject instReqUrlPush = new JSONObject();
        instReqUrlPush.put("ename","push_url");
        instReqUrlPush.put("evalue", missionStatusRequest.getPushUrl());
        reqList.add(instReqUrlPush);

        JSONObject instReqUrlPull = new JSONObject();
        instReqUrlPull.put("ename","pull_url");
        instReqUrlPull.put("evalue", missionStatusRequest.getPullUrl());
        reqList.add(instReqUrlPull);

        request.put("serviceInstReqList", reqList);
        JSONObject responseJson = dspService.serviceInstApplication(request);
        if(responseJson.getIntValue("code") == 0){
            String requestId = responseJson.getJSONObject("data").getString("requestId");
            log.info("dsp实时调用响应requestId：{}",requestId);

        }else {
            log.error("dsp实时调用失败：{}", responseJson);
            throw new ServiceException(HttpStatus.BAD_REQUEST.value(),"任务失败！");
        }
        return responseJson;
    }

    private Boolean stopAI(MissionStatusRequest missionStatusRequest) {
        ThMission thMission = getRecentlyRecord(missionStatusRequest,TaskStatusEnum.FLIGHT.getCode());
        Assert.notNull(thMission, "飞行任务不能为空！");
        ThMission thMissionUpdate = new ThMission(UpdateOrCreateEnum.UPDATE.getCode());

        thMissionUpdate.setId(thMission.getId());
        thMissionUpdate.setMileage(missionStatusRequest.getMileage());
        boolean result=false;
        try {
            AirWeatherVO weather = inspectionService.getWeather(thMission.getAirportId());
            String weatherStr = WeatherUtil.getWeather(weather);
            thMissionUpdate.setWeather(weatherStr);
        }catch (Exception e){
            thMissionUpdate.setWeather("");
            log.info("获取天气信息失败，请重试");
        }

        //任务调用完成之后，调用发送通道，请求DSP关闭请求
        //调用DSP接口
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("requestId",thMission.getRequestId());
        JSONObject responseJson=new JSONObject();
        try {
            responseJson = dspService.serviceStopApplication(jsonObject);
            if(responseJson.getIntValue("code") == 0){
                if(responseJson.containsKey("data") && ObjectUtil.isNotEmpty(responseJson.get("data"))) {
                    String requestId = responseJson.getJSONObject("data").getString("requestId");
                    log.info("dsp实时调用响应requestId：{}", requestId);
                }else{
                    log.info("dsp实时调用响应:{}",responseJson);
                }
                result=true;
            }else {
                log.error("dsp实时调用失败：{}", responseJson);
                thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.FAILED.getCode());
            }
            thMissionMapper.updateById(thMissionUpdate);
        }catch (Exception e){
            log.error("dsp实时调用失败：{}", responseJson);
            thMissionUpdate.setAnalyseStatus(AiAnalyseStatusEnum.FAILED.getCode());
            thMissionMapper.updateById(thMissionUpdate);
        }

        return result;
    }

    private ThMission setStatus(MissionStatusRequest missionStatusRequest, ThMission thMission,AirPortTaskStatusEnum airPortTaskStatusEnum) {
        ThMission thMissionUpdate = new ThMission(UpdateOrCreateEnum.UPDATE.getCode());
        thMissionUpdate.setId(thMission.getId());
        if(missionStatusRequest.getStatus()==AirPortTaskStatusEnum.FLIGHT.getCode() && airPortTaskStatusEnum.getCode()==AirPortTaskStatusEnum.FLIGHT.getCode()) {
            thMissionUpdate.setPushUrl(missionStatusRequest.getPushUrl());
            thMissionUpdate.setPullUrl(missionStatusRequest.getPullUrl());
            thMissionUpdate.setStatus(TaskStatusEnum.FLIGHT.getCode());
        }
        return thMissionUpdate;
    }

    private ThMission getRecentlyRecord(MissionStatusRequest missionStatusRequest,Integer status) {
        //获取当前任务里面这个巡检的最近的那一条,修改对应的任务的状态
        LambdaQueryWrapper<ThMission> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.orderByAsc(ThMission::getExecutionStartTime);
        lambdaQueryWrapper.eq(ThMission::getInspectionLine, missionStatusRequest.getId());
        lambdaQueryWrapper.eq(ThMission::getStatus,status);
        //lambdaQueryWrapper.eq(ThMission::getTenantId,ShiroUtils.getTenantId());
        List<ThMission> thMissions = thMissionMapper.selectList(lambdaQueryWrapper);
        return thMissions.size()>0? thMissions.get(0) : null;
    }

    @Override
    public IPage<MissionVO> findList(MissionQuery queryInspectionRequest) {
        Page<ThMission> page = new Page<>();
        page.setSize(queryInspectionRequest.getLimit());
        page.setCurrent(queryInspectionRequest.getPage());
        queryInspectionRequest.setTenantId(ShiroUtils.getTenantId());
        LambdaQueryWrapper<ThMission> queryMission=new LambdaQueryWrapper<>();
        queryParam(queryInspectionRequest, queryMission);
        queryMission.eq(ThMission::getMark,MarkTypeEnum.VALID.getCode()).orderByDesc(ThMission::getCreateTime);

        IPage<ThMission> thMissionIPage = thMissionMapper.selectPage(page, queryMission);
        List<ThMission> records = thMissionIPage.getRecords();

        Map<Integer, String> userName = getUserNameMap(records);
        List<MissionVO> result=new ArrayList<>();
        records.forEach(mission->{
            MissionVO missionVO=new MissionVO();
            BeanUtils.copyProperties(mission,missionVO);

            //获取最后一次的飞行时间
            getFlyTime(mission, missionVO);
            missionVO.setCreateUser(userName.get(mission.getCreateUser()));
            result.add(missionVO);
        });

        IPage<MissionVO> resultPage=new Page<>();
        resultPage.setCurrent(thMissionIPage.getCurrent());
        resultPage.setPages(thMissionIPage.getPages());
        resultPage.setSize(thMissionIPage.getSize());
        resultPage.setTotal(thMissionIPage.getTotal());
        resultPage.setRecords(result);
        return resultPage;
    }

    private void getFlyTime(ThMission mission, MissionVO missionVO) {
        if(missionVO.getStatus().equals(TaskStatusEnum.COMPLETE.getCode()) || missionVO.getStatus().equals(TaskStatusEnum.FLIGHT.getCode())) {
            LambdaQueryWrapper<ThInspection> lambdaInspection = new LambdaQueryWrapper<>();
            lambdaInspection.eq(ThInspection::getMissionId, mission.getId());
            lambdaInspection.eq(ThInspection::getMark, MarkTypeEnum.VALID.getCode()).orderByDesc(ThInspection::getCreateTime);
            List<ThInspection> thInspections = inspectionMapper.selectList(lambdaInspection);
            if (ObjectUtil.isNotEmpty(thInspections) && thInspections.size() > 0) {
                ThInspection temp = thInspections.get(0);
                missionVO.setFlyTime(TimeUtil.getFormatFlyTime(temp.getFlyTime() * 1000));
            }
        }
    }

    private Map<Integer, String> getUserNameMap(List<ThMission> records) {
        if(records.size()==0){
            return new HashMap<>();
        }
        Map<Integer,String> userName=new HashMap<>();
        Set<Integer> userId=new HashSet<>();
        records.forEach(thMission -> {
            userId.add(thMission.getCreateUser());
        });

        List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>().in(User::getId, userId));
        for (User user : users) {
            userName.put(user.getId(),user.getRealname());
        }
        return userName;
    }

    private void queryParam(MissionQuery queryInspectionRequest, LambdaQueryWrapper<ThMission> queryInspection) {
        //编号
        queryInspection.like(StringUtils.isNotEmpty(queryInspectionRequest.getCode()),ThMission::getCode, queryInspectionRequest.getCode());
        //任务名称
        queryInspection.like(StringUtils.isNotEmpty(queryInspectionRequest.getName()),ThMission::getName, queryInspectionRequest.getName());
        //任务类型
        queryInspection.like(ObjectUtil.isNotEmpty(queryInspectionRequest.getType()),ThMission::getType, queryInspectionRequest.getType());
        //任务状态
        queryInspection.eq(ObjectUtil.isNotEmpty(queryInspectionRequest.getStatus()),ThMission::getStatus, queryInspectionRequest.getStatus());
        //巡检机场
        queryInspection.eq(ObjectUtil.isNotEmpty(queryInspectionRequest.getAirportId()),ThMission::getAirportId, queryInspectionRequest.getAirportId());
        //巡检线路
        queryInspection.eq(ObjectUtil.isNotEmpty(queryInspectionRequest.getInspectionLine()),ThMission::getInspectionLine, queryInspectionRequest.getInspectionLine());
        //巡检类型
        //queryInspection.eq(ObjectUtil.isNotEmpty(queryInspectionRequest.getInspectionType()),ThMission::getInspectionType, queryInspectionRequest.getInspectionType());
    }

    @Override
    public MissionVO findById(Integer id) {
        MissionVO missionVO=new MissionVO();
       BeanUtils.copyProperties(thMissionMapper.selectById(id),missionVO);
        return missionVO;
    }


    @Override
    public boolean deleteBatch(List<Integer> idList) {
        //Integer updateUser = ShiroUtils.getUserId();
        ThMission mission=new ThMission(UpdateOrCreateEnum.UPDATE.getCode());
        mission.setMark(MarkTypeEnum.NOTVALID.getCode());
        boolean result=false;
        if(thMissionMapper.update(mission,new LambdaUpdateWrapper<ThMission>().in(ThMission::getId,idList))>0){
            Integer missionId = mission.getId();
            questionMapper.delete(new LambdaQueryWrapper<Question>().eq(Question::getMissionId,missionId));
            inspectionMapper.delete(new LambdaQueryWrapper<ThInspection>().eq(ThInspection::getMissionId,missionId));
            reportMapper.delete(new LambdaQueryWrapper<Report>().eq(Report::getMissionId,missionId));
            result=true;
        }
        return result;
    }

    @Override
    public MissionLiveVO live(Integer id) {
        //根据机场的Id查询出来直播的对象
        LambdaQueryWrapper<ThMission> lambdaQueryWrapper=new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(ThMission::getMark,MarkTypeEnum.VALID.getCode());
        lambdaQueryWrapper.eq(ThMission::getAirportId,id);
        lambdaQueryWrapper.eq(ThMission::getStatus,TaskStatusEnum.FLIGHT.getCode()).orderByDesc(ThMission::getExecutionStartTime);
        List<ThMission> thMissions = thMissionMapper.selectList(lambdaQueryWrapper);
        //一般不会出现多条，如果出现，就说明有问题，应该取最后执行的那一条
        ThMission thMission= ObjectUtil.isEmpty(thMissions)? null :thMissions.get(0);
        MissionLiveVO missionLiveVO=null;
        if(ObjectUtil.isNotEmpty(thMission)){
            missionLiveVO=new MissionLiveVO();
            BeanUtils.copyProperties(thMission,missionLiveVO);
        }
        return missionLiveVO;
    }

}