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

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cpp.web.domain.datafactory.BaseParsing;
import com.cpp.web.domain.datafactory.ParsingDq;
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.ForecastPowerShortTermStation;
import com.cpp.web.mapper.datafactory.ParsingDqMapper;
import com.cpp.web.service.datafactory.ParsingDqService;
import com.cpp.web.service.datafactory.ParsingInterface;
import com.cpp.web.service.station.ForecastPowerShortTermStationService;
import com.cpp.web.utils.ParsingFieldUtil;
import com.cpp.web.utils.ParsingFileUtil;
import com.cpp.web.utils.ParsingUtil;
import lombok.AllArgsConstructor;
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;
import java.util.stream.Collectors;

/**
 * 短期解析业务层实现类
 *
 * @author tl
 * @date 2022-05-11 18:07:03
 */
@Service("dqParsing")
@Slf4j
@AllArgsConstructor
@Transactional
public class ParsingDqServiceImpl extends ServiceImpl<ParsingDqMapper, ParsingDq> implements ParsingDqService, ParsingInterface {


    private List<ParsingDq> parsingDqs = new ArrayList<>();

    private final ForecastPowerShortTermStationService forecastPowerShortTermStationService;

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

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

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

    @Override
    public ParsingResultDto parsing(File file, String stationCode) {
        ParsingResultDto parsingResultDto = new ParsingResultDto();
        parsingResultDto.setFileType(FileTypeEnum.dq.name());
        parsingResultDto.setFileName(file.getName());

        try {
            List<ForecastPowerShortTermStation> forecastPowerShortTermStationList = new ArrayList();

            List<ParsingDq> parsingDqList = selectByStationCode(stationCode);

            if (!parsingDqList.isEmpty()) {
                ParsingDq parsingDqInfo = parsingDqList.get(0);
                List<String> fileContent = ParsingFileUtil.getFileContent(file);
                if (parsingDqInfo.getDataType().equals(ParsingFieldUtil.MULTI)) {//多行操作
                    Date forecastTime = parsingForecastTime(parsingDqInfo.getForecastTime(), fileContent);
                    Date time = forecastTime;
                    if (forecastTime != null) {//解析时间成功才可以进行以下操作
                        if (parsingDqInfo.getFpValue() != null) {
                            List<BigDecimal> fpValues = parsingFpValue(parsingDqInfo.getFpValue(), fileContent);
                            if (fpValues.size() > 0) {
                                for (BigDecimal fpValue : fpValues) {
                                    ForecastPowerShortTermStation forecastPowerShortTermStation = new ForecastPowerShortTermStation();
                                    forecastPowerShortTermStation.setStationCode(stationCode);
                                    forecastPowerShortTermStation.setFpValue(fpValue);
                                    forecastPowerShortTermStation.setTime(time);
                                    forecastPowerShortTermStation.setForecastHowLongAgo(calcHowLongAgo(forecastTime, time));
                                    forecastPowerShortTermStationList.add(forecastPowerShortTermStation);
                                    time = new Date(time.getTime() + 900000L);//递增15分钟
                                }
                                forecastPowerShortTermStationService.saveBatch(forecastPowerShortTermStationList);
                                log.info("解析DQ文件：{} 成功！ O(∩_∩)O", file.getName());
                                parsingResultDto.setStatus("success");
                            } else {
                                parsingResultDto.setMessage("解析短期文件时间错误");
                                log.error("解析DQ文件时间错误");
                            }
                        } else {
                            parsingResultDto.setMessage("短期文件里日期不对");
                            log.error("dq文件里日期不对");
                        }

                    } else {
                        parsingResultDto.setMessage("解析短期文件无数据");
                        log.error("解析短期文件无数据");
                    }

                }


            } else {
                parsingResultDto.setMessage("短期暂无单行解析方式");
                log.info("dq暂无单行解析方式");
            }
        } catch (Exception e) {
            parsingResultDto.setMessage("解析短期数据失败!");
            log.error("解析短期数据失败！ /(ㄒoㄒ)/~~", e);
        } finally {
            return parsingResultDto;
        }
    }

    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：第三列
     * */
    protected 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;
        }
    }

    public List<ParsingDq> selectByStationCode(String stationCode) {
        return this.parsingDqs.stream().filter(p -> p.getStationCode().equals(stationCode)).collect(Collectors.toList());
    }


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