package com.jiayue.insu.inclientqn.service.client;

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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jiayue.insu.inclientqn.constant.CommonStant;
import com.jiayue.insu.inclientqn.entity.*;
import com.jiayue.insu.inclientqn.inenum.QNHLEnum;
import com.jiayue.insu.inclientqn.inenum.StatusEnum;
import com.jiayue.insu.inclientqn.mapper.CorrforeStMapper;
import com.jiayue.insu.inclientqn.model.RequestVo;
import com.jiayue.insu.inclientqn.model.ResponseVo;
import com.jiayue.insu.inclientqn.permisson.com.ComPermisson;
import com.jiayue.insu.inclientqn.service.*;
import com.jiayue.insu.inclientqn.util.RequestUtils;
import com.jiayue.insu.inclientqn.util.SystermUtils;
import com.jiayue.insu.minio.util.MinioUtilService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

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;

/**
 * @description:
 * @author: yuanhao
 * @createDate: 2021/9/27
 * @version: 1.0
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CorrforeService extends ServiceImpl<CorrforeStMapper, CorrforeSt> {


    private final RecordService recordService;

    private final StationService stationService;

    private final CorrforeStService corrforeStService;

    private final VelocityEngine velocityEngine;

    private final ComPermisson comPermisson;

    private final MinioUtilService minioUtilService;

    private final CorrectUltraShortTermService correctUltraShortTermService;

    private final RepairPlanService repairPlanService;


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


    public void downLoadUltraShortTerm(long signTime){

        Station station = stationService.findThis();
        //标记为要生成超短期的时刻
        LocalDateTime signLDT = LocalDateTimeUtil.of(signTime).plusMinutes(15L);

        Record record = new Record();
        record.setType(CommonStant.RECORD_TYPE_CORRECT_DATA);
        record.setContent(QNHLEnum.DATA_CORRULTRSHOR_TYPE.getCode());
        record.setCreateTime(LocalDateTime.now());

        //标记为要生成超短期的时刻
        record.setTime(signLDT);

        RequestVo requestVo = RequestVo.CORRECT_US(station.getSignCode(), null, signTime);
        JSONObject json = JSONUtil.parseObj(requestVo, true);
        String body = json.toString();
        String response = RequestUtils.post(station.getDownloadurl(), body, station.getComKey());
        if (RequestUtils.checkResponse(response, record)) {

            ResponseVo responseVo = JSONUtil.toBean(response, ResponseVo.class);
            String code = responseVo.getRetCode();

            if (code.equals(QNHLEnum.REQUEST_SUCCESS.getCode())) {


                JSONObject jsonObject = JSONUtil.parseObj(responseVo.getData());

                if(genUs(station,jsonObject)){

                    correctUltraShortTerm(jsonObject.get("data").toString(),signLDT);

                    record.setState(StatusEnum.SUCCESS.getSign());
                    record.setStateContent(responseVo.getRetMsg());
                }else{
                    record.setState(StatusEnum.GEN_FILE_FAIL.getSign());
                    record.setStateContent(StatusEnum.GEN_FILE_FAIL.getMsg());
                }



            } else {
                record.setState(code);
                record.setStateContent(responseVo.getRetMsg());
            }
        }

        recordService.save(record);

    }

    public void downLoadRepairPlan(long signTime){

        Station station = stationService.findThis();

        LocalDateTime localDateTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
        Record record = new Record();
        record.setType(CommonStant.RECORD_TYPE_CORRECT_DATA);
        record.setContent(QNHLEnum.DATA_REPAPLAN_TYPE.getCode());
        record.setCreateTime(LocalDateTime.now());
        record.setTime(localDateTime);

        RequestVo requestVo = RequestVo.CORRECT_RP(null, signTime);
        JSONObject json = JSONUtil.parseObj(requestVo, true);
        String body = json.toString();
        String response = RequestUtils.post(station.getDownloadurl(), body, station.getComKey());

        if (RequestUtils.checkResponse(response, record)) {

            ResponseVo responseVo = JSONUtil.toBean(response, ResponseVo.class);
            String code = responseVo.getRetCode();

            if (code.equals(QNHLEnum.REQUEST_SUCCESS.getCode())) {

                if(genRp(station,responseVo.getData())){

                    repairPlan(responseVo.getData(),localDateTime);

                    record.setState(StatusEnum.SUCCESS.getSign());
                    record.setStateContent(responseVo.getRetMsg());
                }else{
                    record.setState(StatusEnum.GEN_FILE_FAIL.getSign());
                    record.setStateContent(StatusEnum.GEN_FILE_FAIL.getMsg());
                }



            } else {
                record.setState(code);
                record.setStateContent(responseVo.getRetMsg());
            }
        }


        recordService.save(record);

    }

    /**
     * 下载修正文件，从嘉越云上
     *
     * @param station
     * @return
     */
    public boolean downLoadCorrforeFile(Station station) {

        Record record = new Record();
        record.setType(CommonStant.RECORD_TYPE_PULL_CORRECT_JY);
        LocalDateTime localDateTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
        record.setTime(localDateTime);
        record.setCreateTime(LocalDateTime.now());

        boolean isUpload = false;

        try {
            List<String> names = minioUtilService.listObjects(bucketName, station.getStationCode(), true);
            boolean isFile = false;
            String downfileName = "";
            String fileName = station.getStationCode() + "/DQ_" + DateUtil.format(DateUtil.beginOfDay(new Date()), "yyyyMMdd");
            for (String name : names) {
                if (name.contains(fileName)) {
                    isFile = true;
                    downfileName = name;
                    break;
                }
            }

            if (isFile) {
                minioUtilService.downloadObject(bucketName, downfileName, station.getLocalFilePath() + File.separatorChar + downfileName.split("/")[1]);
                record.setState(StatusEnum.SUCCESS.getSign());
            }else{
                record.setState(StatusEnum.FILE_NULL.getSign());
            }

        } catch (Exception e) {
            e.printStackTrace();
            record.setState(StatusEnum.DOWNLOAD_FILE_ERROR.getSign());
            record.setStateContent(StatusEnum.DOWNLOAD_FILE_ERROR.getMsg());
        }


        recordService.save(record);
        return isUpload;
    }

    /**
     * 下载修正预测数据，从一体化上
     *
     * @param station
     * @return
     */
    public boolean downLoadCorrforeData(Station station) {

        Record record = new Record();
        record.setType(CommonStant.RECORD_TYPE_PULL_CORRECT);
        LocalDateTime localDateTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
        record.setTime(localDateTime);
        record.setCreateTime(LocalDateTime.now());


        String token = station.getComKey();
        LocalDateTime tokenTime = station.getKeyTime();

        String dataPullUrl = station.getDownloadurl();


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

        if (StrUtil.isEmpty(token) || LocalDateTime.now().isAfter(tokenTime)) {
            if (comPermisson.generateKey(station)) {
                station = stationService.findThis();
                token = station.getComKey();
                tokenTime = station.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())) {

                            log.info(station.getStationCode() + " 请求短期修正数据返回内容:{}", response);

                            try {

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

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

                                /**************检测解析数据完整性*******************/
                                BigDecimal one = new BigDecimal("1");
                                BigDecimal checkCount = new BigDecimal(station.getDays().toString()).add(one).multiply(new BigDecimal("96")).add(one);

                                if (list.size() > 0) {
                                    if (list.size() < checkCount.intValue()) {
                                        log.warn("========== 请求短期修正数据缺数: {}", list.size());
                                    }
                                    corrforeStService.updateBetweenForecastTime(list.get(0).getTimeFormat(), list.get(list.size() - 1).getTimeFormat(), list);
                                    genFile(station, list);
                                    result = true;


                                } else {
                                    record.setState(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getCode());
                                    record.setStateContent(StatusEnum.CONNECT_RESPONSE_CONTENT_NULL.getMsg());
                                }


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

                            } catch (Exception e) {
                                e.printStackTrace();
                                record.setState(StatusEnum.CONNECT_RESPONSE_FORMAT_ERROR.getSign());
                                record.setStateContent("解析短期或生成文件失败");
                                log.error("========== 解析短期或生成文件失败 ");
                            }


                            if (result) {
                                log.info("========== 拉取短期修正数据成功！ ==========");
                                record.setState(StatusEnum.SUCCESS.getSign());
                                record.setStateContent(String.valueOf(list.size()));

                            }

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

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

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


    /**
     * 光伏数据解析
     *
     * @param data 待解析数据
     * @return
     * @throws Exception
     */
    public List<CorrforeSt> correctPhotovoltaicData(String data) throws Exception {
        List<CorrforeSt> list = new ArrayList<>();

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

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

            CorrforeSt corrforeSt = new CorrforeSt();
            String column = content[i];
            String[] datas = column.split(CommonStant.SPACE1_CONSTANT);
            corrforeSt.setForecastTime(DateUtil.parse(datas[2], "yyyyMMddHHmmss").getTime());
            corrforeSt.setTimeFormat(DateUtil.parse(datas[2], "yyyyMMddHHmmss").toTimestamp().toLocalDateTime());

            corrforeSt.setFpValue(isNumberOrNull(datas[3]));

            corrforeSt.setGlobalR(isNumberOrNull(datas[4]));

            corrforeSt.setDirectR(isNumberOrNull(datas[5]));

            corrforeSt.setDiffuseR(isNumberOrNull(datas[6]));

            corrforeSt.setT(isNumberOrNull(datas[7]));

            corrforeSt.setRh(isNumberOrNull(datas[8]));

            corrforeSt.setP(isNumberOrNull(datas[9]));

            corrforeSt.setWs(isNumberOrNull(datas[10]));

            corrforeSt.setWd(isNumberOrNull(datas[11]));

            corrforeSt.setCorrectTime(LocalDateTime.now());

            Collections.sort(list, Comparator.comparing(CorrforeSt::getForecastTime));

            list.add(corrforeSt);
        }

        return list;

    }

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

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

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


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

            CorrforeSt corrforeSt = new CorrforeSt();
            String column = content[i];
            String[] datas = column.split(CommonStant.SPACE1_CONSTANT);
            corrforeSt.setForecastTime(DateUtil.parse(datas[2], "yyyyMMddHHmmss").getTime());
            corrforeSt.setTimeFormat(DateUtil.parse(datas[2], "yyyyMMddHHmmss").toTimestamp().toLocalDateTime());

            corrforeSt.setFpValue(isNumberOrNull(datas[3]));

            corrforeSt.setWs(isNumberOrNull(datas[4]));

            corrforeSt.setWd(isNumberOrNull(datas[5]));

            corrforeSt.setT(isNumberOrNull(datas[6]));

            corrforeSt.setRh(isNumberOrNull(datas[7]));

            corrforeSt.setP(isNumberOrNull(datas[8]));

            corrforeSt.setCorrectTime(LocalDateTime.now());

            Collections.sort(list, Comparator.comparing(CorrforeSt::getForecastTime));

            list.add(corrforeSt);
        }


        return list;

    }


    public boolean correctUltraShortTerm(String content,LocalDateTime signTime){
        boolean result = true;

        try {
            List<CorrectUltraShortTerm> list = new ArrayList<>();

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


            for (int i = 3; i < contents.length-1; i++) {
                CorrectUltraShortTerm cus = new CorrectUltraShortTerm();
                String column = contents[i];
                String[] datas = column.split("\\s+");
                cus.setSignTime(signTime);
                cus.setRequestTime(LocalDateTime.now());
                cus.setPassTime(LocalDateTime.now());
                cus.setForecastTime( DateUtil.parse(datas[2], "yyyyMMddHHmmss").toTimestamp().toLocalDateTime());
                cus.setRatio(new BigDecimal(datas[3]));
                list.add(cus);
            }

            correctUltraShortTermService.saveBatch(list);
        }catch (Exception e){
            e.printStackTrace();
            result = false;
        }

        return result;


    }

    public boolean repairPlan(String content,LocalDateTime signTime){
        boolean result = true;

        try {
            List<RepairPlan> list = new ArrayList<>();

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


            for (int i = 3; i < contents.length-1; i++) {
                RepairPlan rp = new RepairPlan();
                String column = contents[i];
                String[] datas = column.split("\\s+");
                rp.setSignTime(signTime);
                rp.setRequestTime(LocalDateTime.now());
                rp.setPassTime(LocalDateTime.now());
                rp.setStartTime( DateUtil.parse(datas[2], "yyyyMMddHHmmss").toTimestamp().toLocalDateTime());
                rp.setEndTime( DateUtil.parse(datas[3], "yyyyMMddHHmmss").toTimestamp().toLocalDateTime());
                rp.setCap(new BigDecimal(datas[4]));
                list.add(rp);
            }

            repairPlanService.saveBatch(list);

        }catch (Exception e){
            e.printStackTrace();
            result = false;
        }

        return result;


    }



    /**
     * 判断是否是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, List<CorrforeSt> list) {

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

            list.sort(Comparator.comparing(CorrforeSt::getForecastTime));
            List<Map<String, Object>> vList = new ArrayList<>();

            for (CorrforeSt a : list) {
                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);


            File fileUrl = new File(station.getLocalFilePath());
            if (!fileUrl.exists()) {// 判断目录是否存在
                fileUrl.mkdirs();
            }

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

            file = new File(station.getLocalFilePath() + 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);
                    }
                }
                log.info("执行生成文件完毕："+station.getLocalFilePath() + File.separatorChar + fileName);
            }

        }

        return file;
    }


    public boolean genUs(Station station, JSONObject jsonObject){
        boolean result = true;

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


            velocityContext.put("content",  jsonObject.get("data").toString());

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


            File fileUrl = new File(station.getLocalFilePath());
            if (!fileUrl.exists()) {// 判断目录是否存在
                fileUrl.mkdirs();
            }

            String fileName = jsonObject.get("fileName").toString() ;
            String[] s = fileName.split("_");
            String fn = "CDQ_"+s[1]+s[2]+"00.RB";
            file = new File(station.getLocalFilePath() + File.separatorChar + fn);


            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 {
                    result = false;
                    log.warn(station.getStationCode() + " 生成修正超短期系数文件失败");
                }
            } catch (IOException e) {
                e.printStackTrace();
                result = false;
                log.warn(station.getStationCode() + " 创建修正超短期系数文件失败");
            } finally {
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        log.error("文件生成关闭流失败", e);
                    }
                }
                log.info("执行生成文件完毕："+station.getLocalFilePath() + File.separatorChar + fileName);
            }

        }

        return result;
    }


    public boolean genRp(Station station, String content){
        boolean result = true;

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


            velocityContext.put("content", content);

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


            File fileUrl = new File(station.getLocalFilePath());
            if (!fileUrl.exists()) {// 判断目录是否存在
                fileUrl.mkdirs();
            }

            String fileName = "JX_"+LocalDateTimeUtil.format(LocalDateTimeUtil.beginOfDay(LocalDateTime.now()),"yyyyMMddHHmmss")+".RB" ;

            file = new File(station.getLocalFilePath() + 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 {
                    result = false;
                    log.warn(station.getStationCode() + " 生成修正超短期系数文件失败");
                }
            } catch (IOException e) {
                e.printStackTrace();
                result = false;
                log.warn(station.getStationCode() + " 创建修正超短期系数文件失败");
            } finally {
                if (os != null) {
                    try {
                        os.close();
                    } catch (IOException e) {
                        log.error("文件生成关闭流失败", e);
                    }
                }
                log.info("执行生成文件完毕："+station.getLocalFilePath() + File.separatorChar + fileName);
            }

        }

        return result;
    }
}
