package cn.cecep.talroad.data.analyse.task.constant;

import cn.cecep.talroad.common.core.utils.DateUtils;
import cn.cecep.talroad.common.core.utils.StringUtils;
import cn.cecep.talroad.data.analyse.task.anomaly.analysis.DataAnomalyAbstractService;
import cn.cecep.talroad.data.analyse.task.entity.PreAmProblemFi;
import cn.cecep.talroad.domain.AmProblemFi;
import cn.cecep.talroad.domain.BasDevice;
import cn.cecep.talroad.domain.analysis.BasDeviceParamAnalyse;
import cn.cecep.talroad.domain.BasThresholdConfig;
import cn.cecep.talroad.enums.ProblemTypeEnum;
import cn.cecep.talroad.mapper.BasThresholdConfigMapper;
import cn.cecep.talroad.vo.BasDeviceParamListVo;
import cn.cecep.talroad.vo.FactoryDeviceVo;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 数据恒定抽象处理类
 */
@Slf4j
public abstract class DataConstantAbstractService<T> extends DataAnomalyAbstractService<T> {

    /**
     * 数据异常判断配置 code 正常来说 如果不变的情况下 走默认 异常来不及修改情况可从配置获取
     */
    @Value("${data.logic.code:S02}")
    private String earlyWarningParamCode;

    /**
     * 数据异常判断阈值 恒定时间 默认 6小时
     */
    @Value("${data.logic.default.threshold:5}")
    private Integer defaultThreshold;

    @Autowired
    private BasThresholdConfigMapper basThresholdConfigMapper;

    @Override
    protected List<AmProblemFi> verify(String deviceId, List<T> deviceRealData, List<BasDeviceParamListVo> deviceBindOnlineParams) {
        Map<String, BasDeviceParamListVo> paramsMap = deviceBindOnlineParams.stream().collect(Collectors.toMap(BasDeviceParamListVo::getParamId, Function.identity()));
        Map<String, List<Object>> paramAllValue = getColumnParamValue(deviceRealData, new ArrayList<>(paramsMap.keySet()));
        List<PreAmProblemFi> preAmProblemFis = new ArrayList<>();
        Map<String,String> pMap = new HashMap<>();
        for (Map.Entry<String, List<Object>> entry : paramAllValue.entrySet()) {
            List<Object> values = entry.getValue();
            //去重
            List<Object> collect = values.stream().distinct().collect(Collectors.toList());
            if (collect.size() != 1){
                //只要去重后 数据不等于1 就代表不是恒定的 直接结束
                continue;
            }
            BasDeviceParamListVo deviceParam = paramsMap.get(entry.getKey());
            if (deviceParam == null){
                continue;
            }
            String startTime = getLogicExceptionsDate(deviceRealData.get(0));
            String endTime = getLogicExceptionsDate(deviceRealData.get(deviceRealData.size() - 1));
            preAmProblemFis.add(new PreAmProblemFi(deviceId,entry.getKey(),startTime,endTime));
        }
        //无异常情况 直接退出
        if (CollectionUtil.isEmpty(preAmProblemFis)){
            return new ArrayList<>();
        }
        //获取 预警设备 和参数的名称 用来组装预警信息
        List<String> deviceIds = preAmProblemFis.stream().map(PreAmProblemFi::getDeviceId).distinct().collect(Collectors.toList());
        List<String> paramIds = preAmProblemFis.stream().map(PreAmProblemFi::getParamId).distinct().collect(Collectors.toList());
        Map<String, BasDevice> deviceMap = queryDeviceByIds(deviceIds);
        Map<String, String> paramsNameByIds = queryParamsNameByIds(paramIds);
        Map<String, BasDeviceParamAnalyse> paramAnalyseMap = queryParamsAnalyseByIds(paramIds);
        return convertPreAmProblemFiToAmProblemFi(preAmProblemFis,deviceMap,paramsNameByIds,paramAnalyseMap,pMap,deviceId);
    }

    public List<AmProblemFi> convertPreAmProblemFiToAmProblemFi(List<PreAmProblemFi> preAmProblemFis,
                                                                Map<String, BasDevice> deviceMap,
                                                                Map<String, String> paramsNameByIds,
                                                                Map<String, BasDeviceParamAnalyse> paramAnalyseMap,
                                                                Map<String,String> pMap,
                                                                String deviceId){
        List<AmProblemFi> result = new ArrayList<>();

        for (PreAmProblemFi preAmProblemFi : preAmProblemFis) {
            BasDeviceParamAnalyse basDeviceParamAnalyse = paramAnalyseMap.get(preAmProblemFi.getParamId());
            String dataType = "1";
            if (basDeviceParamAnalyse != null){
                dataType = basDeviceParamAnalyse.getDataType();
            }
            //生成告警信息
            FactoryDeviceVo factoryDeviceVo = new FactoryDeviceVo();
            BasDevice basDevice = deviceMap.get(deviceId);
            if (basDevice == null){
                log.error("设备信息不存在！deviceId:{}",deviceId);
                continue;
            }
            factoryDeviceVo.setDeviceName(basDevice.getName());
            factoryDeviceVo.setDeviceId(deviceId);
            factoryDeviceVo.setFactoryId(basDevice.getFactoryId());

            //构建报警信息
            String msg = buildMsg(basDevice.getName(),paramsNameByIds.get(preAmProblemFi.getParamId()),
                    preAmProblemFi.getStartTime(),preAmProblemFi.getEndTime());
            //构建报警实体
            AmProblemFi amProblemFi = doProcessAlaram(factoryDeviceVo,dataType,
                    DateUtils.parseDate(preAmProblemFi.getStartTime()),
                    DateUtils.parseDate(preAmProblemFi.getEndTime()),
                    ProblemTypeEnum.SJLJYC, msg,
                    paramsNameByIds.get(preAmProblemFi.getParamId()), preAmProblemFi.getParamId());

            if(amProblemFi!=null){
                String key = deviceId+preAmProblemFi.getParamId();
                String value = pMap.get(key);
                if(StringUtils.isEmpty(value)){
                    pMap.put(key,deviceId);
                    result.add(amProblemFi);
                }
            }
        }
        return result;
    }

    /**
     * 构建报警信息
     */
    private String buildMsg(String deviceName,String paramName,String start,String end){
        return  deviceName + "-" +
                paramName + "-于报警开始时间(" +
                start + ")至报警结束时间(" +
                end + "出现数据连续恒定情况";
    }

    /**
     * 构建报警信息实体
     */
    private AmProblemFi doProcessAlaram(FactoryDeviceVo vo,String problemSources,
                                        Date start, Date end, ProblemTypeEnum problemType, String msg, String param , String paramProperty) {
        AmProblemFi problemFi = new AmProblemFi();
        problemFi.setId(IdUtil.simpleUUID());
        problemFi.setProblemSources(problemSources);
        problemFi.setFactoryId(vo.getFactoryId());
        problemFi.setProblemDetails(msg);
        problemFi.setType(1);
        problemFi.setProblemType(problemType.getCode());
        problemFi.setProblemTreatmentState("1");
        problemFi.setAnalyseTime(start);
        problemFi.setAnalyseTimeEnd(end);
        problemFi.setStationId(vo.getDeviceId());
        problemFi.setStationName(vo.getDeviceName());
        problemFi.setCreateTime(new Date());
        problemFi.setParamName(param);
        problemFi.setInputStartTime(DateUtils.dateTime());
        problemFi.setInputEndTime(DateUtils.dateTime());
        problemFi.setParamProperty(paramProperty);
        Map<String,Object> map = new HashMap<>();
        List<Map<String,Object>> list = new ArrayList<>();
        Map m = new HashMap();
        m.put("deviceId",vo.getDeviceId());
        m.put("params", Arrays.asList(paramProperty.split(",")));
        list.add(m);
        map.put("dcsDeviceList",list);
        problemFi.setExtra(JSON.toJSONString(map));
        return problemFi;
    }
    /**
     * 获取逻辑异常时间
     */
    protected abstract String getLogicExceptionsDate(T entity);

    /**
     * 获取查询实时表开始时间
     */
    protected Date getQueryDataStartDateTime(){
        BasThresholdConfig thresholdConfig = basThresholdConfigMapper.selectByParamCode(earlyWarningParamCode);
        Calendar calendar = Calendar.getInstance();
        if (thresholdConfig == null || thresholdConfig.getThresholdValue() == null){
            calendar.set(Calendar.HOUR_OF_DAY, (calendar.get(Calendar.HOUR_OF_DAY) - defaultThreshold));
            return calendar.getTime();
        }
        int thresholdValue = thresholdConfig.getThresholdValue().intValue();
        if ("小时".equals(thresholdConfig.getUnit())){
            calendar.set(Calendar.HOUR_OF_DAY, (calendar.get(Calendar.HOUR_OF_DAY) - thresholdValue));
        }else if ("分钟".equals(thresholdConfig.getUnit())){
            calendar.set(Calendar.MINUTE, (calendar.get(Calendar.MINUTE) - thresholdValue));
        }
        return calendar.getTime();
    }

    /**
     * 获取查询实时表结束时间
     */
    protected Date getQueryDataEndDateTime(){
        return Calendar.getInstance().getTime();
    }

    @Override
    protected boolean filterDeviceParamTaskSwitch(BasDeviceParamAnalyse analyse){
        return "1".equals(analyse.getContourEw());
    }

    /**
     * 获取所有设备ids
     * 需要自行实现
     */
    protected abstract List<String> queryDeviceIds();

    /**
     * 获取实时数据
     *
     * @return
     */
    protected abstract List<T> queryReal(List<String> deviceIds,Date startTime,Date endTime);

}
