package com.jiayue.insu.incloud.pulldata;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jiayue.insu.incloud.compermisson.QNHLComPermisson;
import com.jiayue.insu.incloud.constants.CommonStant;
import com.jiayue.insu.incloud.constants.CompanyConstant;
import com.jiayue.insu.incloud.constants.enums.QNHLEnum;
import com.jiayue.insu.incloud.constants.enums.StatusEnum;
import com.jiayue.insu.incloud.constants.vo.RequestVo;
import com.jiayue.insu.incloud.constants.vo.ResponseVo;
import com.jiayue.insu.incloud.entity.ForecastData;
import com.jiayue.insu.incloud.entity.IntegrationCompany;
import com.jiayue.insu.incloud.entity.Record;
import com.jiayue.insu.incloud.entity.Station;
import com.jiayue.insu.incloud.service.ForecastDataService;
import com.jiayue.insu.incloud.service.IntegrationCompanyService;
import com.jiayue.insu.incloud.service.RecordService;
import com.jiayue.insu.incloud.service.StationService;
import com.jiayue.insu.incloud.utils.SystermUtils;
import com.jiayue.insu.minio.util.MinioUtilService;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import java.io.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 清能互联 拉取修正数据业务
 *
 * @author yh
 * @version 1.0
 * @since 2022/5/22 11:29
 */
@Component
@Slf4j
@RefreshScope
public class PullCorrectDataForQNHL implements IPullInitCorrectData {

    @Autowired
    private ForecastDataService forecastDataService;
    @Autowired
    private StationService stationService;
    @Autowired
    private IntegrationCompanyService integrationCompanyService;
    @Autowired
    private QNHLComPermisson qNHLComPermisson;

    @Autowired
    private RecordService recordService;
    @Autowired
    private VelocityEngine velocityEngine;
    @Autowired
    private MinioUtilService minioUtilService;

    @Value("${minio.fileurl}")
    String fileurl;

    @Value("${minio.bucketname}")
    private String bucketName;

    /**
     * 拉取修正预测数据并生成文件上送minio服务器
     *
     * @param station 场站信息
     * @return 是否成功
     */
    @Override
    public Boolean pullDQAndNWPData(Station station) {

        Record record = new Record();
        record.setStationCode(station.getStationCode());
        record.setInCode(station.getInCode());
        record.setType(CommonStant.RECORD_TYPE_PULL_CORRECT);
        LocalDateTime localDateTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
        record.setTime(localDateTime);
        record.setCreateTime(LocalDateTime.now());

        Station st = stationService.findByStationCode(station.getStationCode());
        String token = st.getComKey();
        LocalDateTime tokenTime = st.getKeyTime();

        IntegrationCompany integrationCompany = integrationCompanyService.findByCode(CompanyConstant.COMPANY_QNHL);
        String dataPullUrl = integrationCompany.getPullUrl();


        boolean result = false;
        boolean isUpload = false;
        String response;
        RequestVo requestVo;
        List<ForecastData> list = new ArrayList<>();

        if (StrUtil.isEmpty(token) || LocalDateTime.now().isAfter(tokenTime)) {
            if (qNHLComPermisson.generateKey(station)) {
                st = stationService.findByStationCode(station.getStationCode());
                token = st.getComKey();
                tokenTime = st.getKeyTime();
            }
        }

        if (StrUtil.isNotEmpty(token) && LocalDateTime.now().isBefore(tokenTime)) {
            try {

                DateTime dateTime = DateUtil.parse(DateUtil.today());
                requestVo = RequestVo.builder()
                        .transferType(QNHLEnum.TRANSFER_TYPE_CORRECT.getCode())
                        .date(dateTime.toString("yyyyMMdd"))
                        .dataType(QNHLEnum.DATA_CORRFORE_TYPE.getCode())
                        .build();

                JSONObject json = JSONUtil.parseObj(requestVo, true);
                String body = json.toString();

                HttpRequest httpRequest = HttpRequest.post(dataPullUrl)
                        .header("Content-Type", "application/json")
                        .header("Authorization", token);
                httpRequest.setGlobalTimeout(20000);
                response = httpRequest
                        .body(body)
                        .execute().body();

                if (StrUtil.isNotEmpty(response)) {
                    boolean isJson = JSONUtil.isJsonObj(response);
                    if (isJson) {
                        ResponseVo responseVo = JSONUtil.toBean(response, ResponseVo.class);
                        String code = responseVo.getRetCode();
                        if (code.equals(QNHLEnum.REQUEST_SUCCESS.getCode())) {

                            List<ForecastData> aList = new ArrayList<>();
                            long startTime = DateUtil.beginOfDay(new Date()).getTime();
                            long endTime = DateUtil.offsetDay(DateUtil.beginOfDay(DateUtil.tomorrow()), st.getDays()).getTime();
                            aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
//                            log.info(station.getStationCode() + " 请求短期修正数据返回内容:{}", response);

                            try {

                                if (CommonStant.ET_PHOTOVOLTAIC.equals(st.getType())) {
                                    list = correctPhotovoltaicData(responseVo.getData());

                                } else {
                                    list = correctWindData(responseVo.getData());
                                }

                                /**************检测解析数据完整性*******************/
                                BigDecimal one = new BigDecimal("1");
                                BigDecimal checkCount = new BigDecimal(st.getDays().toString()).add(one).multiply(new BigDecimal("96")).add(one);
                                if (list.size() < checkCount.intValue()) {
                                    record.setState(StatusEnum.DATA_DEFICIENCY.getCode());
                                    record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
                                    log.warn("========== {}:{} ==> 请求短期修正数据缺数: {}", integrationCompany.getName(), st.getStationCode(), list.size());
                                } else {
                                    result = true;
                                    for (ForecastData a : aList) {
                                        List<ForecastData> collect = list.stream().filter(n -> n.getForecastTime().longValue() == a.getForecastTime().longValue()).collect(Collectors.toList());
                                        if (CollectionUtil.isNotEmpty(collect)) {
                                            ForecastData correct = collect.get(0);
                                            a.setCorrectTime(LocalDateTime.now());
                                            a.setFpValueCorrect(correct.getFpValueCorrect());
                                            a.setSwrCorrect(correct.getSwrCorrect());
                                            a.setDirectRadiationCorrect(correct.getDirectRadiationCorrect());
                                            a.setDiffuseRadiationCorrect(correct.getDiffuseRadiationCorrect());
                                            a.setWindSpeedCorrect(correct.getWindSpeedCorrect());
                                            a.setWindDirCorrect(correct.getWindDirCorrect());
                                            a.setTemperatureCorrect(correct.getTemperatureCorrect());
                                            a.setHumidityCorrect(correct.getHumidityCorrect());
                                            a.setPressureCorrect(correct.getPressureCorrect());

                                        } else {
                                            record.setState(StatusEnum.DATA_DEFICIENCY.getCode());
                                            record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
                                            log.warn("========== {}:{} ==> 请求短期修正数据缺数: {}", integrationCompany.getName(), st.getStationCode(), list.size());
                                            break;
                                        }
                                    }

                                }
                                /**************检测解析数据完整性*******************/

                            } catch (Exception e) {
                                record.setState(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getSign());
                                record.setStateContent("解析短期修正数据失败");
                                log.error("=========={}:{} ==> 解析短期修正数据失败 ", integrationCompany.getName(), st.getStationCode());
                            }


                            if (result) {
                                log.info("=========={}:{} ==> 拉取短期修正数据成功！ ==========", integrationCompany.getName(), st.getStationCode());
                                record.setState(StatusEnum.SUCCESS.getSign());
                                record.setStateContent(String.valueOf(list.size()));
                                boolean b = forecastDataService.saveOrUpdateBatch(aList);
                                if (b) {
                                    File file = genFile(station);
                                    if (file != null) {

                                        boolean flag = minioUtilService.bucketExists(bucketName);
                                        if (flag) {
                                            InputStream in = new FileInputStream(file);
                                            String fileName = "/" + station.getStationCode() + "/" + file.getName();
                                            minioUtilService.putObject(bucketName, fileName, in);
                                        }

                                    }
                                }

                            }

                        } else {
                            record.setState(StatusEnum.RESPONSE_FAIL.getSign());
                            record.setStateContent(StatusEnum.RESPONSE_FAIL.getMsg());
                            log.error("=========={}:{} ==>拉取短期修正数据失败 响应码异常 ", integrationCompany.getName(), st.getStationCode());
                        }
                    } else {
                        record.setState(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getSign());
                        record.setStateContent(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getMsg());
                        log.error("=========={}:{} ==>拉取短期修正数据失败 接收响应字符串非json格式 ", integrationCompany.getName(), st.getStationCode());
                    }
                } else {
                    record.setState(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getSign());
                    record.setStateContent(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getMsg());
                    log.error("=========={}:{} ==> 拉取短期修正数据失败  返回响应内容为空 ==========", integrationCompany.getName(), st.getStationCode());
                }

            } catch (Exception e) {
                record.setState(StatusEnum.CONNECT_ERROR.getSign());
                record.setStateContent(StatusEnum.CONNECT_ERROR.getMsg());
                log.error("=========={}:{} ==>请求短期修正数据失败 连接断开或请求超时 ==========", integrationCompany.getName(), st.getStationCode());
                e.printStackTrace();

            }
        }
        recordService.save(record);
        return isUpload;

    }


    /**
     * 生成文件
     *
     * @return
     */
    public File genFile(Station station) {

        String vmsPath = SystermUtils.getResourceBasePath() + "/vms/DQ.vm";
        File file = null;
        Template template = this.velocityEngine.getTemplate(vmsPath);
        if (template != null) {
            VelocityContext velocityContext;
            StringWriter writer;

            long startTime = DateUtil.beginOfDay(new Date()).getTime();
            long endTime = DateUtil.offsetDay(DateUtil.beginOfDay(DateUtil.tomorrow()), station.getDays()).getTime();
            List<ForecastData> aList = new ArrayList<>();
            aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
            aList.sort(Comparator.comparing(ForecastData::getForecastTime));
            List<Map<String, Object>> vList = new ArrayList<>();

            for (ForecastData a : aList) {
                Map<String, Object> map = new HashMap<>();
                map.put("id", a.getId());
                map.put("stationName", station.getName());
                map.put("forecastTime", DateUtil.format(new Date(a.getForecastTime()), "yyyy-MM-dd HH:mm:ss"));
                map.put("fpValue", a.getFpValue() == null ? "-99" : a.getFpValue());
                vList.add(map);

            }

            velocityContext = new VelocityContext();
            velocityContext.put("stationName", station.getName());

            velocityContext.put("date", DateUtil.format(new Date(), "yyyy-MM-dd"));
            velocityContext.put("vList", vList);

            writer = new StringWriter();
            template.merge(velocityContext, writer);

            String fUrl = fileurl + File.separatorChar + "correct" + File.separatorChar +station.getStationCode();
            log.info(fUrl);
            File fileUrl = new File(fUrl);
            if (!fileUrl.exists()) {// 判断目录是否存在
                fileUrl.mkdirs();
            }

            String fileName = "DQ_" + DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyyMMddHHmmss") + "0.RB";

            file = new File(fUrl + File.separatorChar + fileName);


            FileOutputStream os = null;

            try {
                boolean res = file.createNewFile();
                if (res) {
                    os = new FileOutputStream(file);
                    // 采用UTF-8字符集
                    os.write(writer.toString().getBytes("UTF-8"));
                    os.flush();
                } else {
                    log.warn(station.getStationCode() + " 生成DQ文件失败");
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.warn(station.getStationCode() + " 创建DQ文件失败");
            } finally {
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        log.error("文件生成关闭流失败", e);
                    }
                }
            }

        }

        return file;
    }


    /**
     * 光伏数据解析
     *
     * @param data 待解析数据
     * @return
     * @throws Exception
     */
    public List<ForecastData> correctPhotovoltaicData(String data) throws Exception {

        String[] content = data.split("\n");

        List<ForecastData> list = new ArrayList<>();

        for (int i = 3; i < content.length - 1; i++) {

            ForecastData inForecastPowerShortTerm = new ForecastData();
            String column = content[i];
            String[] datas = column.split(CommonStant.SPACE1_CONSTANT);
            inForecastPowerShortTerm.setForecastTime(DateUtil.parse(datas[2], "yyyyMMddHHmmss").getTime());


            inForecastPowerShortTerm.setFpValueCorrect(isNumberOrNull(datas[3]));

            inForecastPowerShortTerm.setSwrCorrect(isNumberOrNull(datas[4]));

            inForecastPowerShortTerm.setDirectRadiationCorrect(isNumberOrNull(datas[5]));

            inForecastPowerShortTerm.setDiffuseRadiationCorrect(isNumberOrNull(datas[6]));

            inForecastPowerShortTerm.setTemperatureCorrect(isNumberOrNull(datas[7]));

            inForecastPowerShortTerm.setHumidityCorrect(isNumberOrNull(datas[8]));

            inForecastPowerShortTerm.setPressureCorrect(isNumberOrNull(datas[9]));

            inForecastPowerShortTerm.setWindSpeedCorrect(isNumberOrNull(datas[10]));

            inForecastPowerShortTerm.setWindDirCorrect(isNumberOrNull(datas[11]));

            inForecastPowerShortTerm.setCorrectTime(LocalDateTime.now());


            list.add(inForecastPowerShortTerm);
        }

        return list;

    }

    /**
     * 风电数据解析
     *
     * @param data 待解析数据
     * @return 解析数据
     * @throws Exception
     */
    public List<ForecastData> correctWindData(String data) throws Exception {

        String[] content = data.split("\n");

        List<ForecastData> list = new ArrayList<>();

        for (int i = 3; i < content.length - 1; i++) {

            ForecastData inForecastPowerShortTerm = new ForecastData();
            String column = content[i];

            String[] datas = column.split(CommonStant.SPACE1_CONSTANT);

            inForecastPowerShortTerm.setForecastTime(DateUtil.parse(datas[2], "yyyyMMddHHmmss").getTime());

            inForecastPowerShortTerm.setFpValueCorrect(isNumberOrNull(datas[3]));

            inForecastPowerShortTerm.setWindSpeedCorrect(isNumberOrNull(datas[4]));

            inForecastPowerShortTerm.setWindDirCorrect(isNumberOrNull(datas[5]));

            inForecastPowerShortTerm.setTemperatureCorrect(isNumberOrNull(datas[6]));

            inForecastPowerShortTerm.setHumidityCorrect(isNumberOrNull(datas[7]));

            inForecastPowerShortTerm.setPressureCorrect(isNumberOrNull(datas[8]));

            inForecastPowerShortTerm.setCorrectTime(LocalDateTime.now());

            list.add(inForecastPowerShortTerm);
        }


        return list;

    }

    /**
     * 判断是否是NULL 和是否是数值
     *
     * @param data
     * @return
     */
    public BigDecimal isNumberOrNull(String data) {
        BigDecimal bigDecimal = new BigDecimal("-99");
        if (!data.contains("null") && !data.contains("NULL")) {

            Pattern pattern = Pattern.compile("-[0-9]+(.[0-9]+)?|[0-9]+(.[0-9]+)?");
            Matcher isNum = pattern.matcher(data);
            try {
                if (isNum.matches()) {
                    bigDecimal = new BigDecimal(data).setScale(2, BigDecimal.ROUND_DOWN);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

        }

        return bigDecimal;
    }


    @Override
    public Boolean pullDQData(Station station) {
        return null;
    }

    @Override
    public Boolean pullNWPData(Station station) {
        return null;
    }

    /**
     * 上传文件
     *
     * @return
     */
   /* public boolean uploadFile(String filePath, File file, String stationCode) {
        boolean status = false;
        try {
            MinioClient minioClient = new MinioClient(minloHost, minloUser, minloPwd, false);

            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists("forcast");
            if (!isExist) {
                // 创建一个名为asiatrip的存储桶，用于存储照片的zip文件。
                minioClient.makeBucket("forcast");
            }

            // 使用putObject上传一个文件到存储桶中。
            minioClient.putObject("forcast", filePath, FileUtil.getInputStream(file), new PutObjectOptions(file.length(), -1));

            Map<String, Object> parmer = new HashMap<>();
            parmer.put("stationCode", stationCode);
            parmer.put("fileName", file.getName());
            String s = JSONUtil.toJsonStr(parmer);
            String response = "";

            response = HttpUtil.post(logurl, parmer);
            if (StringUtils.isNotEmpty(response)) {
                boolean isJson = JSONUtil.isJsonObj(response);
                if (isJson) {
                    JSONObject jsonObject = JSONUtil.parseObj(response);
                    String code = jsonObject.getStr("code");
                    if (code.equals("0")) {
                        status = true;
                    } else {
                        log.warn(stationCode + " minlo上送日志响应不为0");
                    }
                } else {
                    log.warn(stationCode + " minlo上送日志响应格式不对");
                }

            }

        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件上传存储服务器失败" + filePath, e);
        }

        return status;
    }*/


}
