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.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
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 io.minio.MinioClient;
import io.minio.PutObjectOptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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.stereotype.Component;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringWriter;
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;

@Component
@Slf4j
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;

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

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

    @Value("${minio.host}")
    private String minloHost;

    @Value("${minio.user}")
    private String minloUser;

    @Value("${minio.pwd}")
    private String minloPwd;

    @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);

                            String dataContent = responseVo.getData();
                            if (!dataContent.contains("NULL") && !dataContent.contains("null")) {

                                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());
                                }
                            } else {
                                record.setState(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getSign());
                                record.setStateContent(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getMsg());
                                log.error("=========={}:{} ==>拉取短期修正数据失败  返回响应存在NULL ==========" ,integrationCompany.getName(),st.getStationCode());
                            }


                            if (result) {
                                log.info("=========={}:{} ==> 拉取短期修正数据成功！ ==========" ,integrationCompany.getName(),st.getStationCode());
                                record.setState(QNHLEnum.REQUEST_SUCCESS.getSign());
                                record.setStateContent(QNHLEnum.REQUEST_SUCCESS.getMsg());
                                boolean b = forecastDataService.saveOrUpdateBatch(aList);
                                if(b){
                                    File file = genFile(station);
                                    if(file!=null){
                                        isUpload = uploadFile(station.getStationCode() + "/" + file.getName(), file, station.getStationCode());
                                    }
                                }

                            }

                        } else {

                        }
                    } 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;

    }

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

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


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

        String vmsPath = SystermUtils.getResourceBasePath() + "/vms/DQAMEND.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("forecastTime", DateUtil.format(new Date(a.getForecastTime()), "yyyyMMddHHmmss"));
                map.put("fpValue", a.getFpValue() == null ? "-99" : a.getFpValue());
                map.put("fpValueAmend", a.getFpValueCorrect() == null ? "-99" : a.getFpValueCorrect());
                map.put("swr", a.getSwr() == null ? "-99" : a.getSwr());
                map.put("swrAmend", a.getSwrCorrect() == null ? "-99" : a.getSwrCorrect());
                map.put("directRadiation", a.getDirectRadiation() == null ? "-99" : a.getDirectRadiation());
                map.put("directRadiationAmend", a.getDirectRadiationCorrect() == null ? "-99" : a.getDirectRadiationCorrect());
                map.put("diffuseRadiation", a.getDiffuseRadiation() == null ? "-99" : a.getDiffuseRadiation());
                map.put("diffuseRadiationAmend", a.getDiffuseRadiationCorrect() == null ? "-99" : a.getDiffuseRadiationCorrect());
                map.put("windspeed", a.getWindSpeed() == null ? "-99" : a.getWindSpeed());
                map.put("windspeedAmend", a.getWindSpeedCorrect() == null ? "-99" : a.getWindSpeedCorrect());
                map.put("windDir", a.getWindDir() == null ? "-99" : a.getWindDir());
                map.put("windDirAmend", a.getWindDirCorrect() == null ? "-99" : a.getWindDirCorrect());
                map.put("temperature", a.getTemperature() == null ? "-99" : a.getTemperature());
                map.put("temperatureAmend", a.getTemperatureCorrect() == null ? "-99" : a.getTemperatureCorrect());
                map.put("humidity", a.getHumidity() == null ? "-99" : a.getHumidity());
                map.put("humidityAmend", a.getHumidityCorrect() == null ? "-99" : a.getHumidityCorrect());
                map.put("pressure", a.getPressure() == null ? "-99" : a.getPressure());
                map.put("pressureAmend", a.getPressureCorrect() == null ? "-99" : a.getPressureCorrect());
                vList.add(map);

            }

            velocityContext = new VelocityContext();
            velocityContext.put("sign", "signCode");

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

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

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

            String fileName = "AMENDFORECAST_" + DateUtil.format(new Date(), "yyyyMMddHHmm") + ".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() + " 生成minlo文件失败");
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.warn(station.getStationCode() + " 创建minlo文件失败");
            } finally {
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        log.error("文件生成关闭流失败", e);
                    }
                }
            }

        }

        return file;
    }

    /**
     * 上传文件
     *
     * @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;
    }


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

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


        String dateStr = content[0].split("'")[1];

        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(isNumber(datas[3]));

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

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

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

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

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

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

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

            inForecastPowerShortTerm.setWindDirCorrect(isNumber(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");


        String dateStr = content[0].split("'")[1];

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


        if (content[1].contains("CorrectForecast")) {


            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(isNumber(datas[3]));

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

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

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

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

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

                inForecastPowerShortTerm.setCorrectTime(LocalDateTime.now());

                list.add(inForecastPowerShortTerm);
            }
        } else {
            log.error("解析一体化修正短期异常:{}", "标识错误不为<CorrectForecast>");

        }


        return list;

    }

    /**
     * 判断是否是数值
     *
     * @param data
     * @return
     */
    public BigDecimal isNumber(String data) {
        BigDecimal bigDecimal = 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;
    }


}
