package com.gyee.runeconomy.service.agc;


import cn.hutool.core.lang.TypeReference;
import com.gyee.runeconomy.config.GyeeConfig;
import com.gyee.runeconomy.controller.agc.AgcDeviateTag;
import com.gyee.runeconomy.controller.agc.AiPoints;
import com.gyee.runeconomy.controller.agc.FileService;
import com.gyee.runeconomy.init.CacheContext;
import com.gyee.runeconomy.util.realtimesource.feign.IDataAdapter;
import com.gyee.runeconomy.util.realtimesource.feign.RemoteServiceBuilder;
import com.gyee.runeconomy.util.realtimesource.feign.TsDoubleTsData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 读取数据库配置文件
 */
@Order(0)
@Component
public class AgcDeviateService {

    /**
     * 是否是离线版本
     */
    private boolean isOffline;

    /**
     * 离线数据保存路径
     */
    private String filePathPower = "data\\power\\";

    public File jarF = null;

    {
        ApplicationHome h = new ApplicationHome(getClass());
        jarF = h.getSource();
    }

    /**
     * 文件读写
     */
    private FileService fileService;


    @Autowired
    private GyeeConfig config;

    @Resource
    private IDataAdapter iDataAdapter;
    @Autowired
    private RemoteServiceBuilder remoteService;

    /**
     * 获取agc曲线偏差分析需要的数据
     *
     * @param id       场站ID
     * @param startTs  开始时间戳
     * @param endTs    结束时间戳
     * @param interval 数据时间间隔
     * @return 分析数据
     */
    public List<AgcDeviateTag> getAgcDeviateTags(String id, long startTs, long endTs, int interval) {
        List<AgcDeviateTag> ladt = new ArrayList<>();
        List<AiPoints> laps = getAiPoints(id);
        if (laps == null) {
            return ladt;
        }
        for (AiPoints ap : laps) {
            AgcDeviateTag adt = new AgcDeviateTag();
            adt.setName(ap.getName());
            List<TsDoubleTsData> lpd = getPointData(ap, startTs, endTs, interval);
            adt.setValues(lpd);
            ladt.add(adt);
        }
        // 上限下限
        List<AgcDeviateTag> upperLowerLimits = getUpperLowerLimits(ladt, id);
        ladt.addAll(upperLowerLimits);
        return ladt;
    }

    private List<TsDoubleTsData> getPointData(AiPoints ap, long startTs, long endTs, int interval) {
        List<TsDoubleTsData> lpds = null;
        if (ap.getTag().contains(",")) {
            lpds = getMultiple(ap, startTs, endTs, interval);
        } else {


            if (ap.getTag().startsWith("NEM")) {
                lpds = remoteService.taos().getHistorytsSnap(ap.getTag(), startTs, endTs, interval);
            } else {
                lpds = remoteService.adapterfd().getHistorytsSnap(ap.getTag(), startTs, endTs, interval);
            }

        }
        if (ap.getMultiplier() != 1) {
            for (TsDoubleTsData pd : lpds) {
                pd.setDoubleValue(pd.getDoubleValue() * ap.getMultiplier());
            }
        }
        return lpds;
    }

    /**
     * 获取多个标签点数值
     */
    private List<TsDoubleTsData> getMultiple(AiPoints ap, long startTs, long endTs, int interval) {
        String[] tags = ap.getTag().split(",");
        boolean isFirst = true;
        List<TsDoubleTsData> lpd = new ArrayList<>();
        for (String tag : tags) {
            if (tag.equals("")) {
                continue;
            }

            List<TsDoubleTsData> vals = iDataAdapter.getHistorySnap(tag, startTs, endTs, interval);
            for (int i = 0; i < vals.size(); ++i) {
                if (isFirst) {
                    lpd.addAll(vals);
                    isFirst = false;
                    break;
                } else {
                    TsDoubleTsData pd = lpd.get(i);
                    pd.setDoubleValue(vals.get(i).getDoubleValue() + pd.getDoubleValue());
                }
            }
        }
        return lpd;
    }

    /**
     * 获取上限下限
     */
    private List<AgcDeviateTag> getUpperLowerLimits(List<AgcDeviateTag> ladt, String id) {
        // 装机容量
        double capacity = getCapacity(id);
        // 偏差
        double deviation = capacity * 0.03;
        // 有功设定
        Optional<AgcDeviateTag> agcLimit = ladt.stream().filter(ad -> ad.getName().equals("有功设定限值")).findFirst();

        List<AgcDeviateTag> la = new ArrayList<>();
        if (!agcLimit.isPresent()) {
            return la;
        }
        AgcDeviateTag adtUper = new AgcDeviateTag();
        adtUper.setName("偏差上限");
        adtUper.setValues(new ArrayList<>());
        AgcDeviateTag adtLimt = new AgcDeviateTag();
        adtLimt.setName("偏差下限");
        adtLimt.setValues(new ArrayList<>());

        for (TsDoubleTsData pd : agcLimit.get().getValues()) {
            long ts = pd.getTs();
            TsDoubleTsData pdUper = new TsDoubleTsData();
            pdUper.setTs(ts);
            pdUper.setDoubleValue(pd.getDoubleValue() * 1.03);
            TsDoubleTsData pdLimt = new TsDoubleTsData();
            pdLimt.setTs(ts);
            pdLimt.setDoubleValue(pd.getDoubleValue() * 0.97);
            adtUper.getValues().add(pdUper);
            adtLimt.getValues().add(pdLimt);
        }
        la.add(adtUper);
        la.add(adtLimt);
        return la;
    }


    /**
     * 根据ID获取agc配置信息
     *
     * @param id 场站ID
     * @return 配置信息
     */
    private List<AiPoints> getAiPoints(String id) {
        if (!CacheContext.agcDeviateConfigMap.containsKey(id)) {
            return null;
        }
        AiPoints[] aiPoints = CacheContext.agcDeviateConfigMap.get(id).getAiPoints();
        return Arrays.stream(aiPoints).filter(ap -> ap.getName().contains("功") && !ap.getName().contains("预测")).collect(Collectors.toList());
    }

    private double getCapacity(String id) {
        if (!CacheContext.agcDeviateConfigMap.containsKey(id)) {
            return 0;
        }
        return CacheContext.agcDeviateConfigMap.get(id).getInstalledCapacity();
    }

    /**
     * 获取配置
     *
     * @return
     */
    public Object getConfig() {
        return CacheContext.agcDeviateConfigMap;
    }

    public List<AgcDeviateTag> getAgcDeviateTagsOffline(String id, long startTs, long endTs, int interval) {
        if (!CacheContext.files.containsKey(id)) {
            return new ArrayList<>();
        }
        List<String> ls = CacheContext.files.get(id);

        if (ls == null) {
            return new ArrayList<>();
        }

        int ran = (int) (Math.random() * ls.size());
        return fileService.getFromFile(ls.get(ran), new TypeReference<List<AgcDeviateTag>>() {
        });
    }
}