package com.base.track.thread;

import com.base.api.model.SatelliteAndInstanceRpcDTO;
import com.base.api.model.YxInfoBasisInstanceRpcDTO;
import com.base.api.model.YxInfoBasisSatelliteRpcDTO;

import com.base.api.model.StationRpcDTO;
import com.base.orbit.utils.DateUtils;
import com.base.orbit.utils.FileUtil;
import com.base.orbit.utils.TimeUtil;
import com.base.track.model.entity.AstronomicalForecast;
import com.base.track.model.entity.TrbutData;
import com.base.track.service.TrbutDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class TrbutThread {

    @Resource
    TrbutDataService trbutDataService;

    @Async("trbutTaskExecutor")
    public void run(String filePath, StationRpcDTO station, SatelliteAndInstanceRpcDTO satelliteAndInstance, String startTime, String endTime) {
        try {
            String code = satelliteAndInstance.getYxInfoBasisSatelliteDTO().getSatelliteCode();
            log.info("卫星" + code + "开始测站预报计算");
            boolean isFileWrite = writeDependFile(filePath, station, satelliteAndInstance, startTime, endTime);
            if (isFileWrite) {
                //文件写入成功，开始执行exe文件
                runExeFile(filePath, satelliteAndInstance.getYxInfoBasisSatelliteDTO(), station);
            } else {
                //文件写入失败
                log.error("卫星" + code + "写入测站预报条件文件失败");
            }
            log.info("卫星" + code + "结束测站预报计算");
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 生成进出站计算依赖文件（注意进出站的计算结果是两个数据！！！）
     * 一下计算数据现阶段使用的是瞬根来计算，不使用GPS和两行数据来计算，所以地
     *
     * @throws IOException
     */
    private boolean writeDependFile(String filePath, StationRpcDTO station, SatelliteAndInstanceRpcDTO satelliteAndInstance, String startTime, String endTime) throws IOException {
        // 卫星信息
        YxInfoBasisSatelliteRpcDTO infoBasisSatelliteDO = satelliteAndInstance.getYxInfoBasisSatelliteDTO();
        // 轨道根数信息
        YxInfoBasisInstanceRpcDTO instanceDO = satelliteAndInstance.getYxInfoBasisInstanceDTO();
        // 天线最小接受角，默认为1度
        Integer antMinRecvElevation = station.getAntMinRecvElevation() == null ? 1 : station.getAntMinRecvElevation();
        // 天线最小跟踪角，默认为1度,数库中没有
        Integer antMinTrackAngle = 1;
        // 日凌角，没有获取到数据的时候默认为 1 度
        Integer sundialCorner = station.getSundialCorner() == null ? 1 : station.getSundialCorner();

        StringBuffer sb = new StringBuffer();
        // 1 卫星详细信息
        sb.append("1 ").append(infoBasisSatelliteDO.getSatelliteCode()).append(" ").append(infoBasisSatelliteDO.getMass()).append(" ").append(infoBasisSatelliteDO.getWindArea()).append(" ").append(infoBasisSatelliteDO.getShineArea()).append(" ").append(infoBasisSatelliteDO.getEarthGravityFieldModeOrde1() != null ? infoBasisSatelliteDO.getEarthGravityFieldModeOrde1() : "32.0").append(" ").append(infoBasisSatelliteDO.getEarthGravityFieldModeOrde2() != null ? infoBasisSatelliteDO.getEarthGravityFieldModeOrde2() : "32.0").append("\n");
        // 2 预报开始时间 在
        sb.append("2 " + startTime + " " + endTime + " " + " 1.0\n");
        // 3 地面站信息
        sb.append("3 " + station.getLongitude() + " " + station.getLatitude() + " " + station.getAltitude() + " " + antMinTrackAngle + " " + antMinRecvElevation + " " + sundialCorner + "\n");
        // 4 星历类型
        sb.append("4 3\n");
        // 5 星历文件目录
        sb.append("5 /\n");
        // 6 星历预报时间
        sb.append("6 " + startTime + " " + endTime + " 1.0 1.0\n");
        // 7 星历轨道类型 输入轨道类型，输出轨道类型 目前只能使用瞬根 就是1.0
        sb.append("7 1 1\n");
        // 8 六根数对应的时间
        sb.append("8 " + instanceDO.getOrbitNum() + " " + TimeUtil.format(new Date(instanceDO.getEpochTime().getTime()-8*3600*1000)) + " " + TimeUtil.format(new Date(instanceDO.getEpochTime().getTime()-8*3600*1000)) + "\n");
        // 9 瞬根数据
        sb.append("9 " + instanceDO.getSemiMajorAxis() + " " + instanceDO.getEccentricity() + " " + instanceDO.getInclination() + " " + instanceDO.getRaan() + " " + instanceDO.getArgumentOfPerigee() + " " + instanceDO.getMeanAnoMaly() + "\n");
        // 10 GPS数据
        sb.append("10 0 0 0 0 0 0\n");
        // 11 两行数据
        sb.append("11 1 0 0 0 0 0 0 0 0\n");
        // 12 两行数据
        sb.append("12 2 0 0 0 0 0 0 0 0");

        File file = new File(filePath + Thread.currentThread().getName().split("-")[2] + "/orbdata/sttnio.inp");
        if (file.exists()) {
            file.delete();
        }
        BufferedWriter bufferedWriter;
        bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file, true)));
        bufferedWriter.write(sb.toString());
        bufferedWriter.flush();
        bufferedWriter.close();
        return true;
    }

    /**
     * 写完依赖文件之后运行执行exe程序
     *
     * @return
     */
    private boolean runExeFile(String filePath, YxInfoBasisSatelliteRpcDTO yxInfoBasisSatellite, StationRpcDTO station) throws Exception {
        String port = Thread.currentThread().getName().split("-")[2];
        File oldFile = new File(filePath + port + "/orbdata/trbut.dat");
        boolean isOldFileDelete = true;
        if (oldFile.exists()) {
            isOldFileDelete = oldFile.delete();
        }
        File okFile = new File(filePath + port + "/orbdata/sttnio.ok");
        boolean isOkFileDelete = true;
        if (okFile.exists()) {
            isOkFileDelete = okFile.delete();
        }
        if (isOldFileDelete && isOkFileDelete) {
            Process exec = Runtime.getRuntime().exec(filePath + port + "/bin/sttnio.exe", null, new File(filePath + port + "/bin/"));
            if (FileUtil.checkFileStatus(okFile, "卫星" + yxInfoBasisSatellite.getSatelliteCode() + "进出站计算", log)) {
                DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
                exec.destroy();
                FileInputStream fileInputStream;
                InputStreamReader inputStreamReader;
                BufferedReader bufferedReader;
                fileInputStream = new FileInputStream(oldFile);
                inputStreamReader = new InputStreamReader(fileInputStream);
                bufferedReader = new BufferedReader(inputStreamReader);
                String result;
                int line = 0;
                String code = yxInfoBasisSatellite.getSatelliteCode();
                while ((result = bufferedReader.readLine()) != null) {
                    if (line != 0 && line != 1) {
                        List<String> r = FileUtil.getLineArray(result);
                        String pitStr = r.get(0) + " " + r.get(1);
                        String rsStr = r.get(3) + " " + r.get(4);
                        String reStr = r.get(5) + " " + r.get(6);
                        String exitStr = r.get(7) + " " + r.get(8);
                        Date pitTime =new Date(sdf.parse(pitStr).getTime()+8*3600*1000);
                        Date rsTime =new Date(sdf.parse(rsStr).getTime()+8*3600*1000);
                        Date reTime =new Date(sdf.parse(reStr).getTime()+8*3600*1000);
                        Date exitTime =new Date(sdf.parse(exitStr).getTime()+8*3600*1000);
                        Date date = sdf.parse(pitStr);
                        // 获取弧段时间和日凌事件事件交叉的个数
                       /* long count = astronomicalForecastList.stream().filter(t -> !(t.getStartTime().compareTo(reTime) > 0 || rsTime.compareTo(t.getEndTime()) > 0)).count();
                       */
                        // 若该资源没有日凌事件影响，则保存
                       /* if (count == 0) {*/
                            TrbutData trbutData = new TrbutData();
                            trbutData.setId(code + date.getTime());
                            trbutData.setPitTime(pitTime);
                            trbutData.setStartAzimuth(Double.parseDouble(r.get(2)));
                            trbutData.setReceiveStartTime(rsTime);
                            trbutData.setReceiveEndTime(reTime);
                            trbutData.setExitTime(exitTime);
                            trbutData.setEndAzimuth(Double.parseDouble(r.get(9)));
                            trbutData.setHighestElevationAngle(Double.parseDouble(r.get(10)));
                            trbutData.setHighestAzimuth(Double.parseDouble(r.get(11)));
                            trbutData.setOrbitNum(Integer.parseInt(r.get(12)));
                            trbutData.setSatelliteId(yxInfoBasisSatellite.getId());
                            trbutData.setSatelliteName(yxInfoBasisSatellite.getSatelliteName());
                            trbutData.setStationId(station.getId());
                            trbutData.setCreate_time(new Date());
                            trbutData.setStationType(0);
                            trbutData.setStationCode(station.getStationCode());
                            trbutData.setStationName(station.getStationName());
                            trbutData.setSatelliteCode(yxInfoBasisSatellite.getSatelliteCode());
                            long diff=reTime.getTime()-rsTime.getTime();
                            trbutData.setDuration((int) diff);
                            trbutDataService.saveOrUpdate(trbutData);

                    }
                    line++;
                }
            }
        }
        return true;
    }

}
