package com.cpp.web.service.datafactory.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cpp.common.utils.spring.SpringUtils;
import com.cpp.system.service.ISysConfigService;
import com.cpp.web.domain.datafactory.BaseParsing;
import com.cpp.web.domain.datafactory.ParsingCdq;
import com.cpp.web.domain.datafactory.dto.ParsingConfParam;
import com.cpp.web.domain.datafactory.dto.ParsingResultDto;
import com.cpp.web.domain.datafactory.enums.FileTypeEnum;
import com.cpp.web.domain.station.ForecastPowerUltraShortTermRegulation;
import com.cpp.web.domain.station.ForecastPowerUltraShortTermStation;
import com.cpp.web.mapper.datafactory.ParsingCdqMapper;
import com.cpp.web.service.datafactory.ParsingCdqService;
import com.cpp.web.service.datafactory.ParsingInterface;
import com.cpp.web.service.station.ForecastPowerUltraShortTermRegulationService;
import com.cpp.web.service.station.ForecastPowerUltraShortTermStationService;
import com.cpp.web.utils.ParsingFieldUtil;
import com.cpp.web.utils.ParsingFileUtil;
import com.cpp.web.utils.ParsingUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 超短期解析业务层实现类
 *
 * @author tl
 * @date 2022-05-11 18:07:03
 */
@Service("cdqParsing")
@RequiredArgsConstructor
@Slf4j
@Transactional
public class ParsingCdqServiceImpl extends ServiceImpl<ParsingCdqMapper, ParsingCdq> implements ParsingCdqService, ParsingInterface {

    private final ISysConfigService configService;

    private final ForecastPowerUltraShortTermStationService forecastPowerUltraShortTermStationService;

    private List<ParsingCdq> parsingCdqs = new ArrayList<>();

    @Override
    public boolean save(BaseParsing parsingInfo) {
        return save((ParsingCdq) parsingInfo);
    }

    @Override
    public boolean deleteById(Long id) {
        return removeById(id);
    }

    @Override
    public ParsingResultDto parsing(File file, String stationCode) {
        ParsingResultDto parsingResultDto = new ParsingResultDto();
        parsingResultDto.setFileName(file.getName());
        parsingResultDto.setFileType(FileTypeEnum.cdq.name());
        try {
            if (!this.parsingCdqs.isEmpty()) {
                ParsingCdq parsingCdq = this.parsingCdqs.get(0);
                List<String> fileContent = ParsingFileUtil.getFileContent(file);
                if (parsingCdq.getDataType().equals(ParsingFieldUtil.MULTI)) {//多行操作
                    Date forecastTime = parsingForecastTime(parsingCdq.getForecastTime(), fileContent);
                    Date genTime = new Date(forecastTime.getTime() - 900000L);
                    Date time = forecastTime;
                    if (forecastTime != null) {//解析时间成功才可以进行以下操作
                        if (parsingCdq.getFpValue() != null) {
                            List<BigDecimal> fpValues = parsingFpValue(parsingCdq.getFpValue(), fileContent);
                            if (fpValues.size() > 0) {
                                List<ForecastPowerUltraShortTermStation> forecastPowerUltraShortTermStationList = new ArrayList();
                                BigDecimal openCapacity = parsingValue(parsingCdq.getOpenCapacity(), fileContent);
                                for (BigDecimal fpValue : fpValues) {
                                    ForecastPowerUltraShortTermStation forecastPowerUltraShortTermStation = new ForecastPowerUltraShortTermStation();
                                    forecastPowerUltraShortTermStation.setStationCode(stationCode);
                                    forecastPowerUltraShortTermStation.setFpValue(fpValue);
                                    forecastPowerUltraShortTermStation.setGenTime(genTime);
                                    forecastPowerUltraShortTermStation.setTime(time);
                                    forecastPowerUltraShortTermStation.setForecastHowLongAgo(calcHowLongAgo(forecastTime, time));
                                    forecastPowerUltraShortTermStation.setOpenCapacity(openCapacity);
                                    forecastPowerUltraShortTermStationList.add(forecastPowerUltraShortTermStation);
                                    time = new Date(time.getTime() + 900000L);//递增15分钟
                                }
                                int cdqPoint = 16;
                                try {
                                    cdqPoint = Integer.parseInt(configService.selectConfigByKey("require_cdq_point"));
                                } catch (Exception e) {
                                }
                                if (forecastPowerUltraShortTermStationList.size() == cdqPoint) {
                                    forecastPowerUltraShortTermStationService.remove(
                                            new QueryWrapper<ForecastPowerUltraShortTermStation>()
                                                    .eq("gen_time", genTime)
                                                    .eq("station_code", stationCode)
                                                    .between("time", forecastPowerUltraShortTermStationList.get(0).getTime(), forecastPowerUltraShortTermStationList.get(forecastPowerUltraShortTermStationList.size() - 1).getTime()));
                                    forecastPowerUltraShortTermStationService.saveBatch(forecastPowerUltraShortTermStationList);
                                    String syncRegulation = configService.selectConfigByKey("sync_regulation");
                                    if (!syncRegulation.isEmpty() && syncRegulation.equals("true")) {
                                        syncRegulation(stationCode, forecastPowerUltraShortTermStationList, genTime);
                                    }

                                    log.info("[" + stationCode + "]解析超短期文件：{} 成功！ O(∩_∩)O", file.getName());
                                    parsingResultDto.setStatus("success");
                                } else {
                                    parsingResultDto.setMessage("解析超短期文件数据量与要求不一致");
                                    log.error("[" + stationCode + "]解析超短期文件数据量与要求不一致，fileName：{}", file.getName());
                                }
                            } else {
                                parsingResultDto.setMessage("解析超短期文件时间错误");
                                log.error("[" + stationCode + "]解析超短期文件时间错误，fileName：{}", file.getName());
                            }
                        } else {
                            parsingResultDto.setMessage("超短期文件里日期不对");
                            log.error("[" + stationCode + "]超短期文件里日期不对，fileName：{}", file.getName());
                        }
                    } else {
                        parsingResultDto.setMessage("解析超短期文件无数据");
                        log.error("[" + stationCode + "]解析超短期文件无数据，fileName：{}", file.getName());
                    }
                }
            } else {
                parsingResultDto.setMessage("超短期暂无单行解析方式");
                log.error("[" + stationCode + "]超短期暂无单行解析方式，fileName：{}", file.getName());
            }
        } catch (Exception e) {
            parsingResultDto.setMessage("解析超短期数据失败!");
            log.error("[" + stationCode + "]解析超短期数据失败！ /(ㄒoㄒ)/~~，fileName：{}", file.getName(), e);
        } finally {
            return parsingResultDto;
        }
    }

    @Override
    public boolean activationParsingConf() {
        this.parsingCdqs = baseMapper.selectList(null);
        return true;
    }


    //解析预测时间
    protected Date parsingForecastTime(String sign, List<String> fileContent) {
        Date forecastTime = null;
        try {
            ParsingConfParam config = ParsingFieldUtil.getConfig(sign);

            String s = fileContent.get(ParsingUtil.noParseInt(config.getLineNumber()));
            int signIndex = s.indexOf(config.getDataSign());
            String result;
            if (signIndex > 0) {
                int startLength = config.getDataSign().length() + signIndex + 1;
                int length = config.getFormat().length();
                if (String.valueOf(s.charAt(startLength + 1)).equals("'")) {
                    startLength += 1;
                }
                result = s.substring(startLength, startLength + length);

                SimpleDateFormat simpleDateFormat = new SimpleDateFormat(config.getFormat());

                forecastTime = simpleDateFormat.parse(result);

                log.info("解析超短期【预测时间】成功，开始时间为：{}", result);
            } else {
                log.error("解析超短期【预测时间】时公式标识不存在所在行");
            }

        } catch (RuntimeException e) {
            log.error("解析超短期【预测时间】失败");
            e.printStackTrace();
        } finally {
            return forecastTime;
        }

    }


    /*
     * 解析配置格式规则：
     *   s=>>1=>>entity=
     *   s：单行标识
     *   1：取值在1行
     *   entity=：键标记标记
     *
     *   m=>>4-20=>>3
     *   m：多行标识
     *   4-20：取值在4-20行
     *   3：第三列
     * */
    private List<BigDecimal> parsingFpValue(String sign, List<String> fileContent) {
        List<BigDecimal> fpValues = new ArrayList<>();
        try {
            ParsingConfParam config = ParsingFieldUtil.getConfig(sign);

            String[] lineNumber = config.getLineNumber().split("-");
            int startLine = ParsingUtil.noParseInt(lineNumber[0]);
            int endLine = ParsingUtil.noParseInt(lineNumber[1]);

            for (int i = startLine; i <= endLine; i++) {
                String[] strings = ParsingUtil.splitLineWithSpace(fileContent.get(i));
                String result = strings[ParsingUtil.noParseInt(config.getRowNumber())];

                fpValues.add(new BigDecimal(result));
            }

            log.info("解析超短期【预测数据】成功！！！，记录数：{}", fpValues.size());

        } catch (RuntimeException e) {
            log.error("解析超短期【预测数据】失败");
            e.printStackTrace();
        } finally {
            return fpValues;
        }
    }

    /**
     * 计算D+x中的x
     *
     * @param baseTime
     * @param time
     */
    public Integer calcHowLongAgo(Date baseTime, Date time) {
        return ((int) ((time.getTime() - baseTime.getTime()) / 900000L)) + 1;
    }


    private final ForecastPowerUltraShortTermRegulationService powerUltraShortTermRegulationService;

    /**
     * 同步调控后超短期数据表
     *
     * @param stationCode
     * @param forecastPowerUltraShortTermStationList
     * @param genTime
     */
    public void syncRegulation(String stationCode, List<ForecastPowerUltraShortTermStation> forecastPowerUltraShortTermStationList, Date genTime) {
        log.info("同步调控后超短期数据表");
        List<ForecastPowerUltraShortTermRegulation> forecastPowerUltraShortTermRegulationList = new ArrayList<>();
        for (ForecastPowerUltraShortTermStation forecastPowerUltraShortTermStation : forecastPowerUltraShortTermStationList) {
            ForecastPowerUltraShortTermRegulation forecastPowerUltraShortTermRegulation = new ForecastPowerUltraShortTermRegulation();
            forecastPowerUltraShortTermRegulation.setGenTime(forecastPowerUltraShortTermStation.getGenTime());
            forecastPowerUltraShortTermRegulation.setForecastHowLongAgo(forecastPowerUltraShortTermStation.getForecastHowLongAgo());
            forecastPowerUltraShortTermRegulation.setFpValue(forecastPowerUltraShortTermStation.getFpValue());
            forecastPowerUltraShortTermRegulation.setTime(forecastPowerUltraShortTermStation.getTime());
            forecastPowerUltraShortTermRegulation.setOpenCapacity(forecastPowerUltraShortTermStation.getOpenCapacity());
            forecastPowerUltraShortTermRegulation.setStationCode(stationCode);
            forecastPowerUltraShortTermRegulationList.add(forecastPowerUltraShortTermRegulation);
        }

        SpringUtils.getBean(ParsingRcdqServiceImpl.class).scheduleAddCache(forecastPowerUltraShortTermRegulationList, stationCode);
        powerUltraShortTermRegulationService.remove(
                new QueryWrapper<ForecastPowerUltraShortTermRegulation>()
                        .eq("gen_time", genTime)
                        .eq("station_code", stationCode)
                        .between("time", forecastPowerUltraShortTermRegulationList.get(0).getTime(), forecastPowerUltraShortTermRegulationList.get(forecastPowerUltraShortTermRegulationList.size() - 1).getTime()));
        powerUltraShortTermRegulationService.saveBatch(forecastPowerUltraShortTermRegulationList);
    }
}
