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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tuoheng.admin.config.SystemConstant;
import com.tuoheng.admin.entity.domain.Tenant;
import com.tuoheng.admin.entity.domain.ThMission;
import com.tuoheng.admin.entity.domain.Warning;
import com.tuoheng.admin.entity.domain.WarningRecord;
import com.tuoheng.admin.entity.request.airport.PointFlightRequest;
import com.tuoheng.admin.enums.*;
import com.tuoheng.admin.mapper.TenantMapper;
import com.tuoheng.admin.mapper.ThMissionMapper;
import com.tuoheng.admin.mapper.WarningMapper;
import com.tuoheng.admin.mapper.WarningRecordMapper;
import com.tuoheng.admin.utils.CodeUtil;
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.utils.ShiroUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class PointFlightService {

    @Autowired
    private TenantMapper tenantMapper;

    @Autowired
    private WarningMapper warningMapper;

    @Autowired
    private ThMissionMapper missionMapper;

    @Autowired
    private WarningRecordMapper warningRecordMapper;

    @Transactional
    public JsonResult executePointFligh(PointFlightRequest request) {
        log.info("进入调用机场平台，执行定点飞行, request = {}", request);
        JsonResult result = this.check(request);
        User user = ShiroUtils.getUserInfo();
        Integer tenantId = user.getTenantId();
        ThMission oldMission = (ThMission) result.getData();

        // 获取租户信息
        Tenant tenant = this.getTenant(tenantId);

        Integer emergencyDataMissionId = 0;
        boolean callOldAirpor = false;
        boolean callNewAirpor = false;
        if (TaskStatusEnum.COMPLETE.getCode() == oldMission.getStatus()) {
            log.info("执行定点飞行, 原巡检任务已完成");
            // 巡检任务已经结束
            // 再次选择原来机场进行定点飞行，
            if (oldMission.getAirportId() == request.getAirportId()) {
                log.info("原机场，重新执行定点飞行");
            } else {
                log.info("新机场执行定点飞行");
            }
            callNewAirpor = true;
        } else {
            log.info("执行定点飞行, 原巡检任务在执行");
            if (oldMission.getAirportId().equals(request.getAirportId())) {
                log.info("原机场，直接执行定点飞行");
                callOldAirpor =  true;
                emergencyDataMissionId = oldMission.getId();
            } else {
                log.info("新机场执行定点飞行");
                callNewAirpor = true;

            }
        }

        // 创建应急任务
        ThMission emergencyMission = this.createMission(user, request, emergencyDataMissionId);

        // 调用机场平台
        log.info("调用机场平台, callOldAirpor={}, callNewAirpor={}", callOldAirpor, callNewAirpor);
        if (callOldAirpor) {
            this.callOldAirpor(request);
        }

        if (callNewAirpor) {
            this.callNewAirpor(tenant, request, emergencyMission.getId());
        }

        // 修改原巡检任务状态为已完成
        oldMission.setStatus(TaskStatusEnum.COMPLETE.getCode());
        missionMapper.updateById(oldMission);

        // 创建预警记录
        WarningRecord warningRecord = this.createWarningRecord(user.getId(), tenantId, request, emergencyMission.getId());

        log.info("调用机场平台方法: 执行定点飞行结束");
        return JsonResult.success(warningRecord);
    }

    /**
     * 检查参数
     *
     * @param request
     */
    private JsonResult check(PointFlightRequest request) {
        if (ObjectUtil.isNull(request.getWarningId())) {
            throw new ServiceException("预警ID为空");
        }
        if (ObjectUtil.isNull(request.getMissionId())) {
            throw new ServiceException("原巡检任务ID为空");
        }
        if (ObjectUtil.isNull(request.getAirportId())) {
            throw new ServiceException("机场ID为空");
        }
        if (ObjectUtil.isNull(request.getAirportName())) {
            throw new ServiceException("机场名称为空");
        }
        if (ObjectUtil.isNull(request.getAlt())) {
            throw new ServiceException("指点高度为空");
        }
        if (ObjectUtil.isNull(request.getLon())) {
            throw new ServiceException("经度为空");
        }
        if (ObjectUtil.isNull(request.getLat())) {
            throw new ServiceException("纬度为空");
        }
        Warning warning = warningMapper.selectOne(new LambdaQueryWrapper<Warning>()
                .eq(Warning::getId, request.getWarningId())
                .eq(Warning::getMark, MarkEnum.VALID.getCode()));
        if (ObjectUtil.isNull(warning)) {
            throw new ServiceException("该预警信息不存在");
        }
        ThMission mission = missionMapper.selectOne(new LambdaQueryWrapper<ThMission>()
                .eq(ThMission::getId, request.getMissionId())
                .eq(ThMission::getMark, MarkEnum.VALID.getCode()));
        if (ObjectUtil.isNull(mission)) {
            throw new ServiceException("原巡检任务不存在");
        }

        // 判断是否有正在执行的应急任务
        List<WarningRecord> warningRecordList = warningRecordMapper.selectList(new LambdaQueryWrapper<WarningRecord>()
                .eq(WarningRecord::getWarningId, warning.getId())
                .eq(WarningRecord::getMissionId, mission.getId())
                .eq(WarningRecord::getMark, MarkTypeEnum.VALID.getCode()));
        if (CollectionUtil.isNotEmpty(warningRecordList)) {
            List<Integer> missionIdList = warningRecordList.stream().map(WarningRecord::getEmergencyMissionId).collect(Collectors.toList());
            List<ThMission> missionList = missionMapper.selectList(new LambdaQueryWrapper<ThMission>()
                    .eq(ThMission::getMark, MarkEnum.VALID.getCode())
                    .in(ThMission::getId, missionIdList));
            for (ThMission missionTmp : missionList) {
                if (TaskStatusEnum.FLIGHT.getCode() == missionTmp.getStatus()) {
                    throw new ServiceException("已存在正在执行的应急任务");
                }
            }
        }

        if (mission.getAirportId() == request.getAirportId()) {
            ThMission missionTmp = missionMapper.selectOne(new LambdaQueryWrapper<ThMission>()
                    .eq(ThMission::getEmergencyDataMissionId, mission.getId())
                    .eq(ThMission::getMark, MarkEnum.VALID.getCode()));
            if (ObjectUtil.isNotNull(missionTmp)) {
                if (TaskStatusEnum.FLIGHT.getCode() == missionTmp.getStatus()) {
                    log.info("原机场正在执行任务");
                    throw new ServiceException("发现该问题的机场正在执行任务");
                }
            }
        } else {
            ThMission missionTmp = missionMapper.selectOne(new LambdaQueryWrapper<ThMission>()
                    .eq(ThMission::getAirportId, request.getAirportId())
                    .eq(ThMission::getStatus, TaskStatusEnum.FLIGHT.getCode())
                    .eq(ThMission::getMark, MarkEnum.VALID.getCode())
                    .last(" limit 1"));
            if (ObjectUtil.isNotNull(missionTmp)) {
                log.info("新机场正在执行任务");
                throw new ServiceException("该机场正在执行任务");
            }
        }
        return JsonResult.success(mission);
    }

    /**
     * 获取租户信息
     *
     * @param tenantId
     * @return
     */
    private Tenant getTenant(Integer tenantId) {
        Tenant tenant = tenantMapper.selectById(tenantId);
        if (ObjectUtil.isEmpty(tenant)) {
            log.info("调用机场平台，执行定点飞行: 租户不存在");
            throw new ServiceException("租户不存在");
        }
        return tenant;
    }

    /**
     * 调用老机场平台
     *
     * @param request
     */
    private void callOldAirpor(PointFlightRequest request) {
        String url = CommonConfig.airportURL + SystemConstant.API_AIRPORT_DRONE_CONTROL;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("taskId", request.getMissionId());
        jsonObject.put("airportId", request.getAirportId());
        jsonObject.put("zalt", request.getAlt());
        jsonObject.put("zlon", request.getLon());
        jsonObject.put("zlat", request.getLat());

        log.info("调用机场平台，原无人机执行定点飞行: url:{}", url);
        log.info("调用机场平台，原无人机执行定点飞行: jsonObject:{}", jsonObject);

        String airPortStr = HttpUtils.doSend(url, jsonObject, null, "POST");
        if (StringUtils.isEmpty(airPortStr)) {
            log.info("原无人机执行定点飞行：机场接口返回数据为空，飞行失败，jsonObject：{}", jsonObject);
            throw new ServiceException("机场接口返回数据为空，飞行失败");
        }
        JsonResult jsonResult = JacksonUtil.json2pojo(airPortStr, JsonResult.class);
        if (0 != jsonResult.getCode()) {
            log.info("原无人机执行定点飞行，机场接口返回：失败，jsonResult：{}", jsonResult.getMsg());
            throw new ServiceException("机场平台返回，失败");
        }
    }

    /**
     * 调用新机场平台
     *
     * @param tenant
     * @param request
     */
    private void callNewAirpor(Tenant tenant, PointFlightRequest request, Integer emergencyMissionId) {
        String url = CommonConfig.airportURL + SystemConstant.API_AIRPORT_POINT_FLIGH;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("airportId", request.getAirportId());
        jsonObject.put("requestId", emergencyMissionId);
        jsonObject.put("code", SystemConstant.PLATFORM_CODE); // 与机场平台约定好的
        jsonObject.put("tenantCode", tenant.getCode());
        jsonObject.put("alt", request.getAlt());
        jsonObject.put("lon", request.getLon());
        jsonObject.put("lat", request.getLat());

        log.info("调用机场平台，新无人机执行定点飞行: url:{}", url);
        log.info("调用机场平台，新无人机执行定点飞行: jsonObject:{}", jsonObject);

        String airPortStr = HttpUtils.doSend(url, jsonObject, null, "POST");
        if (StringUtils.isEmpty(airPortStr)) {
            log.info("新无人机执行定点飞行：机场接口返回数据为空，飞行失败，jsonObject：{}", jsonObject);
            throw new ServiceException("机场接口返回数据为空，飞行失败");
        }
        JsonResult jsonResult = JacksonUtil.json2pojo(airPortStr, JsonResult.class);
        if (0 != jsonResult.getCode()) {
            log.info("新无人机执行定点飞行，机场接口返回：失败，jsonResult：{}", jsonResult.getMsg());
            throw new ServiceException("机场平台返回，失败");
        }
    }

    /**
     * 创建应急任务
     *
     * @param user
     * @param request
     * @return
     */
    private ThMission createMission(User user, PointFlightRequest request, Integer emergencyDataMissionId) {
        ThMission mission = new ThMission(UpdateOrCreateEnum.CREATE.getCode());
        String code = "XJRW" + CodeUtil.createCodeNo();
        mission.setCode(code);
        mission.setName("应急任务" + code);
        mission.setTenantId(user.getTenantId());
        mission.setType(2);
        mission.setStatus(TaskStatusEnum.FLIGHT.getCode()); // 设置应急任务状态为飞行中
        mission.setInspectionType(InspectionTypeEnum.AIRPORT.getCode());
        mission.setAirportId(request.getAirportId());
        mission.setAirportName(request.getAirportName());
        mission.setInspectionLine(0);
        mission.setInspectionLineName("");
        mission.setExecutionStartTime(DateUtils.now());
        mission.setCreateUser(user.getId());
        mission.setCreateTime(DateUtils.now());
        mission.setEmergencyDataMissionId(emergencyDataMissionId);
        Integer count = missionMapper.insert(mission);
        if (count <= 0) {
            log.info("创建应急任务失败");
            throw new ServiceException("创建应急任务失败");
        } else {
            log.info("创建应急任务成功, mission={}", mission);
        }
        return mission;
    }

    /**
     * 创建预警记录
     *
     * @param userId
     * @param tenantId
     * @param request
     * @param emergencyMissionId
     */
    private WarningRecord createWarningRecord(Integer userId, Integer tenantId, PointFlightRequest request, Integer emergencyMissionId) {
        WarningRecord warningRecord = new WarningRecord();
        warningRecord.setTenantId(tenantId);
        warningRecord.setWarningId(request.getWarningId());
        warningRecord.setMissionId(request.getMissionId());
        warningRecord.setEmergencyMissionId(emergencyMissionId);
        warningRecord.setName(request.getAirportName() + "执行任务");
        warningRecord.setCreateUser(userId);
        warningRecord.setCreateTime(DateUtils.now());
        Integer count = warningRecordMapper.insert(warningRecord);
        if (count <= 0) {
            log.info("创建预计记录失败");
            throw new ServiceException("创建预计记录失败");
        }
        return warningRecord;
    }

}