package com.ruoyi.dj.controller;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.dj.mqtt.client.DJICloudMQTTClient;
import com.ruoyi.dj.mqtt.cmd.CmdConstant;
import com.ruoyi.dj.mqtt.common.CommonFieldsVo;
import com.ruoyi.dj.mqtt.dto.*;
import com.ruoyi.dj.mqtt.utils.GatewayOperationLogUtil;
import com.ruoyi.dj.mqtt.utils.HandleResultUtil;
import com.ruoyi.dj.mqtt.utils.PayloadUtil;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.dto.MissionsDto;
import com.ruoyi.system.dto.MissionsListDto;
import com.ruoyi.system.service.IFlightPathsService;
import com.ruoyi.system.service.IMissionsService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

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

/**
 * @auther 周志雄
 * @date 2024/9/14 14:48
 */
@Slf4j
@RestController
@Api(tags = "新航线任务相关")
@RequestMapping("/dj/task")
public class NewTaskController extends BaseController {
    private static final String SERVICES_TOPIC = "thing/product/?/services";
    @Resource
    private DJICloudMQTTClient djiCloudMQTTClient;
    @Resource
    private IMissionsService missionsService;
    @Resource
    private IFlightPathsService flightPathsService;

    @PostMapping("/add")
    @ApiOperation("添加任务")
    public AjaxResult add(@RequestBody Missions missions) {
        // 获取文件ID
        String fileId = missions.getFileId();

        // 查询数据
        FlightPaths flightPaths = flightPathsService.selectFlightPathsById(Long.valueOf(fileId));
        // 如果没有文件、则返回错误
        if (flightPaths != null && flightPaths.getFileUrl() == null) {
            return AjaxResult.error("请先在航线绘制内容");
        }
        if (missions.getType() == 1) {
            missions.setState("定时待执行");
        }
        // 任务有效
        missions.setFlag(1);
        // 新增数据到数据库
        missions.setCreatedAt(new Date());
        missionsService.insertMissions(missions);

        // 处理业务数据、如果是立即任务则下发并执行
        if (missions.getType() == 0) {
            // TODO 下发任务
            Map<String, String> map = flightTaskPrepare(missions);
            String flightId = map.get("flightId");
            String taskId = map.get("taskId");

            // TODO 执行任务
            FlightTaskExecuteDto flightTaskExecuteDto = new FlightTaskExecuteDto();
            flightTaskExecuteDto.setFlightId(flightId);
            flightTaskExecuteDto.setGateway(missions.getGateway());
            flightTaskExecuteDto.setTaskId(Long.valueOf(taskId));
            return executeTask(flightTaskExecuteDto);
        }
        return AjaxResult.success();
    }

    @PostMapping("/cancel")
    @ApiOperation("挂起任务")
    public AjaxResult cancel(String missionId) {
        Missions missions = new Missions();
        missions.setId(Long.valueOf(missionId));
        missions.setFlag(0);
        missionsService.updateMissions(missions);
        return AjaxResult.success();
    }

    @GetMapping("/list")
    @ApiOperation("任务列表")
    public TableDataInfo list(MissionsListDto missionListDto) {
        startPage();
        // 获取所有符合条件的任务
        List<MissionsDto> missionsList = missionsService.list(missionListDto);
        return getDataTable(missionsList);
    }

    @GetMapping("/getLatest")
    @ApiOperation("获取最新任务信息")
    public AjaxResult getLatest(String gateway) {
        // 获取所有符合条件的任务
        MissionsDto missionsDto = missionsService.getLatest(gateway);
        return AjaxResult.success(missionsDto);
    }


    /**
     * 取消任务
     *
     * @return
     */
    @ApiOperation("取消任务")
    @PostMapping("/flightTaskUndo")
    public AjaxResult flightTaskUndo(@RequestBody FlightTaskUndoDto flightTaskUndoDto) {
        String topic = SERVICES_TOPIC.replace("?", flightTaskUndoDto.getGateway());
        CommonFieldsVo commonFieldVo = CommonFieldsVo.createCommonFieldVo(CmdConstant.FLIGHTTASK_UNDO, flightTaskUndoDto.getGateway());
        // 构造参数
        Map<String, Object> map = new HashMap<>();
        map.put("flight_ids", flightTaskUndoDto.getFlightIds());
        String payload = PayloadUtil.generatePayload(commonFieldVo, map);
        log.info("取消航线请求数据：{}", payload);
        String response = djiCloudMQTTClient.publishMessage(topic, payload, commonFieldVo);
        // 记录操作日志
        GatewayOperationLogUtil.generateLog(flightTaskUndoDto.getGateway(), CmdConstant.FLIGHTTASK_UNDO, payload, response);
        return HandleResultUtil.handleResult(response, null, "取消任务成功");
    }

    /**
     * 暂停任务
     *
     * @return
     */
    @ApiOperation("暂停任务")
    @PostMapping("/flightTaskPause")
    public AjaxResult flightTaskPause(@RequestBody FlightTaskPauseDto flightTaskPauseDto) {
        String topic = SERVICES_TOPIC.replace("?", flightTaskPauseDto.getGateway());
        CommonFieldsVo commonFieldVo = CommonFieldsVo.createCommonFieldVo(CmdConstant.FLIGHTTASK_PAUSE, flightTaskPauseDto.getGateway());
        String payload = PayloadUtil.generatePayload(commonFieldVo, null);
        log.info("暂停航线请求数据：{}", payload);
        String response = djiCloudMQTTClient.publishMessage(topic, payload, commonFieldVo);
        // 记录操作日志
        GatewayOperationLogUtil.generateLog(flightTaskPauseDto.getGateway(), CmdConstant.FLIGHTTASK_PAUSE, payload, response);
        return HandleResultUtil.handleResult(response, null, "暂停任务成功");
    }

    /**
     * 航线恢复
     *
     * @return
     */
    @ApiOperation("航线恢复")
    @PostMapping("/flightTaskRecovery")
    public AjaxResult flightTaskRecovery(@RequestBody FlightTaskRecoveryDto flightTaskRecoveryDto) {
        String topic = SERVICES_TOPIC.replace("?", flightTaskRecoveryDto.getGateway());
        CommonFieldsVo commonFieldVo = CommonFieldsVo.createCommonFieldVo(CmdConstant.FLIGHTTASK_RECOVERY, flightTaskRecoveryDto.getGateway());
        String payload = PayloadUtil.generatePayload(commonFieldVo, null);
        log.info("恢复航线请求数据：{}", payload);
        String response = djiCloudMQTTClient.publishMessage(topic, payload, commonFieldVo);
        // 记录操作日志
        GatewayOperationLogUtil.generateLog(flightTaskRecoveryDto.getGateway(), CmdConstant.FLIGHTTASK_RECOVERY, payload, response);
        return HandleResultUtil.handleResult(response, null, "航线恢复成功");
    }

    /**
     * 一键返航
     *
     * @return
     */
    @ApiOperation("一键返航")
    @PostMapping("/returnHome")
    public AjaxResult returnHome(@RequestBody ReturnHomeDto returnHomeDto) {
        String topic = SERVICES_TOPIC.replace("?", returnHomeDto.getGateway());
        CommonFieldsVo commonFieldVo = CommonFieldsVo.createCommonFieldVo(CmdConstant.RETURN_HOME, returnHomeDto.getGateway());
        String payload = PayloadUtil.generatePayload(commonFieldVo, null);
        log.info("一键返航请求数据：{}", payload);
        String response = djiCloudMQTTClient.publishMessage(topic, payload, commonFieldVo);
        // 记录操作日志
        GatewayOperationLogUtil.generateLog(returnHomeDto.getGateway(), CmdConstant.RETURN_HOME, payload, response);
        return HandleResultUtil.handleResult(response, null, "一键返航成功");
    }

    /**
     * 下发任务
     *
     * @param missions
     * @return
     */
    public Map<String, String> flightTaskPrepare(Missions missions) {
        HashMap<String, String> hashMap = new HashMap<>();
        String topic = SERVICES_TOPIC.replace("?", missions.getGateway());
        CommonFieldsVo commonFieldVo = CommonFieldsVo.createCommonFieldVo(CmdConstant.FLIGHTTASK_PREPARE, missions.getGateway());
        // 先生成一个随机的数字字符串作为任务ID
        String flightId = String.valueOf((int) (Math.random() * 900000) + 100000);
        // 把任务对象转化为 FlightTaskParam 参数、便于构建下发任务的 JSON 参数
        String fileId = missions.getFileId();
        FlightPaths flightPaths = flightPathsService.selectFlightPathsById(Long.valueOf(fileId));
        FlightTaskParam flightTaskParam = getFlightTaskParam(missions, flightId, flightPaths);
        flightTaskParam.setTaskType(missions.getType());
        // 设置执行时间为当前时间戳
        flightTaskParam.setExecuteTime(missions.getTimeStamp());
        Map<String, Object> map = convertDtoToMap(flightTaskParam);
        String payload = PayloadUtil.generatePayload(commonFieldVo, map);
        String response = djiCloudMQTTClient.publishMessage(topic, payload, commonFieldVo);
        // 记录操作日志
        GatewayOperationLogUtil.generateLog(missions.getGateway(), CmdConstant.FLIGHTTASK_PREPARE, payload, response);
        ObjectMapper objectMapper = new ObjectMapper();
        // 将字符串解析为 JSON 对象
        JsonNode resultNode = null;
        try {
            ObjectNode jsonNode = null;
            jsonNode = (ObjectNode) objectMapper.readTree(response);
            resultNode = jsonNode.path("data").path("result");
            Integer result = Integer.valueOf(resultNode.asText());
            if (result == 0) {
                // 执行指令没有出错则更新下发任务数据到数据库
                missions.setFlightId(Long.valueOf(flightId));
                missions.setState("待执行");
                missionsService.updateMissions(missions);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        // 返回任务ID
        hashMap.put("flightId", flightId);
        hashMap.put("taskId", missions.getId().toString());
        return hashMap;
    }

    /**
     * 根据droneMissions获取FlightTaskParam
     *
     * @param droneMissions
     * @return
     */
    private static FlightTaskParam getFlightTaskParam(Missions droneMissions, String flightId, FlightPaths flightPaths) {
        FlightTaskParam flightTaskParam = new FlightTaskParam();
        // 设置计划ID
        flightTaskParam.setFlightId(flightId.toString());
        // 创建航线文件对象
        FlightTaskParam.File file = new FlightTaskParam.File();
        // 设置航线文件MD5
        file.setFingerprint(flightPaths.getFileMd5());
        // 设置航线文件URL
        file.setUrl(flightPaths.getFileUrl());
        // 设置文件信息
        flightTaskParam.setFile(file);
        // 设置返航高度
        flightTaskParam.setRthAltitude(Integer.valueOf(droneMissions.getReturnAltitude().toString()));
        // 设置返航高度模式
        flightTaskParam.setRthMode(Integer.valueOf(droneMissions.getReturnAltitudeMode().toString()));
        // 设置遥控器失控类型
        flightTaskParam.setOutOfControlAction(Integer.valueOf(droneMissions.getOutOfControlAction().toString()));
        // 设置航线失控动作
        flightTaskParam.setExitWaylineWhenRcLost(Integer.valueOf(droneMissions.getFlightControlAction().toString()));
        // 设置航线精度类型
        flightTaskParam.setWaylinePrecisionType(Integer.valueOf(droneMissions.getWaylinePrecisionType().toString()));
        log.info("构造航线下发的参数：{}", flightTaskParam);
        return flightTaskParam;
    }

    /**
     * 构造航线下发的参数
     *
     * @param flightTaskParam
     * @return
     */
    private Map<String, Object> convertDtoToMap(FlightTaskParam flightTaskParam) {
        Map<String, Object> dataMap = new HashMap<>();

        // 如果断点信息不为空，则加入到 Map
        if (flightTaskParam.getBreakPoint() != null) {
            dataMap.put("break_point", flightTaskParam.getBreakPoint());
        }
        // 如果执行条件不为空，则加入到 Map
        if (flightTaskParam.getExecutableConditions() != null) {
            dataMap.put("executable_conditions", flightTaskParam.getExecutableConditions());
        }
        // 如果有指定任务执行时间，则加入到 Map
        if (flightTaskParam.getExecuteTime() != null) {
            dataMap.put("execute_time", flightTaskParam.getExecuteTime());
        }
        // 如果文件信息不为空，则加入到 Map
        if (flightTaskParam.getFile() != null) {
            dataMap.put("file", flightTaskParam.getFile());
        }
        // 如果有计划 ID，则加入到 Map
        if (flightTaskParam.getFlightId() != null) {
            dataMap.put("flight_id", flightTaskParam.getFlightId());
        }
        // 如果有定义遥控器失控动作，则加入到 Map
        if (flightTaskParam.getOutOfControlAction() != null) {
            dataMap.put("out_of_control_action", flightTaskParam.getOutOfControlAction());
        }
        // 如果有就绪条件，则加入到 Map
        if (flightTaskParam.getReadyConditions() != null) {
            dataMap.put("ready_conditions", flightTaskParam.getReadyConditions());
        }
        // 如果模拟任务不为空，则加入到 Map
        if (flightTaskParam.getSimulateMission() != null) {
            dataMap.put("simulate_mission", flightTaskParam.getSimulateMission());
        }
        // 如果有返航高度，则加入到 Map
        if (flightTaskParam.getRthAltitude() != null) {
            dataMap.put("rth_altitude", flightTaskParam.getRthAltitude());
        }
        // 如果有返航高度模式，则加入到 Map
        if (flightTaskParam.getRthMode() != null) {
            dataMap.put("rth_mode", flightTaskParam.getRthMode());
        }
        // 如果有航线失控动作，则加入到 Map
        if (flightTaskParam.getExitWaylineWhenRcLost() != null) {
            dataMap.put("exit_wayline_when_rc_lost", flightTaskParam.getExitWaylineWhenRcLost());
        }
        // 如果有航线类型，则加入到 Map
        if (flightTaskParam.getTaskType() != null) {
            dataMap.put("task_type", flightTaskParam.getTaskType());
        }
        // 任务类型和航线精度类型始终加入到 Map，因为它们为基础属性
        dataMap.put("task_type", flightTaskParam.getTaskType());
        dataMap.put("wayline_precision_type", flightTaskParam.getWaylinePrecisionType());

        return dataMap;
    }

    /**
     * 执行任务
     *
     * @param flightTaskExecuteDto
     * @return
     */
    public AjaxResult executeTask(FlightTaskExecuteDto flightTaskExecuteDto) {
        String topic = SERVICES_TOPIC.replace("?", flightTaskExecuteDto.getGateway());
        CommonFieldsVo commonFieldVo = CommonFieldsVo.createCommonFieldVo(CmdConstant.FLIGHTTASK_EXECUTE, flightTaskExecuteDto.getGateway());
        // 构造参数
        Map<String, Object> map = new HashMap<>();
        map.put("flight_id", flightTaskExecuteDto.getFlightId());
        String payload = PayloadUtil.generatePayload(commonFieldVo, map);
        log.info("执行航线请求数据：{}", payload);
        String response = djiCloudMQTTClient.publishMessage(topic, payload, commonFieldVo);
        // 记录操作日志
        GatewayOperationLogUtil.generateLog(flightTaskExecuteDto.getGateway(), CmdConstant.FLIGHTTASK_EXECUTE, payload, response);
        ObjectMapper objectMapper = new ObjectMapper();
        // 将字符串解析为 JSON 对象
        JsonNode resultNode = null;
        try {
            ObjectNode jsonNode = null;
            jsonNode = (ObjectNode) objectMapper.readTree(response);
            resultNode = jsonNode.path("data").path("result");
            Integer result = Integer.valueOf(resultNode.asText());
            if (result == 0) {
                Missions missions = new Missions();
                missions.setFlightId(Long.valueOf(flightTaskExecuteDto.getFlightId()));
                Missions mission = missionsService.selectMissionsList(missions).get(0);
                mission.setState("执行中");
                mission.setExecTime(new Date());
                missionsService.updateMissions(mission);
            }
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return HandleResultUtil.handleResult(response, null, "执行任务成功");
    }
}
