package com.njcn.prepare.harmonic.service.mysql.Impl.line;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.common.pojo.enums.response.CommonResponseEnum;
import com.njcn.common.pojo.response.HttpResult;
import com.njcn.common.utils.HttpResultUtil;
import com.njcn.device.pms.pojo.po.Monitor;
import com.njcn.harmonic.pojo.po.day.RStatLimitRateDPO;
import com.njcn.harmonic.pojo.vo.SourceSteadyIndicator;
import com.njcn.harmonic.pojo.vo.ThsStrategyVo;
import com.njcn.oss.utils.FileStorageUtil;
import com.njcn.prepare.enums.*;
import com.njcn.prepare.harmonic.mapper.mysql.line.*;
import com.njcn.prepare.harmonic.pojo.param.SuperviseParam;
import com.njcn.prepare.harmonic.pojo.po.ThsOverRunLog;
import com.njcn.prepare.harmonic.pojo.po.ThsSupervise;
import com.njcn.prepare.harmonic.pojo.vo.SuperviceRunLogVo;
import com.njcn.prepare.harmonic.service.mysql.day.IRStatLimitRateDService;
import com.njcn.prepare.harmonic.service.mysql.line.ThsSuperviseService;
import com.njcn.process.annotaion.HarCurrent;
import com.njcn.process.annotaion.HarVoltage;
import com.njcn.process.annotaion.InterharVoltage;
import com.njcn.process.api.FlowableDefineFeignClient;
import com.njcn.process.pojo.po.ThsWarnStrategyAss;
import com.njcn.system.api.DicDataFeignClient;
import com.njcn.system.pojo.po.DictData;
import com.njcn.user.api.DeptFeignClient;
import com.njcn.user.pojo.po.Dept;
import com.njcn.web.utils.RequestUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Field;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author lxp
 * @since 2023-03-16
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class ThsSuperviseServiceImpl extends ServiceImpl<ThsSuperviseMapper, ThsSupervise> implements ThsSuperviseService {




    private final ThsWarnStrategyMapper thsWarnStrategyMapper;

    private final ThsWarnStrategyAssMapper thsWarnStrategyAssMapper;

    private final PmsMonitorMapper pmsMonitorMapper;

    private final IRStatLimitRateDService rateDService;

    private final DicDataFeignClient dicDataFeignClient;

    private final ThsSuperviseMapper thsSuperviseMapper;

    private final ThsOverRunLogMapper thsOverRunLogMapper;

    private final DeptFeignClient deptFeignClient;

    private final FileStorageUtil fileStorageUtil;
    private static final String DESCRIPTION = "description";

    private final FlowableDefineFeignClient flowableDefineFeignClient;


    @Override
    @Async("asyncExecutor")
    public void creatSupervise(SuperviseParam superviseParam) {
        this.initSupervise(superviseParam);
    }

    @Override
    public HttpResult<String> initSupervise(SuperviseParam superviseParam) {
        SuperviceRunLogVo superviceRunLogVo = new SuperviceRunLogVo();
        List<ThsOverRunLog> overRunLogList = new ArrayList<>();
        if (InitTypeEnum.MANUAL.getCode().equals(superviseParam.getInitType()) && StringUtils.isBlank(superviseParam.getDeptId())) {
            return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.INVALID_PARAMETER, null, "");
        }
        List<ThsStrategyVo> thsStrategyList = this.selectStrategyList(superviseParam);
        //按部门进行分组
        if (CollectionUtil.isNotEmpty(thsStrategyList)) {
            Map<String, List<ThsStrategyVo>> deptMap = thsStrategyList.stream().collect(Collectors.groupingBy(ThsStrategyVo::getDeptId));
            for (Map.Entry<String, List<ThsStrategyVo>> entry : deptMap.entrySet()) {
                String depId = entry.getKey();
                ThsSupervise thsSupervise = new ThsSupervise();
                List<ThsStrategyVo> deptList = entry.getValue();
                List<ThsStrategyVo> oneLevel = deptList.stream().filter(r -> !GradeEnum.THREE_LEVEL.getCode().equals(r.getGrade())).collect(Collectors.toList());//一级或二级策略集合
                List<SourceSteadyIndicator> oneSourceSteadyIndicatorList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(oneLevel)) {
                    for (ThsStrategyVo oneStrategyVo : oneLevel) {
                        List<ThsWarnStrategyAss> oneInterferenceSourceAsses = this.queryWarnStrategyAss(oneStrategyVo.getId(), TypeEnum.SOURCE_TYPE);//干扰源列表
                        List<ThsWarnStrategyAss> oneSteadyIndicatorAsses = this.queryWarnStrategyAss(oneStrategyVo.getId(), TypeEnum.INTERFERENCE_TYPE);//干扰源列表
                        List<String> oneSteadyIndicatorAssesIds = oneSteadyIndicatorAsses.stream().map(ThsWarnStrategyAss::getAssId).collect(Collectors.toList());
                        //封装每一种干扰源和对应的指标
                        for (ThsWarnStrategyAss oneWarnStrategyAss : oneInterferenceSourceAsses) {
                            SourceSteadyIndicator build = SourceSteadyIndicator.builder().id(oneStrategyVo.getId()).operation(oneStrategyVo.getOperation())
                                    .interferenceSource(oneWarnStrategyAss.getAssId())
                                    .steadyIndicator(oneSteadyIndicatorAssesIds)
                                    .deptId(oneStrategyVo.getDeptId())
                                    .type(oneStrategyVo.getType())
                                    .monitorId(oneStrategyVo.getMonitorId())
                                    .build();
                            oneSourceSteadyIndicatorList.add(build);
                        }
                    }
                }
                List<ThsStrategyVo> threeLevel = deptList.stream().filter(r -> GradeEnum.THREE_LEVEL.getCode().equals(r.getGrade())).collect(Collectors.toList());//三级策略集合
                if (CollectionUtil.isNotEmpty(threeLevel)) {
                    for (ThsStrategyVo threeStrategyVo : threeLevel) {
                        Iterator<SourceSteadyIndicator> iterator = oneSourceSteadyIndicatorList.iterator();
                        while (iterator.hasNext()) {
                            SourceSteadyIndicator sourceSteady = iterator.next();
                            if (sourceSteady.getType().equals(threeStrategyVo.getType())) {
                                if (StringUtils.equals(threeStrategyVo.getMonitorId(), sourceSteady.getMonitorId())) {
                                    List<ThsWarnStrategyAss> interferenceSourceAsses = this.queryWarnStrategyAss(threeStrategyVo.getId(), TypeEnum.SOURCE_TYPE);
                                    //干扰源类型id
                                    List<String> threeInterferenceSourceIds = interferenceSourceAsses.stream().map(ThsWarnStrategyAss::getAssId).collect(Collectors.toList());
                                    List<ThsWarnStrategyAss> threeSteadyIndicatorAsses = this.queryWarnStrategyAss(threeStrategyVo.getId(), TypeEnum.INTERFERENCE_TYPE);
                                    //指标类型id
                                    List<String> steadyIndicatorIds = threeSteadyIndicatorAsses.stream().map(ThsWarnStrategyAss::getAssId).collect(Collectors.toList());
                                    for (String threeInterferenceSourceId : threeInterferenceSourceIds) {
                                        if (OperationEnum.AND.getCode().equals(threeStrategyVo.getOperation())) {//处理三级策略的与
                                            if (OperationEnum.AND.getCode().equals(sourceSteady.getOperation())) {
                                                if (StringUtils.equals(threeInterferenceSourceId, sourceSteady.getInterferenceSource()) &&
                                                        steadyIndicatorIds.containsAll(sourceSteady.getSteadyIndicator())) {
                                                    iterator.remove();
                                                }
                                            }
                                        } else {//处理三级策略的或
                                            if (StringUtils.equals(threeInterferenceSourceId, sourceSteady.getInterferenceSource())) {
                                                if (steadyIndicatorIds.containsAll(sourceSteady.getSteadyIndicator())) {
                                                    iterator.remove();
                                                } else {
                                                    List<String> steadyIndicator = sourceSteady.getSteadyIndicator();
                                                    steadyIndicator.removeAll(steadyIndicatorIds);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                if (CollectionUtil.isNotEmpty(oneSourceSteadyIndicatorList)) {
                    oneSourceSteadyIndicatorList.forEach(steady -> {
                        Monitor monitor = pmsMonitorMapper.selectById(steady.getMonitorId());
                        if (monitor != null) {
                            if (StringUtils.equals(monitor.getMonitorTag(), steady.getInterferenceSource())) {//匹配该监测点属于的干扰源类型
                                //查询该监测点的检测数据
                                RStatLimitRateDPO limitRate = this.queryLimitTargetData(monitor.getId());
                                //判断指标是否超标
                                Map<String, Object> limitBoolMap = this.verifyLimit(limitRate, steady);
                                //构建监督数据
                                this.buildData(steady, limitBoolMap, monitor, limitRate, superviseParam.getInitType(), thsSupervise, overRunLogList);

                            }
                        }
                    });
                    //生成技术监督数据
                    HttpResult<Dept> deptById = deptFeignClient.getDeptById(depId);
                    Dept dept = deptById.getData();
                    if (InitTypeEnum.AUTO.getCode().equals(superviseParam.getInitType())) {
                        this.creatData(dept, thsSupervise, overRunLogList);
                    } else {
                        this.buildSuperviseName(thsSupervise, overRunLogList, dept);
                        superviceRunLogVo.setOverRunLog(overRunLogList);
                        superviceRunLogVo.setThsSupervise(thsSupervise);
                    }
                }
            }
        }
        return HttpResultUtil.assembleCommonResponseResult(CommonResponseEnum.SUCCESS, JSON.toJSONString(superviceRunLogVo), "");
    }

    /**
     * 构建技术监督名称
     *
     * @param thsSupervise
     * @param overRunLogList
     * @param dept
     */
    private void buildSuperviseName(ThsSupervise thsSupervise, List<ThsOverRunLog> overRunLogList, Dept dept) {
        if (CollectionUtil.isNotEmpty(overRunLogList)) {
            thsSupervise.setDescription(overRunLogList.get(0).getDescription());
            String str = Arrays.asList(overRunLogList.get(0).getDescription().split(",")).get(0);
            String overItem = str.substring(0, str.indexOf("次") - 1);
            thsSupervise.setName(DateUtil.today() + dept.getName() + overRunLogList.get(0).getName() + "等" + overRunLogList.size() + "个监测点" + overItem);
        }
    }

    //生成技术监督数据
    @DS("process")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void creatData(Dept dept, ThsSupervise thsSupervise, List<ThsOverRunLog> overRunLogList) {
        if (CollectionUtil.isNotEmpty(overRunLogList)) {
            thsSupervise.setDescription(overRunLogList.get(0).getDescription());
            String str = Arrays.asList(overRunLogList.get(0).getDescription().split(",")).get(0);
            String overItem = str.substring(0, str.indexOf("次") - 1);
            thsSupervise.setName(DateUtil.today() + dept.getName() + overRunLogList.get(0).getName() + "等" + overRunLogList.size() + "个监测点" + overItem);
            thsSuperviseMapper.insert(thsSupervise);

            //TODO 解决工作流写死问题
            Map<String, Object> mapParam = new HashMap<>();
            String proInId ="";
            if(thsSupervise.getType() == 0){
                proInId = "flow_yzep99kb:1:a100b48b-da75-11ed-8335-b07b253cdad9";
            }else {
                proInId = "flow_yzep99kb:2:6358e099-dcba-11ed-8026-b07b253cdad9";
            }
            flowableDefineFeignClient.start(proInId,thsSupervise.getSupIndex(),mapParam);

            for (ThsOverRunLog thsOverRunLog : overRunLogList) {
                thsOverRunLogMapper.insert(thsOverRunLog);
            }
        }
    }


    /**
     * 查询策略列表
     *
     * @param superviseParam
     * @return
     */
    @DS("process")
    @Override
    public List<ThsStrategyVo> selectStrategyList(SuperviseParam superviseParam) {
        return thsWarnStrategyMapper.selectStrategyList(superviseParam);
    }

    /**
     * 查询策略绑定的干扰源列表或指标参数列表
     *
     * @param warnId
     * @param typeEnum
     * @return
     */
    @DS("process")
    @Override
    public List<ThsWarnStrategyAss> queryWarnStrategyAss(String warnId, TypeEnum typeEnum) {
        return thsWarnStrategyAssMapper.selectList(new LambdaQueryWrapper<ThsWarnStrategyAss>()
                .eq(ThsWarnStrategyAss::getWarnId, warnId)
                .eq(ThsWarnStrategyAss::getType, typeEnum.getCode()));
    }

    /**
     * 生成监督数据
     *
     * @param limitBoolMap
     */
    @Override
    public void buildData(SourceSteadyIndicator steady, Map<String, Object> limitBoolMap, Monitor monitor, RStatLimitRateDPO limitRate, Integer initType, ThsSupervise thsSupervise, List<ThsOverRunLog> thsOverRunLogs) {
        if (CollectionUtil.isNotEmpty(limitBoolMap)) {
            if (OperationEnum.AND.getCode().equals(steady.getOperation())) {
                for (Map.Entry<String, Object> entry : limitBoolMap.entrySet()) {
                    if (entry.getValue() instanceof Boolean && !(boolean) entry.getValue()) {
                        return;
                    }
                }
                //构建监督数据
                this.buildSuperviseData(steady, monitor, limitRate, limitBoolMap, initType, thsSupervise, thsOverRunLogs);
                //构建告警/预警监测点列表数据
                this.buildOverRunLog(steady, thsSupervise, monitor, limitRate, limitBoolMap, initType, thsOverRunLogs);
                return;
            }
            if (OperationEnum.OR.getCode().equals(steady.getOperation())) {
                for (Map.Entry<String, Object> entry : limitBoolMap.entrySet()) {
                    if (entry.getValue() instanceof Boolean && (boolean) entry.getValue()) {
                        //生成监督数据
                        this.buildSuperviseData(steady, monitor, limitRate, limitBoolMap, initType, thsSupervise, thsOverRunLogs);
                        //生成告警/预警监测点数据
                        this.buildOverRunLog(steady, thsSupervise, monitor, limitRate, limitBoolMap, initType, thsOverRunLogs);
                        return;
                    }
                }
            }
        }
    }


    @Override
    public void buildSuperviseData(SourceSteadyIndicator steady, Monitor monitor, RStatLimitRateDPO limitRate, Map<String, Object> limitBoolMap, Integer initType, ThsSupervise thsSupervise, List<ThsOverRunLog> thsOverRunLogs) {
        if (thsSupervise != null && StringUtils.isBlank(thsSupervise.getSupIndex())) {
            thsSupervise.setSupIndex(IdUtil.simpleUUID());
            thsSupervise.setDeptId(steady.getDeptId());
            thsSupervise.setCreateTime(new Date());
            thsSupervise.setType(steady.getType());
            thsSupervise.setCreateUser(RequestUtil.getUsername());
            thsSupervise.setProgress(ProgressEnum.START.getCode());
            thsSupervise.setCreateType(initType);
        }
    }


    @Override
    public void buildOverRunLog(SourceSteadyIndicator steady, ThsSupervise thsSupervise, Monitor monitor, RStatLimitRateDPO limitRate, Map<String, Object> limitBoolMap, Integer initType, List<ThsOverRunLog> thsOverRunLogs) {
        ThsOverRunLog thsOverRunLog = new ThsOverRunLog();
        thsOverRunLog.setId(IdUtil.simpleUUID());
        thsOverRunLog.setSupIndex(thsSupervise.getSupIndex());
        thsOverRunLog.setLineIndex(monitor.getId());
        thsOverRunLog.setName(monitor.getPowerrName() + "_" + monitor.getName() + "_" + DateUtil.today() + "_" + monitor.getId());
        thsOverRunLog.setUpdateTime(Date.from(limitRate.getTime().atTime(LocalTime.MIDNIGHT).atZone(ZoneId.systemDefault()).toInstant()));
        thsOverRunLog.setCreateTime(new Date());
        List<String> descriptionList = (List) limitBoolMap.get(DESCRIPTION);
        thsOverRunLog.setDescription(StringUtils.join(descriptionList, ","));
        thsOverRunLogs.add(thsOverRunLog);
    }


    @Override
    @DS("pms")
    public RStatLimitRateDPO queryLimitTargetData(String monitorId) {
        RStatLimitRateDPO limitRate = rateDService.getOne(new LambdaQueryWrapper<RStatLimitRateDPO>().eq(RStatLimitRateDPO::getLineId, monitorId)
                .between(RStatLimitRateDPO::getTime,
                        DateUtil.beginOfDay(DateUtil.offsetDay(new Date(), -1)),
                        DateUtil.endOfDay(DateUtil.offsetDay(new Date(), -1))).last("limit 1"));
        return limitRate;
    }


    /**
     * 判断监测数据是否超标
     *
     * @param limitRate
     * @param steady
     */
    private Map<String, Object> verifyLimit(RStatLimitRateDPO limitRate, SourceSteadyIndicator steady) {
        if (limitRate != null) {
            List<String> steadyIndicator = steady.getSteadyIndicator();
            Map<String, Object> limitBoolMap = new HashedMap();
            List<String> descriptionList = new ArrayList<>();
            steadyIndicator.forEach(id -> {
                HttpResult<DictData> dicDataById = dicDataFeignClient.getDicDataById(id);
                if (CommonResponseEnum.SUCCESS.getCode().equals(dicDataById.getCode()) && dicDataById.getData() != null) {
                    SteadyIndicatorEnum steadyIndicatorEnum = SteadyIndicatorEnum.getSteadyIndicatorEnumByCode(dicDataById.getData().getCode());
                    if (null != steadyIndicatorEnum) {
                        switch (steadyIndicatorEnum) {
                            case Negative_Voltage://负序电压不平衡度
                                if (limitRate.getUbalanceOvertime() > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Negative_Voltage.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Negative_Voltage.getMessage().concat(limitRate.getUbalanceOvertime() + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Negative_Voltage.getCode(), false);
                                }
                                break;
                            case Interhar_Voltage://间谐波电压
                                Integer interharVoltageOvertime = this.maxOverTime(limitRate, InterharVoltage.class);
                                if (interharVoltageOvertime > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Interhar_Voltage.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Interhar_Voltage.getMessage().concat(interharVoltageOvertime + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Interhar_Voltage.getCode(), false);
                                }
                                break;
                            case Neg_Current://负序电流
                                if (limitRate.getINegOvertime() > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Neg_Current.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Neg_Current.getMessage().concat(limitRate.getINegOvertime() + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Neg_Current.getCode(), false);
                                }
                                break;
                            case Fre_Deviation://频率偏差
                                if (limitRate.getFreqDevOvertime() > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Fre_Deviation.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Fre_Deviation.getMessage().concat(limitRate.getFreqDevOvertime() + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Fre_Deviation.getCode(), false);
                                }
                                break;
                            case Voltage_Dev://电压偏差
                                if (limitRate.getVoltageDevOvertime() > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Voltage_Dev.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Voltage_Dev.getMessage().concat(limitRate.getVoltageDevOvertime() + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Voltage_Dev.getCode(), false);
                                }
                                break;
                            case Har_Current://谐波电流
                                Integer harCurrentOvertime = this.maxOverTime(limitRate, HarCurrent.class);
                                if (harCurrentOvertime > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Har_Current.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Har_Current.getMessage().concat(harCurrentOvertime + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Har_Current.getCode(), false);
                                }
                                break;
                            case Voltage_Fluc://电压波动与闪变
                                if (limitRate.getFlickerOvertime() > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Voltage_Fluc.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Voltage_Fluc.getMessage().concat(limitRate.getFlickerOvertime() + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Voltage_Fluc.getCode(), false);
                                }
                                break;
                            case Har_Voltage://谐波电压
                                Integer harVoltageOvertime = this.maxOverTime(limitRate, HarVoltage.class);
                                if (harVoltageOvertime > 0) {
                                    limitBoolMap.put(SteadyIndicatorEnum.Har_Voltage.getCode(), true);
                                    descriptionList.add(SteadyIndicatorEnum.Har_Voltage.getMessage().concat(harVoltageOvertime + "次"));
                                } else {
                                    limitBoolMap.put(SteadyIndicatorEnum.Har_Voltage.getCode(), false);
                                }
                                break;
                        }
                    }
                }
            });
            limitBoolMap.put(DESCRIPTION, descriptionList);
            return limitBoolMap;
        }
        return null;
    }

    /***
     * 获取越限最大值
     * @param object
     * @param annotation
     * @return
     */
    private Integer maxOverTime(Object object, Class annotation) {
        Integer maxValue = 0;
        try {
            Class objClass = object.getClass();
            Field[] fields = objClass.getDeclaredFields();
            for (Field field : fields) {
                field.setAccessible(true);
                boolean isAnon = field.isAnnotationPresent(annotation);
                if (isAnon) {
                    Object objValue = field.get(object);
                    if (objValue instanceof Integer) {
                        if ((Integer) objValue > maxValue) {
                            maxValue = (Integer) objValue;
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("获取越限最大值异常：{}", e.toString());
        }
        return maxValue;
    }
}
