package com.base.biz.mq.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.base.api.client.CalRpcService;
import com.base.api.model.BizTaskStepEnum;
import com.base.api.model.InstanceAopDTO;
import com.base.biz.model.dto.InstanceInfoDTO;
import com.base.biz.model.dto.StationInfoDTO;
import com.base.biz.model.entity.*;
import com.base.biz.mq.factory.HandlerMqFactory;
import com.base.biz.remote.GetAndHandlerInstance;
import com.base.biz.service.*;
import com.base.orbit.log.ServerNameEnum;
import com.base.orbit.mq.topics.TopicConst;
import com.base.orbit.utils.DateUtils;
import com.base.orbit.utils.IdGenerator;
import com.base.orbit.web.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CyclicBarrier;
import java.util.stream.Collectors;

/**
 * 仿真数据接收处理
 */
@Component
@Slf4j
public class SimulationMqConsumerHandler extends AbstractMqInfoHandler {

    @Resource
    private InstanceService instanceService;

    @Resource
    private SatelliteService satelliteService;

    @Resource
    private FzTaskService fzTaskService;

    @Resource
    private PayloadService payloadService;

    @Resource
    private PointService pointService;

    @Resource
    private CalcService calcService;

    @Resource
    private GetAndHandlerInstance getAndHandlerInstance;

    @Resource
    private CalRpcService calRpcService;

    private final static String INIT_TASK_STATE = "1";

    private final static String TARGET_VALUE = "TARGET";

    private final static String MAX_SUN_ELEVATION = "90";

    private final static String MIN_SUN_ELEVATION = "-90";



    @Override
    public void process(List<String> var1) {
        //接收到消息先结束正在执行的可执行文件
        calRpcService.fileroute();

        String message = var1.get(0);
        log.info("receive baseInfo message: " + message, ServerNameEnum.BASE_SERVER);
        //数据入库
        JSONObject obj = JSONObject.parseObject(message);
        JSONObject bodyObj = obj.getJSONObject("body");
        if (Objects.nonNull(bodyObj)) {
            //1.仿真任务信息入库
            List<String> satelliteCodes = buildSimulationTask(obj);
            log.info("信息入库完毕");
            //2.进行仿真任务时间所选载荷星历/星下点计算
            //2.1 构建计算所需参数
            String startTime = bodyObj.getString("startTime");
            String endTime = bodyObj.getString("endTime");
            String creationTime = obj.getString("creationTime");
            String reqId = creationTime.substring(creationTime.length() - 4, creationTime.length());
            //2.2 进行星历星下点及进出站计算
            calcService.calcEphAndSubPoint(satelliteCodes, startTime, endTime, reqId);
        }
    }

    /**
     * 仿真任务信息入库
     *
     * @param obj
     */
    private List<String> buildSimulationTask(JSONObject obj) {
        //1.初始化数据
        String workMode = "1";

        JSONObject bodyObj = obj.getJSONObject("body");
        FzTaskInfo fzTaskInfo = new FzTaskInfo();

        //2.构建仿真任务基础信息
        fzTaskInfo.setId(bodyObj.getString("taskId"));
        fzTaskInfo.setFzTaskStep(BizTaskStepEnum.TASK_GET.toString());
        fzTaskInfo.setFzTaskState(INIT_TASK_STATE);
        fzTaskInfo.setCreateTime(LocalDateTime.now());
        fzTaskInfo.setReqName(bodyObj.getString("taskName"));
        fzTaskInfo.setReqStartTime(bodyObj.getDate("startTime"));
        fzTaskInfo.setReqEndTime(bodyObj.getDate("endTime"));
        fzTaskInfo.setMessageId(obj.getString("messageId"));
        String creationTime = obj.getString("creationTime");
        fzTaskInfo.setWorkMode(workMode);
        String reqId = creationTime.substring(creationTime.length() - 4, creationTime.length());
        fzTaskInfo.setReqId(reqId);
        fzTaskInfo.setTaskId(bodyObj.getString("taskId"));
        fzTaskInfo.setReqTime(obj.getDate("creationTime"));

        //3.构建目标点信息
        buildPointInformation(bodyObj, fzTaskInfo);

        //4.构建卫星及载荷相关信息
        JSONObject wxInstanceBaseMsg = bodyObj.getJSONObject("wxInstanceBaseMsg");
        Integer satelliteNum = wxInstanceBaseMsg.getInteger("satelliteNum");
        Integer trackSurfaces = wxInstanceBaseMsg.getInteger("trackSurfaces");
        //4.1 生成payloadIds
        List<String> payloadIds = new ArrayList<String>();
        for (int i = 0; i < trackSurfaces; i++) {
            String payloadId = IdGenerator.getStrId();
            payloadIds.add(payloadId);
        }
        String payloadIdStr = StringUtils.join(payloadIds, ",");
        fzTaskInfo.setPayloadIds(payloadIdStr);
        //4.2 仿真任务入库
        fzTaskService.save(fzTaskInfo);

        //4.3 卫星载荷瞬根信息处理入库
        Integer satelliteSum = satelliteNum * trackSurfaces;
        Date startTime = bodyObj.getDate("startTime");
        Date epochTime = wxInstanceBaseMsg.getDate("lysk");
        long diff = startTime.getTime() - epochTime.getTime();
        long diffDay = diff / (24 * 60 * 60 * 1000);
        if (diffDay > 3.0) {
            //4.3.1 超过3天就进行瞬根外推，构建外推基础数据
            String strId = IdGenerator.getStrId();
            String satelliteCode = "INST-" + strId.substring(strId.length() - 5, strId.length() - 1);
            InstanceAopDTO instanceAop = new InstanceAopDTO();
            instanceAop.setStartTime(bodyObj.getString("startTime"));
            instanceAop.setEndTime(bodyObj.getString("endTime"));
            instanceAop.setEpochTime(wxInstanceBaseMsg.getString("lysk"));
            instanceAop.setEccentricity(wxInstanceBaseMsg.getString("pxl"));
            instanceAop.setInclination(wxInstanceBaseMsg.getString("gdqj"));
            instanceAop.setArgumentOfPerigee(wxInstanceBaseMsg.getString("jddfj"));
            instanceAop.setMeanAnoMaly(wxInstanceBaseMsg.getString("pjdj"));
            Double semiMajorAxis = wxInstanceBaseMsg.getDouble("gdbj") * 1000;
            instanceAop.setSemiMajorAxis(semiMajorAxis.toString());
            instanceAop.setRaan(wxInstanceBaseMsg.getString("sjdcj"));
            instanceAop.setOrbitNum("13000");
            instanceAop.setMass(bodyObj.getString("mass"));
            instanceAop.setSatelliteCode(satelliteCode);
            //4.3.2 调用瞬根外推算法
            Result<String> stringResult = calRpcService.calcInstance(instanceAop);
            //4.3.3 根据算法调用结果，查询外推瞬根数据
            if (stringResult.getCode() == 200) {
                //4.3.3.1 替换JSON字符串中数据
                List<String> satelliteCodes = new ArrayList<>();
                satelliteCodes.add(satelliteCode);
                List<InstanceInfoDTO> instanceList = instanceService.getInstanceListBySatellite(satelliteCodes);
                for (InstanceInfoDTO instanceInfoDTO : instanceList) {
                    wxInstanceBaseMsg.put("lysk", instanceInfoDTO.getEpochTime());
                    wxInstanceBaseMsg.put("pxl", instanceInfoDTO.getEccentricity());
                    wxInstanceBaseMsg.put("gdqj", instanceInfoDTO.getInclination());
                    wxInstanceBaseMsg.put("jddfj", instanceInfoDTO.getArgumentOfPerigee());
                    wxInstanceBaseMsg.put("pjdj", instanceInfoDTO.getMeanAnoMaly());
                    wxInstanceBaseMsg.put("sjdcj", instanceInfoDTO.getRaan());
                    Double orbitRadius = Double.parseDouble(instanceInfoDTO.getSemiMajorAxis());
                    orbitRadius = orbitRadius / 1000;
                    wxInstanceBaseMsg.put("gdbj", orbitRadius.toString());
                }
                bodyObj.put("wxInstanceBaseMsg",wxInstanceBaseMsg);
                //4.3.3.2 清除数据库中外推瞬根数据

            }
        }

        List<InstanceInfo> instanceDatas = new ArrayList<>();
        if(satelliteSum > 1){
            instanceDatas = getAndHandlerInstance.getInstanceData(bodyObj);
        }else{
            InstanceInfo instanceInfo = new InstanceInfo();
            String instanceId = IdGenerator.getStrId();
            instanceInfo.setId(instanceId);
            instanceInfo.setEccentricity(wxInstanceBaseMsg.getString("pxl"));
            instanceInfo.setInclination(wxInstanceBaseMsg.getString("gdqj"));
            instanceInfo.setEpochTime(wxInstanceBaseMsg.getDate("lysk"));
            instanceInfo.setMeanAnoMaly(wxInstanceBaseMsg.getString("pjdj"));
            //轨道半径上游系统传入的是千米,数据库存入的数据是米
            Double gdbj = wxInstanceBaseMsg.getDouble("gdbj");
            Double gdbjTrueValue = gdbj * 1000;
            instanceInfo.setSemiMajorAxis(gdbjTrueValue.toString());
            instanceInfo.setArgumentOfPerigee(wxInstanceBaseMsg.getString("jddfj"));
            instanceInfo.setRaan(wxInstanceBaseMsg.getString("sjdcj"));
            instanceInfo.setCreateTime(DateUtils.getNowDate());
            instanceInfo.setOrbitNum("13045");
            instanceDatas.add(instanceInfo);
        }

        ArrayList<String> satelliteCodes = new ArrayList<>();
        for (int i = 0; i < instanceDatas.size(); i++) {
            String satelliteCode = buildPayloadInfo(bodyObj, payloadIds.get(i),instanceDatas.get(i));
            satelliteCodes.add(satelliteCode);
        }
        return satelliteCodes;
    }

    /**
     * 构建载荷相关信息
     *
     * @param bodyObj: 输入数据
     * @param payloadId: 载荷Id
     */
    private String buildPayloadInfo(JSONObject bodyObj, String payloadId,InstanceInfo instanceInfo) {
        //1.初始化数据
        String payloadSeries = "2";
        int overLap = 2;

        String payloadType = bodyObj.getString("load");
        PayloadInfo payloadInfo = new PayloadInfo();
        String satelliteInfoId = IdGenerator.getStrId();
        String payloadTypeStr = payloadType + "BaseMsg";

        payloadInfo.setId(payloadId);
        payloadInfo.setCreateTime(DateUtils.getNowDate());
        payloadInfo.setSatelliteId(satelliteInfoId);
        payloadInfo.setPayloadName(bodyObj.getString("satelliteName"));
        payloadInfo.setMaxSunElevation(MAX_SUN_ELEVATION);
        payloadInfo.setMinSunElevation(MIN_SUN_ELEVATION);
        payloadInfo.setOverLap((double) overLap);
        //构建载荷所属卫星相关信息
        String satelliteCode = buildSatellite(bodyObj, payloadType, payloadInfo, satelliteInfoId, payloadTypeStr,instanceInfo);
        payloadInfo.setSatelliteCode(satelliteCode);
        payloadInfo.setPayloadSeries(payloadSeries);
        payloadService.save(payloadInfo);
        return satelliteCode;
    }

    /**
     * 构建载荷所属卫星相关信息
     *
     * @param bodyObj：传入数据
     * @param payloadType：载荷类型
     * @param payloadInfo：载荷信息
     * @param satelliteInfoId：卫星Id
     * @param payloadTypeStr：载荷存储信息字段
     * @return 卫星code
     */
    private String buildSatellite(JSONObject bodyObj, String payloadType, PayloadInfo payloadInfo, String satelliteInfoId, String payloadTypeStr,InstanceInfo instanceInfo) {
        SatelliteInfo satelliteInfo = new SatelliteInfo();
        satelliteInfo.setCreateTime(DateUtils.getNowDate());
        satelliteInfo.setId(satelliteInfoId);
        satelliteInfo.setSatelliteName(bodyObj.getString("satelliteName"));

        //1.初始化数据
        //1.1 最小侧摆角
        String minRollAngle = "0.0";
        //1.2 最大侧摆角
        String maxRollAngle = "0.0";
        //1，3 数据传输速率
        String dataPassSpeed = "0.0";
        //1.4 载荷类型数据
        String payloadTypeData = "";
        //1.5 载荷幅宽
        String satelliteSwathWidth = "0.0";
        //1.6 分辨率
        Double groundResolution = 0.0;
        //1.7 地球半径
        Double earthRadius = 6371.0;
        //1.8 轨道高度
        Double satelliteOrbitAltitude = 852.0;
        //1.9 固存容积
        String fixedVolume = "2.2";
        //1.10 星上总内存
        String totalMemory = "400000";
        //1.11 固存占用
        String baseMemory = "0.0";
        //1.12 eirp
        String eirp = "50.5";
        //1.13 信息速率
        String xxsl = "150000000";
        //1.14 carrier
        String carrier = "8200";
        //1.15 卫星质量
        String mass = "3300";


        String satelliteCode = bodyObj.getString("satelliteName");
        if (payloadType.equals("kjg") || payloadType.equals("hw") || payloadType.equals("wg") || payloadType.equals("wb")) {
            payloadTypeData = "CCD";
            JSONObject payload = bodyObj.getJSONObject(payloadTypeStr);
            String strId = IdGenerator.getStrId();
            satelliteCode = payloadTypeData + "-" + strId.substring(strId.length() - 5, strId.length() - 1);

            //3.1 构建载荷侧摆角
            maxRollAngle = payload.getString("cbj");
            //3.2 构建卫星瞬根信息
            satelliteOrbitAltitude = buildInstanceInfo(bodyObj, satelliteCode, earthRadius,instanceInfo);
            BigDecimal bigDecimal = new BigDecimal(satelliteOrbitAltitude);
            satelliteOrbitAltitude = bigDecimal.setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
            //3.3 构建载荷工作模式信息
            Double bandWidthInit = payload.getDouble("bandWidth");
            satelliteSwathWidth = bandWidthInit.toString();
            Double bandWidth = bandWidthInit * 1000;
            Map<String, Object> payloadWorkModeMap = new HashMap<>();
            payloadWorkModeMap.put("workMode", "1");
            payloadWorkModeMap.put("swathWidth", bandWidth);
            List<Map<String, Object>> payloadWorkModes = new ArrayList<>();
            payloadWorkModes.add(payloadWorkModeMap);
            payloadInfo.setPayloadWorkModes(JSON.toJSONString(payloadWorkModes));
            payloadInfo.setSwathWidth(bandWidth);
            //3.4 构建载荷传输速率
            dataPassSpeed = payload.getString("dataPassSpeed");
            if (StringUtils.isEmpty(dataPassSpeed)) {
                dataPassSpeed = "450";
            }
            payloadInfo.setDataPassSpeed(dataPassSpeed);
            //3.5 构建载荷分辨率
            groundResolution = payload.getDouble("resolution");

        } else if (payloadType.equals("SAR")) {
            payloadTypeData = "SAR";
            JSONObject payload = bodyObj.getJSONObject(payloadTypeStr);
            String strId = IdGenerator.getStrId();
            satelliteCode = payloadTypeData + "-" + strId.substring(strId.length() - 5, strId.length() - 1);
            // satelliteCode = "YH3A-01";

            //3.1 构建载荷侧摆角,因为SAR星没有侧摆角，只有入射角，所以需要用公式进行转换
            Double incidentAngle = payload.getDouble("cbj");
            double v = Math.toDegrees(Math.asin(Math.cos(Math.toRadians(90 - incidentAngle)) * ((double) (earthRadius) / (earthRadius + satelliteOrbitAltitude))));
            BigDecimal bd = new BigDecimal(v);
            Double maxRollAngleDouble = bd.setScale(5, BigDecimal.ROUND_DOWN).doubleValue();
            if(incidentAngle >= 0){
                minRollAngle = "15";
                if(maxRollAngleDouble < Double.parseDouble(minRollAngle)){
                    maxRollAngle = "45";
                }
            }else{
                if(maxRollAngleDouble > Double.parseDouble(minRollAngle)){
                    maxRollAngle = "-45";
                }
                minRollAngle = "-15";
            }

            //3.2 构建卫星瞬根信息
            satelliteOrbitAltitude = buildInstanceInfo(bodyObj, satelliteCode, earthRadius,instanceInfo);
            BigDecimal bigDecimal = new BigDecimal(satelliteOrbitAltitude);
            satelliteOrbitAltitude = bigDecimal.setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
            //3.3 构建载荷工作模式信息
            Double bandWidth = payload.getDouble("rangeSwath") * 1000;
            Double satelliteBand = bandWidth / 1000;
            satelliteSwathWidth = satelliteBand.toString();
            Map<String, Object> payloadWorkModeMap = new HashMap<>();
            payloadWorkModeMap.put("workMode", "1");
            payloadWorkModeMap.put("swathWidth", bandWidth);
            List<Map<String, Object>> payloadWorkModes = new ArrayList<>();
            payloadWorkModes.add(payloadWorkModeMap);
            payloadInfo.setPayloadWorkModes(JSON.toJSONString(payloadWorkModes));
            payloadInfo.setSwathWidth(bandWidth);
            //3.4 构建载荷传输速率
            dataPassSpeed = payload.getString("dataPassSpeed");
            if (StringUtils.isEmpty(dataPassSpeed)) {
                dataPassSpeed = "450";
            }
            payloadInfo.setDataPassSpeed(dataPassSpeed);
            //3.5 构建载荷分辨率
            groundResolution = payload.getDouble("rangeRes");
            //3.6 设置工作频段
            if ("L".equals(payload.getString("frequencyBand")) || "C".equals(payload.getString("frequencyBand"))) {
                carrier = "1700";
            }
        }
        payloadInfo.setPayloadType(payloadType);
        payloadInfo.setGroundResolution(groundResolution);
        satelliteInfo.setSwathWidth(satelliteSwathWidth);
        satelliteInfo.setGroundResolution(groundResolution.toString());
        satelliteInfo.setMass(StringUtils.isNotEmpty(bodyObj.getString("mass")) ? bodyObj.getString("mass") : mass);
        satelliteInfo.setWindArea("0.3");
        satelliteInfo.setShineArea("0.5");
        satelliteInfo.setEarthGravityFieldModeOrde1("32.0");
        satelliteInfo.setEarthGravityFieldModeOrde2("32.0");
        satelliteInfo.setMaxRollAngle(maxRollAngle);
        satelliteInfo.setMinRollAngle(minRollAngle);
        satelliteInfo.setAltitude(satelliteOrbitAltitude.toString());
        satelliteInfo.setSatelliteCode(satelliteCode);
        satelliteInfo.setDataPassSpeed(dataPassSpeed);
        satelliteInfo.setLoadType(payloadTypeData);
        satelliteInfo.setFixedVolume(fixedVolume);
        satelliteInfo.setTotalMemory(StringUtils.isNotEmpty(bodyObj.getString("totalMemory")) ? bodyObj.getString("totalMemory") : totalMemory);
        satelliteInfo.setBaseMemory(StringUtils.isNotEmpty(bodyObj.getString("baseMemory")) ? bodyObj.getString("baseMemory") : baseMemory);
        satelliteInfo.setEirp(eirp);
        satelliteInfo.setXxsl(xxsl);
        satelliteInfo.setCarrier(carrier);
        satelliteService.save(satelliteInfo);
        return satelliteCode;
    }

    /**
     * 构建卫星瞬根数据
     * @param bodyObj：上游传递数据
     * @param satelliteCode：卫星编号
     * @param earthRadius：地球半径
     * @return 卫星高度
     */
    private Double buildInstanceInfo(JSONObject bodyObj, String satelliteCode, Double earthRadius, InstanceInfo instanceInfo) {
        JSONObject wxInstanceBaseMsg = bodyObj.getJSONObject("wxInstanceBaseMsg");
        instanceInfo.setSatelliteCode(satelliteCode);
        //轨道半径上游系统传入的是千米,数据库存入的数据是米
        Double gdbj = wxInstanceBaseMsg.getDouble("gdbj");
        instanceService.save(instanceInfo);
        return gdbj - earthRadius;
    }

    /**
     * 构建目标点相关信息
     *
     * @param bodyObj：传入的数据
     * @param fzTaskInfo：仿真信息类
     */
    private void buildPointInformation(JSONObject bodyObj, FzTaskInfo fzTaskInfo) {
        String mbBaseMsg = (String) bodyObj.get("mbBaseMsg");
        List<Map<String, String>> targetBaseMessages = (List<Map<String, String>>) JSON.parse(mbBaseMsg);
        List<String> targetIds = new ArrayList<String>();
        List<PointInfo> pointInfos = new ArrayList<>();
        String targetName = "";

        for (int i = 0; i < targetBaseMessages.size(); i++) {
            targetName = targetBaseMessages.get(i).get("targetName");
            String pointStr = targetBaseMessages.get(i).get("points");
            String targetId = IdGenerator.getStrId();

            List<PointInfo> points = JSONArray.parseArray(pointStr, PointInfo.class);
            for (int j = 0; j < points.size(); j++) {
                PointInfo pointInfo = points.get(j);
                Integer serial = Integer.parseInt(pointInfo.getSerial()) - 1;
                pointInfo.setSerial(serial.toString());
                pointInfo.setId(UUID.randomUUID().toString().replace("-", ""));
                pointInfo.setSort("1");
                pointInfo.setPointType("TARGET");
                pointInfo.setCreateTime(DateUtils.getNowDate());
                pointInfo.setParentId(targetId);
                String parentName = TARGET_VALUE + "_" + targetId;
                pointInfo.setParentName(parentName);
                pointInfos.add(pointInfo);
            }
            targetIds.add(targetId);
        }
        pointService.saveBatch(pointInfos);
        String targetId = StringUtils.join(targetIds, ",");
        fzTaskInfo.setTargetId(targetId);
        fzTaskInfo.setTargetName(targetName);
        fzTaskInfo.setPriority(targetBaseMessages.get(0).get("priority"));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        HandlerMqFactory.register(TopicConst.BASE_TASK_TOPIC, this);
    }
}
