package com.iailab.module.model.mdk.sample;

import com.iailab.module.data.api.plan.PlanItemApi;
import com.iailab.module.data.api.plan.dto.ApiPlanItemDTO;
import com.iailab.module.data.api.point.DataPointApi;
import com.iailab.module.data.api.point.dto.ApiPointDTO;
import com.iailab.module.data.enums.DataPointFreqEnum;
import com.iailab.module.data.enums.TimeGranularitySecEnum;
import com.iailab.module.model.mcs.pre.enums.PredGranularityEnum;
import com.iailab.module.model.mdk.common.enums.ModelParamType;
import com.iailab.module.model.mdk.sample.dto.SampleData;
import com.iailab.module.model.mdk.sample.dto.SampleInfo;
import com.iailab.module.model.mdk.vo.DataValueVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.util.*;

abstract class SampleDataConstructor {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private DataPointApi dataPointApi;
    @Autowired
    private PlanItemApi planItemApi;

    /**
     * prepareSampleData
     *
     * @param sampleInfo
     * @return
     */
    public abstract List<SampleData> prepareSampleData(SampleInfo sampleInfo) throws Exception;

    /**
     * 补全数据
     *
     * @param length
     * @param dataEntityList
     * @param startTime
     * @param endTime
     * @return
     */
    public List<DataValueVO> completionData(int length, List<DataValueVO> dataEntityList, Date startTime, Date endTime, String paramType, Integer granularity) {
        if (CollectionUtils.isEmpty(dataEntityList) || length == dataEntityList.size()) {
            return dataEntityList;
        } else if (length < dataEntityList.size()) {
            return dataEntityList.subList(dataEntityList.size() - length, dataEntityList.size());
        }

        List<DataValueVO> completionDataEntityList = new ArrayList<>();
        long oneMin = 0L;

        long start = startTime.getTime();
        long end = endTime.getTime();
        long mins = 0L;

        switch (ModelParamType.getEumByCode(paramType)) {
            case NORMALITEM:
            case MERGEITEM:
                // 设置时间偏移量
                mins = calMins(start, end, granularity);
                break;
            case DATAPOINT:
            case PLAN:
                // 设置时间偏移量
                mins = calMins(start, end, granularity);
                break;
            case IND:
            case IND_ASCII:
                // 设置时间偏移量
                mins = calMins(start, end, granularity) + 1;
                break;
            default:
                break;
        }
        Map<Long, Double> sourceDataMap = new HashMap<>(dataEntityList.size());
        for (DataValueVO dataEntity : dataEntityList) {
            if (null != dataEntity.getDataTime()) {
                sourceDataMap.put(dataEntity.getDataTime().getTime(), dataEntity.getDataValue());
            }
        }

        //找出缺少项
        Map<Long, Double> dataMap = new LinkedHashMap<>();
        for (int i = 0; i < mins; i++) {
            Long key = start + oneMin * i;
            Double value = sourceDataMap.get(key);
            dataMap.put(key, value);
        }

        //补充缺少项
        int k = 0;
        Map.Entry<Long, Double> lastItem = null;
        for (Map.Entry<Long, Double> item : dataMap.entrySet()) {
            if (k == 0 && item.getValue() == null) {
                item.setValue(getFirstValue(dataMap));
            } else if (item.getValue() == null) {
                item.setValue(lastItem.getValue());
            }
            k++;
            lastItem = item;

            DataValueVO dataEntity = new DataValueVO();
            dataEntity.setDataTime(new Date(item.getKey()));
            dataEntity.setDataValue(item.getValue());
            completionDataEntityList.add(dataEntity);
        }
        return completionDataEntityList;
    }

    private long calMins(long start, long end, Integer granularity) {
        long oneMin = granularity * 1000L;
        // 设置时间偏移量
        if (granularity >= 24 * 60 * 60) {
            // 如果时间粒度大于等于一天,因为时区问题,特殊处理,否则时间为8:00,而非0:00
            start = start - ((start + 8 * 60 * 60 * 1000) % oneMin);
            end = end - ((end + 8 * 60 * 60 * 1000) % oneMin);
        } else {
            start = start - (start % oneMin);
            end = end - (end % oneMin);
        }
        return ((end - start) / oneMin);
    }

    /**
     * getFirstValue
     *
     * @param dataMap
     * @return
     */
    private Double getFirstValue(Map<Long, Double> dataMap) {
        for (Map.Entry<Long, Double> item : dataMap.entrySet()) {
            if (item.getValue() != null) {
                return item.getValue();
            }
        }
        return null;
    }

}