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.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jiayue.insu.incloud.constants.CommonStant;
import com.jiayue.insu.incloud.constants.CompanyConstant;
import com.jiayue.insu.incloud.constants.enums.StatusEnum;
import com.jiayue.insu.incloud.entity.*;
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.HuaWeiObsUtil;
import com.jiayue.insu.incloud.utils.SystermUtils;
import com.jiayue.insu.minio.util.MinioUtilService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
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.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
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 PullCorrectDataForLx implements IPullInitCorrectDataForSH {

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

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

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

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

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

//    @Value("${minio.pull.cloudFileCreateLog}")
//    private String cloudFileCreateLog;

    /**
     * 拉取修正预测数据并生成文件上送minio服务器（林洋请求上下午修正短期数据）
     *
     * @param station 场站信息
     * @return 是否成功
     */
    @Override
    public Boolean pullDQData(Station station) {

        Record record = null;
        LocalTime noon = LocalTime.NOON;
        LocalDateTime noonToday = LocalDateTime.of(LocalDate.now(), noon);
        // 判断当前时间是否在中午12点之前
        if (LocalDateTime.now().isBefore(noonToday)) {
            record = new Record(CommonStant.RECORD_TYPE_PULL_CORRECT, CompanyConstant.COMPANY_LX, station.getStationCode(), null, LocalDateTimeUtil.beginOfDay(LocalDateTime.now()), LocalDateTime.now(), null, null);
        } else {
            record = new Record(CommonStant.RECORD_TYPE_PULL_CORRECT, CompanyConstant.COMPANY_LX, station.getStationCode(), null, noonToday, LocalDateTime.now(), null, null);
        }

        IntegrationCompany integrationCompany = integrationCompanyService.findByCode(CompanyConstant.COMPANY_LX);
//        String dataPullUrl = integrationCompany.getPullUrl();
//        String dataPullUrl = "http://112.2.27.84:4220/changeData";

        boolean result = false;
        boolean isUpload = false;
        String response;
        List<ForecastData> list = new ArrayList<>();
        try {
            DateTime dateTime = DateUtil.parse(DateUtil.today());
            String day = dateTime.toString("yyyyMMdd");
            StringBuilder queryString = new StringBuilder();
//            queryString.append("stationId=").append(station.getStationCode());
            queryString.append("stationId=").append(station.getStationCode());
            queryString.append("&version=").append(day);
            queryString.append("&type=").append("E1".equals(station.getType()) ? 2 : 1);
            String url = "http://61.155.87.36:4220/forecast/changeData?" + queryString.toString();
            // 测试地址
//          String url = "https://113.219.237.106:33631/forecast/changeData?" + queryString.toString();
            // 发送请求
            HttpRequest httpRequest = HttpRequest.get(url)
                    .header("Content-Type", "application/json");
            httpRequest.setGlobalTimeout(20000);
            response = httpRequest.execute().body();

            if (StrUtil.isNotEmpty(response)) {
                boolean isJson = JSONUtil.isJsonObj(response);
                if (isJson) {
                    LxCorrectResponse lxCorrectResponse = JSONUtil.toBean(response, LxCorrectResponse.class);
                    String code = lxCorrectResponse.getCode();
                    if (code.equals("200")) {
                        List<ForecastData> aList = new ArrayList<>();
                        long startTime = DateUtil.beginOfDay(DateUtil.tomorrow()).getTime();
                        long endTime = startTime + 10 * 24 * 3600 * 1000L - 1;
                        aList = forecastDataService.findTimeByStation(station.getStationCode(), startTime, endTime);
//                        log.info(station.getStationCode() + " 请求短期修正数据返回内容:{}", response);
                        try {
                            list = correctWindData(response.toString(), station);

                            BigDecimal checkCount = new BigDecimal(960);
                            if (list.size() < checkCount.intValue()) {
//                            if (false) {
                                record.setState(StatusEnum.DATA_DEFICIENCY.getCode());
                                record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
                                log.warn("========== {}:{} ==> 请求短期修正数据缺数: {}", integrationCompany.getName(), station.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());
                                    } else {
                                        record.setState(StatusEnum.DATA_DEFICIENCY.getCode());
                                        record.setStateContent(StatusEnum.DATA_DEFICIENCY.getMsg());
                                        log.warn("========== {}:{} ==> 请求短期修正数据缺数: {}", integrationCompany.getName(), station.getStationCode(), list.size());
                                        break;
                                    }
                                }

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

                        if (result) {
                            log.info("=========={}:{} ==> 拉取短期修正数据成功！ ==========", integrationCompany.getName(), station.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) {
                                    String pushDate = DateUtil.format(new Date(), "yyyyMMdd");
//                                    boolean flag = minioUtilService.bucketExists(bucketName);
//                                    if (flag) {
                                    try (InputStream in = new FileInputStream(file)) {
                                        byte[] bytes = IOUtils.toByteArray(in);
                                        String fileName = station.getStationCode() + "/" + file.getName();
//                                        String minIoFileUrl = minioUtilService.putObject(bucketName, fileName, in);
                                        String minIoFileUrl = HuaWeiObsUtil.uploadFile(bucketName, fileName, bytes);

                                        // 如果文件放成功，回传文件生成信息到云端
//                                        postFileCreateInfoToCloud(station.getStationCode(), file.getName(), minIoFileUrl);
                                        pushCorr(station, file.getName(), pushDate, minIoFileUrl);
                                    } catch (IOException e) {
                                        e.printStackTrace();
                                    }
                                }
                            }
                        }
                    } else {
                        record.setState(StatusEnum.RESPONSE_FAIL.getSign());
                        record.setStateContent(StatusEnum.RESPONSE_FAIL.getMsg());
                        log.error("=========={}:{} ==>拉取短期修正数据失败 响应码异常 ", integrationCompany.getName(), station.getStationCode());
                    }
                } else {
                    record.setState(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getSign());
                    record.setStateContent(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getMsg());
                    log.error("=========={}:{} ==>拉取短期修正数据失败 接收响应字符串非json格式 ", integrationCompany.getName(), station.getStationCode());
                }
            } else {
                record.setState(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getSign());
                record.setStateContent(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getMsg());
                log.error("=========={}:{} ==> 拉取短期修正数据失败  返回响应内容为空 ==========", integrationCompany.getName(), station.getStationCode());
            }

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

        }
        recordService.save(record);
        return isUpload;

    }


    /**
     * 风电数据解析(飔合科技只修正短期预测数据)
     *
     * @param data 待解析数据
     * @return 解析数据
     * @throws Exception
     */
    public List<ForecastData> correctWindData(String data, Station station) throws Exception {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<ForecastData> list = new ArrayList<>();

        JSONObject jsonObject = new JSONObject(data);

        // 获取data数组
        JSONArray dataArray = jsonObject.getJSONArray("data");

        // 遍历data数组并获取每个对象的值
        for (int i = 0; i < dataArray.size(); i++) {
            JSONObject dataObject = dataArray.getJSONObject(i);
            // 获取具体的值
//            String date = dateFormat.format(DateUtil.parse(dataObject.getStr("date")));
            String date = dateFormat.format(DateUtil.parse(dataObject.getStr("date")));
            String time = dataObject.getStr("time");
            double value = dataObject.getDouble("value");
            String stationId = dataObject.getStr("stationId");
//            String version = dataObject.getStr("version");


            Long forecastTime = simpleDateFormat.parse(date + " " + time + ":00").getTime();
            ForecastData forecastData = new ForecastData();
            forecastData.setCorrectTime(LocalDateTime.now());
            forecastData.setFpValueCorrect(new BigDecimal(value));
            forecastData.setStationCode(station.getStationCode());
            forecastData.setForecastTime(forecastTime);
            forecastData.setInCode(station.getInCode());
            list.add(forecastData);
        }
        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;
    }

    /**
     * 生成文件
     *
     * @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.getFpValueCorrect() == null ? a.getFpValue() : a.getFpValueCorrect());
                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 = "";

            //根据时间区分上送minio文件名
            LocalTime noon = LocalTime.NOON;
            LocalDateTime noonToday = LocalDateTime.of(LocalDate.now(), noon);
            // 文件名区分（上午、下午）
            if (LocalDateTime.now().isBefore(noonToday)) {
                fileName = "DQ_" + DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyyMMddHHmmss") + "0.RB";
            } else {
                fileName = "DQ_" + new SimpleDateFormat("yyyyMMdd").format(new Date())+"1200000.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;

    }


//    /**
//     * 上传文件
//     *
//     * @return
//     */
//    public void postFileCreateInfoToCloud(String stationCode, String fileName, String fileDownloadUrl) {
//        fileDownloadUrl = fileDownloadUrl.split("\\?")[0];
//        Map<String, Object> urlMap = new HashMap<>();
//        urlMap.put("stationCode", stationCode);
//        urlMap.put("stationName", stationCode);
//        urlMap.put("fileName", fileName);
//        urlMap.put("fileDownloadUrl", fileDownloadUrl);
//        urlMap.put("sign", SystermUtils.caluMd5Sign(stationCode + DateUtil.today()));
//        try {
//            String body = HttpUtil.post(cloudFileCreateLog, urlMap, 10000);
//            JSONObject result = JSONUtil.parseObj(body);
//            if (!"0".equals(result.getStr(JsonResultUtil.CODE_TAG))) {
//                log.info("请求V3云平台失败");
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            log.info("请求V3云平台失败");
//        }
//    }


    /**
     * @param station
     * @param fileName
     * @param url
     */
    public void pushCorr(Station station, String fileName, String pushDate, String url) {
        // 如果场站信息为空或者 不推送修正数据
        if (station == null || "0".equals(station.getIsPushCorr())) {
            return;
        }
        Map params = new HashMap(5);
        params.put("stationCode", station.getStationCode());
        params.put("forecastDay", pushDate);
        params.put("forecastFileName", fileName);
        String fileDownloadUrl = url.split("\\?")[0];
        params.put("fileDownloadPath", fileDownloadUrl);
        params.put("remark", "数源:一体化修正");
        log.info("发送下发修正文件请求");
        String repose = HttpUtil.post(pushCorrFileUrl, params, 10000);
        log.info("发送下发修正文件请求，请求响应 {}", repose);
    }

    @Data
    public class LxCorrectResponse {

        private String code;

        private String message;

        private String data;
    }


}
