package com.base.plan.service;


import com.base.api.client.SubPointDataRpcService;
import com.base.api.model.*;
import com.base.core.model.enity.ArcCoreDTO;
import com.base.core.model.enity.GridInfoCoreDTO;
import com.base.orbit.utils.DateUtils;
import com.base.plan.mapper.GridInfoMapper;
import com.base.plan.model.entity.EphTrack;
import com.base.plan.model.entity.GridInfo;
import lombok.extern.slf4j.Slf4j;
import com.base.core.model.enity.Region;
import com.base.core.model.enity.ReportPoint;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

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

@Service
@Slf4j
public class RegionService {

    @Resource
    GridInfoMapper gridInfoMapper;

    @Resource
    SubPointDataRpcService subPointDataRpcService;


    /**
     * 记录观测区域顶点信息到观测区域实体类中
     *
     * @param area 网格编码集合
     * @return Region：观测区域实体类，包括原始区域包含的网格和四个顶点
     */
    public Region calCRegion(List<ArcCoreDTO> area, ReportPoint rp) throws Exception {
        Region region = new Region();
        if (!CollectionUtils.isEmpty(area)) {
            List<GridInfo> gridcode1 = new ArrayList<GridInfo>();
            List<GridInfo> gridcode2 = new ArrayList<GridInfo>();
            List<GridInfo> gridcode3 = new ArrayList<GridInfo>();
            List<GridInfo> gridcode4 = new ArrayList<GridInfo>();

            int areasize = area.size() - 1;
            //  判断第一个弧段和最后一个弧段对应的网格是否为空
            ArcCoreDTO firstArc = area.get(0);
            ArcCoreDTO lastArc = area.get(areasize);
            if (firstArc.getGridlist().isEmpty() || lastArc.getGridlist().isEmpty()) {
                log.error("error", "area.get(0).getGridlist().isEmpty() || area.get(areasize).getGridlist().isEmpty()");
                throw new Exception("calculate region error!");
            } else {
                String gridcode_begin_id = firstArc.getGridlist().get(0).getId();
                int lastnum = firstArc.getGridlist().size() - 1;
                String gridcode_end_id = firstArc.getGridlist().get(lastnum).getId();
                GridInfo grid1 = gridInfoMapper.selectById(gridcode_begin_id);
                GridInfo grid2 = gridInfoMapper.selectById(gridcode_end_id);
                gridcode1.add(grid1);
                gridcode2.add(grid2);
                if (gridcode1.isEmpty() || gridcode2.isEmpty()) {
                    log.error("error", "gridcode1.isEmpty() || gridcode2.isEmpty()");
                    throw new Exception("calculate region2 error!");
                } else {
                    //查询最西南角顶点坐标
                    region.setSw_node(grid1.getLbLat(), grid1.getLbLon());
                    //查询最东南角顶点坐标
                    region.setSe_node(gridcode2.get(0).getRbLat(), gridcode2.get(0).getRbLon());
                }

                String gridcode_begin2_id = area.get(areasize).getGridlist().get(0).getId();
                int lastnum2 = area.get(area.size() - 1).getGridlist().size() - 1;
                String gridcode_end2_id = area.get(areasize).getGridlist().get(lastnum2).getId();
                GridInfo grid3 = gridInfoMapper.selectById(gridcode_begin2_id);
                GridInfo grid4 = gridInfoMapper.selectById(gridcode_end2_id);
                gridcode3.add(grid3);
                gridcode4.add(grid4);
                if (gridcode3.isEmpty() || gridcode4.isEmpty()) {
                    log.error("error", "gridcode3.isEmpty() || gridcode4.isEmpty()");
                    throw new Exception("calculate region3 error!");
                } else {
                    //查询最西北角顶点坐标
                    region.setNw_node(grid3.getLtLat(), grid3.getLtLon());
                    //查询最东北角顶点坐标
                    region.setNe_node(grid4.getRtLat(), grid4.getRtLon());

                    double cenlat = (rp.getN_node_lat() + rp.getS_node_lat()) / 2;
                    double cenlon = (rp.getE_node_lon() + rp.getW_node_lon()) / 2;
                    region.setCen_node(cenlat, cenlon);
                    region.setOriginArea(area);
                    region.setReportPoint(rp);
                }
            }
        } else {
            log.error("error", "function calCRegion,area is null");
            throw new Exception("Region area is null");
        }
/*        List<String> gridlistRegion=new ArrayList<>();
       ArcCoreDTO arcCoreDTO = area.get(0);
        for (GridInfoCoreDTO gridInfoCoreDTO:arcCoreDTO.getGridlist()){
            gridlistRegion.add(gridInfoCoreDTO.getId());
        }
        region.setGridlistRegion(gridlistRegion);*/
        return region;
    }


    /**
     * 根据观测区域获得可见星下点数据
     *
     * @param region        观测区域
     * @param payloadRpcDTO 载荷信息
     * @param fzTaskRpcDTO  测控任务
     * @return 可见星下点数据
     */
    public List<SubPointDataRpcDTO> getSubPoint(Region region, PayloadRpcDTO payloadRpcDTO, TargetDemandRpcDTO targetRelationDTO) throws Exception {
        log.debug("debug", "RegionService.getEphFromDb");

        int updown = region.getUpdown();//升降轨都查，防止漏可能，最后再按太阳高度角卡

        /*
         * 计算观测区域的经纬度极值点
         */
        double southlat = region.getSeNode().getLat();
        double northlat = region.getNeNode().getLat();
        double eastlon = region.getSeNode().getLon();
        double westlon = region.getSwNode().getLon();

        //  判断有多少卫星需求。原ppas代码中 需查询卫星需求匹配表 现根据载荷来获取卫星
        //  todo 一个观测任务可选多个载荷,一个载荷对应一个卫星
        String satelliteCode = payloadRpcDTO.getSatelliteCode();
        //  运控无卫星规划时间，此处采用任务开始和结束时间
        QueryEphListRpcDTO queryEphListRpcDTO = new QueryEphListRpcDTO();
        queryEphListRpcDTO.setCode(satelliteCode);
        queryEphListRpcDTO.setUpDown(updown);
        queryEphListRpcDTO.setStartTime(targetRelationDTO.getStartTime());
        queryEphListRpcDTO.setEndTime(targetRelationDTO.getEndTime());
        queryEphListRpcDTO.setSouthLat(southlat);
        queryEphListRpcDTO.setNorthLat(northlat);
        queryEphListRpcDTO.setEastLon(eastlon);
        queryEphListRpcDTO.setWestLon(westlon);
        queryEphListRpcDTO.setPayloadType(payloadRpcDTO.getPayloadType());

        List<SubPointDataRpcDTO> subPointDataList = subPointDataRpcService.getSubPointListForStripExcute(queryEphListRpcDTO);
        return subPointDataList;

    }

    /**
     * 根据时长要求截断成像范围
     *
     * @param ephTracks 星下点 轨迹实体类集合
     * @param region    观测区域
     * @return
     */
    public List<EphTrack> clearbadeph(List<EphTrack> ephTracks, Region region) throws Exception {
        //  观测区域顶点类
        ReportPoint rp = region.getReportPoint();
        List<EphTrack> ephdata = ephTracks;
        //  观测区域中心点
        double cen_lon = (rp.getE_node_lon() + rp.getW_node_lon()) / 2;
        double m1, m2;
        //  根据时长要求截断成像范围
        for (Iterator iterator = ephdata.iterator(); iterator.hasNext(); ) {
            EphTrack ephTrack = (EphTrack) iterator.next();
            if (ephTrack.getPayloadLMT() == null) {
                iterator.remove();
                ;
                continue;
            }
            //  最大观测时长
            int ephcount = (int) ephTrack.getPayloadLMT().getMax_duration();
            //  最大幅宽
            if (ephTrack.getPayloadLMT().getMaxInfoBasisPayload().getSwathWidth().intValue() > 1000 * 1000)
                ephcount = 40 * 60;
            if (ephTrack.getSubPointlist().size() > ephcount) {
                int n1 = ephcount / 2;
                //  取载荷成像最大观测时长中间时刻星下点的经度-目标中心经度
                m1 = Math.abs(ephTrack.getSubPointlist().get(n1).getLon() - cen_lon);
                int num = ephTrack.getSubPointlist().size() - ephcount;
                int n2 = ephTrack.getSubPointlist().size() - n1;
                //  取实际-中间时刻的星下点的经度-目标中心经度
                m2 = Math.abs(ephTrack.getSubPointlist().get(n2).getLon() - cen_lon);
                List<SubPointDataRpcDTO> temptrack = new ArrayList<SubPointDataRpcDTO>();
                if (m1 < m2) {
                    for (int j = 0; j < ephcount; j++) {
                        temptrack.add(ephTrack.getSubPointlist().get(j));
                    }
                } else {
                    for (int j = num; j < ephTrack.getSubPointlist().size(); j++) {
                        temptrack.add(ephTrack.getSubPointlist().get(j));
                    }
                }
                ephTrack.setSubPointlist(temptrack);
            }
            ephTrack.setFlag(true);
            int minephcount = (int) ephTrack.getPayloadLMT().getMin_duration() + 1 + 2;// 20171007
            // chenhy
            // +1
            //  获取载荷最大的幅宽
            if (ephTrack.getPayloadLMT().getMaxInfoBasisPayload().getSwathWidth().intValue() > 1000 * 1000)
                minephcount = 40 * 60;
            if (ephTrack.getSubPointlist().size() < minephcount) {

                int count = ephTrack.getSubPointlist().size() / 2;
                Date center_time = ephTrack.getSubPointlist().get(count).getDate();

                // 计算球面上两点间距离，找到离pointA最近的pointB,找cos(alpha) 最大的
                double tempAngle = 0;
                for (int i = 0; i < ephTrack.getSubPointlist().size(); i++) {

                    SubPointDataRpcDTO satTrack = ephTrack.getSubPointlist().get(i);

                    // 计算cos(alpha)值
                    double value = Math.sin(satTrack.getLat() * Math.PI / 180)
                            * Math.sin(region.getCenNode().getLat() * Math.PI / 180)
                            + Math.cos(satTrack.getLat() * Math.PI / 180)
                            * Math.cos(region.getCenNode().getLat() * Math.PI / 180)
                            * (Math.cos((satTrack.getLon() - region.getCenNode().getLon()) * Math.PI / 180));
                    if (value > tempAngle) {
                        tempAngle = value;
                        center_time = satTrack.getDate();
                    }
                }

                Date starttime = new Date(center_time.getTime() - minephcount * 500);
                Date enttime = new Date(center_time.getTime() + minephcount * 500);
                String start= DateUtils.DateToString(starttime);
                String end= DateUtils.DateToString(enttime);
                List<SubPointDataRpcDTO> satelliteSubPointDataList = subPointDataRpcService.getSubPointDataList(ephTrack.getSatallitCode(), start, end,null);
                if (CollectionUtils.isEmpty(satelliteSubPointDataList)) {
                    log.error("error", "List<Map<Object,Object>> dbdata is null!", "102029");
                    throw new Exception("no suitable eph data for missionstrip!");
                }
                ephTrack.setSubPointlist(satelliteSubPointDataList);
            }
        }

        LinkedList<EphTrack> workList = new LinkedList();
        LinkedList<EphTrack> resultList = new LinkedList();
        workList.addAll(ephdata);

        while (!workList.isEmpty()) {
            EphTrack head_track = workList.getFirst();
            LocalDateTime tw1S = DateUtils.DateCaseToLocalDateTime(head_track.getSubPointlist().get(0).getDate());
            LocalDateTime tw1E = DateUtils.DateCaseToLocalDateTime(head_track.getSubPointlist().get(head_track.getSubPointlist().size() - 1).getDate());
            boolean found_conflict = false;
            EphTrack ephtrack_conflict = null;
            for (int j = 0; j < workList.size(); j++) {
                EphTrack ephtrack_current = workList.get(j);
                if (head_track != ephtrack_current) {

                    LocalDateTime tw2S = DateUtils.DateCaseToLocalDateTime(ephtrack_current.getSubPointlist().get(0).getDate());
                    LocalDateTime tw2E = DateUtils.DateCaseToLocalDateTime(ephtrack_current.getSubPointlist().get(ephtrack_current.getSubPointlist().size() - 1).getDate());
                    if ((tw1E.isBefore(tw2S)) || (tw1S.isAfter(tw2E))) {

                    } else {
                        found_conflict = true;
                        ephtrack_conflict = ephtrack_current;
                    }
                }
            }
            if (found_conflict) {

                workList.remove(ephtrack_conflict);
            } else {
                resultList.add(head_track);
                workList.remove(head_track);
            }
        }
        ephdata.clear();
        ephdata.addAll(resultList);
        log.debug("debug", "EphService.clearbadeph finished");
        return ephdata;
    }

}
