package com.gyee.generation.service;


import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gyee.common.contant.ContantXk;
import com.gyee.common.model.PointData;
import com.gyee.generation.init.CacheContext;
import com.gyee.generation.model.auto.ProBasicEquipment;
import com.gyee.generation.model.auto.ProBasicEquipmentPoint;
import com.gyee.generation.model.auto.ProEconWtCurveFittingMonth;
import com.gyee.generation.model.auto.TurbineInfoMin;
import com.gyee.generation.model.vo.CurveType;
import com.gyee.generation.model.vo.FitClassVo;
import com.gyee.generation.model.vo.StatData;
import com.gyee.generation.service.auto.IProEconWtCurveFittingMonthService;
import com.gyee.generation.service.auto.ITurbineInfoMinService;
import com.gyee.generation.util.DateUtils;
import com.gyee.generation.util.StringUtils;
import com.gyee.generation.util.realtimesource.IEdosUtil;
import com.gyee.generation.util.redis.RedisService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executor;

@Service
public class GoodnessOfFitService {


    //        private static final Logger logger = LoggerFactory.getLogger(GoodnessOfFitService.class);
    @Resource
    private IEdosUtil edosUtil;
    @Resource
    private IProEconWtCurveFittingMonthService proEconWtCurveFittingMonthService;
    @Resource
    private RedisService redisService;
    @Resource
    private ITurbineInfoMinService turbineInfoMinService;

    public Map<String, Map<String, Double>> goodnessOfFit(String wtId, Date nowDate) throws Exception {

        Date endDate = DateUtils.truncate(nowDate);
        Date startDate = DateUtils.addDays(nowDate, -1);


        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        String year = String.valueOf(c.get(Calendar.YEAR));
        String month = String.valueOf(c.get(Calendar.MONTH) + 1);

        c.setTime(nowDate);

        c.set(Calendar.DAY_OF_MONTH, 1);
        Date startDateM = c.getTime();
        c.set(Calendar.MONTH, 0);
        Date startDateY = c.getTime();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String beginDateString = sdf.format(startDate);
        String endDateString = sdf.format(endDate);
        String startDateMString = sdf.format(startDateM);
        String startDateYString = sdf.format(startDateY);


        Map<String, Map<String, Double>> resultmap = new HashMap<>();

        Map<String, FitClassVo> theMapY = new HashMap<>();
        Map<String, FitClassVo> theMapM = new HashMap<>();
        Map<String, FitClassVo> theMapD = new HashMap<>();
//        if (wtId.equals("NX_FGS_HA_F_WT_0027_EQ")) {
            List<FitClassVo> theList = new ArrayList<>();

            List<ProEconWtCurveFittingMonth> powerList = new ArrayList<>();


            if (redisService.hasKey(CurveType.monthCurve.id + "_" + wtId)) {
                String cp0String = redisService.get(CurveType.monthCurve.id + "_" + wtId);
                powerList = JSONObject.parseObject(cp0String, new TypeReference<List<ProEconWtCurveFittingMonth>>() {
                });
            } else {
                QueryWrapper<ProEconWtCurveFittingMonth> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("year", year).eq("month", month).eq("windturbine_id", wtId);
                powerList = proEconWtCurveFittingMonthService.list(queryWrapper);
            }
            ProBasicEquipment wt = CacheContext.wtmap.get(wtId);


            List<FitClassVo> fitsD = new ArrayList<>();
            List<FitClassVo> fitsM = new ArrayList<>();
            List<FitClassVo> fitsY = new ArrayList<>();


            //月数据筛选日分钟间隔
//            Map<String, ProBasicEquipmentPoint> wtpointmap = CacheContext.wtpAimap.get(wt.getId());
//            ProBasicEquipmentPoint fspoint = wtpointmap.get(ContantXk.CJ_SSFS);
//            List<PointData> fsls = edosUtil.getHistStat(fspoint.getNemCode(), startDate.getTime() / 1000, endDate.getTime() / 1000, null, 900L, StatData.AVG.getValue());
//
//            ProBasicEquipmentPoint glpoint = wtpointmap.get(ContantXk.CJ_SSGL);
//            List<PointData> glls = edosUtil.getHistStat(glpoint.getNemCode(), startDate.getTime() / 1000, endDate.getTime() / 1000, null, 900L, StatData.AVG.getValue());
            List<TurbineInfoMin> dayinfoMins = turbineInfoMinService.selectByTurbineId(wt.getId(), beginDateString, endDateString);
            if (!dayinfoMins.isEmpty()) {
                for (TurbineInfoMin min : dayinfoMins) {
                    FitClassVo po = new FitClassVo();
                    po.setWindturbineId(wt.getId());
                    po.setModelId(wt.getModelId());
                    po.setWindpowerstationId(wt.getWindpowerstationId());

                    po.setSpeed(StringUtils.round(min.getPjfs(), 2));
                    po.setPower(StringUtils.round(min.getPjgl(), 2));
                    fitsD.add(po);
                }
            }
//            if (!fsls.isEmpty() && !glls.isEmpty() && fsls.size() == glls.size()) {
//                for (int i = 0; i < fsls.size(); i++) {
//                    PointData fspd = fsls.get(i);
//                    PointData glpd = glls.get(i);
//                    FitClassVo po = new FitClassVo();
//                    po.setWindturbineId(wt.getId());
//                    po.setModelId(wt.getModelId());
//                    po.setWindpowerstationId(wt.getWindpowerstationId());
//
//                    po.setSpeed(StringUtils.round(fspd.getPointValueInDouble(), 2));
//                    po.setPower(StringUtils.round(glpd.getPointValueInDouble(), 2));
//                    fitsD.add(po);
//                }
//            }


            //月数据筛选15分钟间隔
//            fsls = edosUtil.getHistStat(fspoint.getNemCode(), startDateM.getTime() / 1000, endDate.getTime() / 1000, null, 60 * 60L, StatData.AVG.getValue());
//            glls = edosUtil.getHistStat(glpoint.getNemCode(), startDateM.getTime() / 1000, endDate.getTime() / 1000, null, 60 * 60L, StatData.AVG.getValue());
            List<TurbineInfoMin> monthinfoMins = turbineInfoMinService.selectByTurbineId(wt.getId(), startDateMString, endDateString);
            if (!monthinfoMins.isEmpty()) {
                for (TurbineInfoMin min : monthinfoMins) {
                    FitClassVo po = new FitClassVo();
                    po.setWindturbineId(wt.getId());
                    po.setModelId(wt.getModelId());
                    po.setWindpowerstationId(wt.getWindpowerstationId());
                    po.setSpeed(StringUtils.round(min.getPjfs(), 2));
                    po.setPower(StringUtils.round(min.getPjgl(), 2));
                    fitsM.add(po);
                }
            }
//            if (!fsls.isEmpty() && !glls.isEmpty() && fsls.size() == glls.size()) {
//                for (int i = 0; i < fsls.size(); i++) {
//                    PointData fspd = fsls.get(i);
//                    PointData glpd = glls.get(i);
//                    FitClassVo po = new FitClassVo();
//                    po.setWindturbineId(wt.getId());
//                    po.setModelId(wt.getModelId());
//                    po.setWindpowerstationId(wt.getWindpowerstationId());
//
//                    po.setSpeed(StringUtils.round(fspd.getPointValueInDouble(), 2));
//                    po.setPower(StringUtils.round(glpd.getPointValueInDouble(), 2));
//                    fitsM.add(po);
//                }
//            }

            //年数据筛选15分钟间隔
//            fsls = edosUtil.getHistStat(fspoint.getNemCode(), startDateY.getTime() / 1000, endDate.getTime() / 1000, null, 60 * 60L * 6, StatData.AVG.getValue());
//            glls = edosUtil.getHistStat(glpoint.getNemCode(), startDateY.getTime() / 1000, endDate.getTime() / 1000, null, 60 * 60L * 6, StatData.AVG.getValue());

            List<TurbineInfoMin> yearMins = turbineInfoMinService.selectByTurbineId(wt.getId(), startDateYString, endDateString);
            if (!yearMins.isEmpty()) {
                for (TurbineInfoMin min : yearMins) {
                    FitClassVo po = new FitClassVo();
                    po.setWindturbineId(wt.getId());
                    po.setModelId(wt.getModelId());
                    po.setWindpowerstationId(wt.getWindpowerstationId());
                    po.setSpeed(StringUtils.round(min.getPjfs(), 2));
                    po.setPower(StringUtils.round(min.getPjgl(), 2));
                    fitsY.add(po);
                }
            }

//            if (!fsls.isEmpty() && !glls.isEmpty() && fsls.size() == glls.size()) {
//                for (int i = 0; i < fsls.size(); i++) {
//                    PointData fspd = fsls.get(i);
//                    PointData glpd = glls.get(i);
//                    FitClassVo po = new FitClassVo();
//                    po.setWindturbineId(wt.getId());
//                    po.setModelId(wt.getModelId());
//                    po.setWindpowerstationId(wt.getWindpowerstationId());
//
//                    po.setSpeed(StringUtils.round(fspd.getPointValueInDouble(), 2));
//                    po.setPower(StringUtils.round(glpd.getPointValueInDouble(), 2));
//                    fitsY.add(po);
//                }
//            }

            buildList(theMapY, theList, wt.getWindpowerstationId(), fitsY, powerList);
            buildList(theMapM, theList, wt.getWindpowerstationId(), fitsM, powerList);
            buildList(theMapD, theList, wt.getWindpowerstationId(), fitsD, powerList);


            for (FitClassVo item : theList) {
                double rnew = 0;
                double speed = 0;

                if (item.getEpower() != 0) {
                    rnew = (double) Math.sqrt((double) (item.getPower() / item.getEpower()));
                }
                if (item.getNumber() != 0) {
                    speed = item.getSpeed() / item.getNumber();
                }
                item.setSpeed(speed);
                item.setPower(rnew);
            }


            theMapD.forEach((key, value) -> {
                if (resultmap.containsKey(key)) {
                    Map<String, Double> tempmap = resultmap.get(key);
                    tempmap.put("day", value.getPower() > 1 ? 1 : StringUtils.round(value.getPower(), 2));
                    resultmap.put(key, tempmap);
                } else {
                    Map<String, Double> tempmap = new HashMap<>();
                    tempmap.put("day", value.getPower() > 1 ? 1 : StringUtils.round(value.getPower(), 2));
                    resultmap.put(key, tempmap);
                }

            });

            theMapM.forEach((key, value) -> {

                if (resultmap.containsKey(key)) {
                    Map<String, Double> tempmap = resultmap.get(key);
                    tempmap.put("month", value.getPower() > 1 ? 1 : StringUtils.round(value.getPower(), 2));
                    resultmap.put(key, tempmap);
                } else {
                    Map<String, Double> tempmap = new HashMap<>();
                    tempmap.put("month", value.getPower() > 1 ? 1 : StringUtils.round(value.getPower(), 2));
                    resultmap.put(key, tempmap);
                }

            });

            theMapY.forEach((key, value) -> {
                if (resultmap.containsKey(key)) {
                    Map<String, Double> tempmap = resultmap.get(key);
                    tempmap.put("year", value.getPower() > 1 ? 1 : StringUtils.round(value.getPower(), 2));
                    resultmap.put(key, tempmap);
                } else {
                    Map<String, Double> tempmap = new HashMap<>();
                    tempmap.put("year", value.getPower() > 1 ? 1 : StringUtils.round(value.getPower(), 2));
                    resultmap.put(key, tempmap);
                }

            });

//        }
        return resultmap;
    }


    private void buildList(Map<String, FitClassVo> theMap, List<FitClassVo> theList, String windpowerstationId, List<FitClassVo> fitsY, List<ProEconWtCurveFittingMonth> powerList) {


        for (FitClassVo item : fitsY) {
            Double speed = StringUtils.round(item.getSpeed(), 1);

            String windturbineId = item.getWindturbineId();
            if (CacheContext.theoreticalPowerMap.containsKey(item.getModelId())) {
                if (CacheContext.theoreticalPowerMap.get(item.getModelId()).size() > 0) {


                    if (CacheContext.theoreticalPowerMap.get(item.getModelId()).containsKey(speed)) {
                        Double epower = CacheContext.theoreticalPowerMap.get(item.getModelId()).get(speed).getEnsurePower();


                        buildtheMap(theMap, theList, windpowerstationId, item, speed, epower);


                    }
                } else {
                    if (powerList != null && powerList.size() > 0) {
                        Double finalSpeed = speed;
                        OptionalDouble tempp = powerList.stream()
                                .filter(i -> Objects.equals(i.getSpeed(), finalSpeed) && i.getWindturbineId().equals(windturbineId))
                                .mapToDouble(ProEconWtCurveFittingMonth::getOptimalPower).findFirst();
                        double p;

                        if (tempp.isPresent()) {
                            Double epower = tempp.getAsDouble();

                            buildtheMap(theMap, theList, windpowerstationId, item, speed, epower);
                        } else {
                            DoubleSummaryStatistics summaryStatistics = powerList.stream().filter(i -> i.getWindturbineId().equals(windturbineId))
                                    .mapToDouble(ProEconWtCurveFittingMonth::getSpeed).summaryStatistics();

                            double max = summaryStatistics.getMax();
                            if (speed > max) {
                                summaryStatistics = powerList.stream().filter(i -> i.getWindturbineId().equals(windturbineId)).mapToDouble(ProEconWtCurveFittingMonth::getActualPower).summaryStatistics();
                                p = summaryStatistics.getMax();

                                Double epower = p;

                                buildtheMap(theMap, theList, windpowerstationId, item, speed, epower);
                            }

                        }

                    }
                }

            }
        }
    }

    private static void buildtheMap(Map<String, FitClassVo> theMap, List<FitClassVo> theList, String windpowerstationId, FitClassVo item, Double speed, Double epower) {
        Double value1 = item.getPower() - epower;
        value1 *= value1;
        Double value2 = item.getPower();
        value2 *= value2;


        if (theMap.containsKey(item.getWindturbineId())) {
            FitClassVo vo = theMap.get(item.getWindturbineId());
            int number = vo.getNumber();
            vo.setSpeed(item.getSpeed() + speed);
            vo.setPower(item.getPower() + value1);
            vo.setEpower(epower + value2);
            number = number + 1;
            vo.setNumber(number);
            theMap.put(item.getWindturbineId(), vo);
        } else {
            FitClassVo fit = new FitClassVo();
            fit.setWindturbineId(item.getWindturbineId());
            fit.setWindpowerstationId(windpowerstationId);
            fit.setModelId(item.getModelId());
            fit.setSpeed(speed);
            fit.setPower(value1);
            fit.setEpower(value2);
            fit.setNumber(1);
            theList.add(fit);
            theMap.put(item.getWindturbineId(), fit);
        }
    }

}

