package com.base.biz.service;

import com.base.api.client.CalRpcService;
import com.base.api.model.request.TaskStateNotice;
import com.base.biz.model.dto.StationInfoDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 调用计算服务
 */
@Service
@Slf4j
public class CalcService implements Runnable{

    @Resource
    private CalRpcService calRpcService;

    @Resource
    private StationService stationService;

    @Resource
    private FzTaskService fzTaskService;

    private String reqId;

    private List<String> satelliteCodes;

    private String startTime;

    private String endTime;

    private final static Integer INIT_TASK_STATE = 0;

    /**
     * 这个方法来进行异步调用星历星下点
     */
    public void calcEphAndSubPoint(List<String> satelliteCodeList, String startTime, String endTime, String reqId){
        this.reqId = reqId;
        this.satelliteCodes = satelliteCodeList;
        this.startTime = startTime;
        this.endTime = endTime;
        //cyclicBarrier:创建一个CyclicBarrier实例，屏障数据设为2，处理完成之后，执行当前类的run方法
        CyclicBarrier cyclicBarrier = new CyclicBarrier(3,this);

        //threadPoolExecutor：创建一个线程池来进行多线程星历星下点计算
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(3, 3, 300, TimeUnit.SECONDS, new LinkedBlockingDeque<>(10));

        //1.开启线程进行星历星下点及进出站计算
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    log.info("开始计算星历!!!");
                    for (int i = 0; i < satelliteCodeList.size(); i++) {
                        List<String> satelliteCodes = new ArrayList<>();
                        satelliteCodes.add(satelliteCodeList.get(i));
                        calRpcService.calcEph(satelliteCodes, startTime, endTime);
                    }
                    log.info("星历计算成功！！！");
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    log.info("星历计算出错:{}", e.getMessage());
                }
            }
        });

        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    log.info("开始计算星下点!!!");
                    Thread.sleep(5000);
                    List<String> satelliteCodes = satelliteCodeList;
                    calRpcService.calcSubPoint(satelliteCodes, startTime, endTime);
                    log.info("星下点计算成功！！！");
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    log.info("星下点计算出错:{}", e.getMessage());
                }
            }
        });
        threadPoolExecutor.execute(new Runnable() {
            @Override
            public void run() {
                //1.这里进行进出站的计算
                List<StationInfoDTO> stationLists = stationService.getAllList();
                List<String> stationIds = stationLists.stream().map(StationInfoDTO::getId).collect(Collectors.toList());
                try {
                    log.info("开始计算进出站!!!");
                    for (int i = 0; i < satelliteCodeList.size(); i++) {
                        List<String> satelliteCodes = new ArrayList<>();
                        satelliteCodes.add(satelliteCodeList.get(i));
                        calRpcService.calcStation(satelliteCodes, stationIds, startTime, endTime);
                    }
//                    List<String> satelliteCodes = satelliteCodeList;
//                    calRpcService.calcStation(satelliteCodes, stationIds, startTime, endTime);
                    log.info("卫星进出站计算成功！！！");
                    cyclicBarrier.await();
                }catch (InterruptedException | BrokenBarrierException e){
                    log.info("进出站计算出错:{}", e.getMessage());
                }
            }
        });
        //2.待执行完成后，停止线程池
        threadPoolExecutor.shutdown();
    }

    @Override
    public void run() {
        //1.待星历星下点计算完成进行中继星的进出站弧段计算
        List<StationInfoDTO> stationLists = stationService.getAllList();
        List<String> stationIds = stationLists.stream().filter(t -> t.getResourceType().equals("1")).map(StationInfoDTO::getId).collect(Collectors.toList());
        calRpcService.calcRelaySatellite(satelliteCodes, stationIds, startTime, endTime);
        //2.待星历星下点及进出站计算完成后，修改任务状态，让其在前端显示
        TaskStateNotice taskStateNotice = new TaskStateNotice();
        taskStateNotice.setState(INIT_TASK_STATE);
        taskStateNotice.setBizTaskId(reqId);
        fzTaskService.updateTaskStepState(taskStateNotice);
    }
}
