package com.jay.monitor.data.server.report.alert.rule;

import com.jay.monitor.data.core.model.serializable.base.CommonDataDTO;
import com.jay.monitor.data.server.componts.GroupFactory;
import com.jay.monitor.data.server.enums.MatchRuleEnums;
import com.jay.monitor.data.server.models.dto.alert.AlertDto;
import com.jay.monitor.data.server.models.dto.alert.RealTimeAlert;
import com.jay.monitor.data.server.models.store.AlertRuleConfig;
import com.jay.monitor.data.server.report.alert.AlertSendProcess;
import com.jay.monitor.data.server.report.alert.RuleCacheFactory;
import org.apache.commons.beanutils.BeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * 配置规则触发告警
 *
 * @author liukaixiong
 * @Email liukx@elab-plus.com
 * @date 2021/9/6 - 15:01
 */
@Component
public class ConfigAlertRule implements CommonDataTriggerRule, InitializingBean {
    private Logger logger = LoggerFactory.getLogger(getClass());
    @Autowired
    private List<MatchValueCondition> matchValueConditions;

    @Autowired
    private AlertSendProcess alertSendProcess;

    @Autowired
    private RuleCacheFactory ruleCacheFactory;

    private String prefixCache = "config_alert";

    @Override
    public void alert(CommonDataDTO commonDataDTO) {
        try {

            // 将对象转换成Map方便定位属性
            Map baseMap = BeanUtils.describe(commonDataDTO);

            // 所有项目
            List<AlertRuleConfig> allAlertRuleConfigList = ruleCacheFactory.getCacheRuleList("all");

            processRule(commonDataDTO, allAlertRuleConfigList, baseMap);

            // 查找具体项目规则列表
            List<AlertRuleConfig> projectRuleConfigList =
                ruleCacheFactory.getCacheRuleList(commonDataDTO.getApplicationName());

            // 执行规则匹配
            processRule(commonDataDTO, projectRuleConfigList, baseMap);
        } catch (Exception e) {
            logger.error("配置告警异常", e);
        }
    }

    private void processRule(CommonDataDTO commonDataDTO, List<AlertRuleConfig> alertRuleConfigList, Map baseMap) {
        assert commonDataDTO != null;
        // 遍历规则与属性匹配是否满足
        for (int i = 0; i < alertRuleConfigList.size(); i++) {

            AlertRuleConfig alertRuleConfig = alertRuleConfigList.get(i);

            String fieldName = alertRuleConfig.getFieldName();
            MatchRuleEnums ruleType = alertRuleConfig.getRuleType();

            Object value = baseMap.get(fieldName);

            if (fieldName.equals("all") || MatchRuleEnums.expression == ruleType) {
                value = commonDataDTO;
            }

            if (value != null) {

                String fieldValue = alertRuleConfig.getFieldValue();

                MatchValueCondition matchValueCondition =
                    GroupFactory.getINSTANCE().getObject(prefixCache, ruleType.name(), MatchValueCondition.class);
                boolean match = false;
                try {
                    // 由于表达式录入的时候没有强制的验证一定符合数据内容，所以一旦产生异常不要影响主流程。
                    match = matchValueCondition.match(value, fieldValue);
                } catch (Exception e) {
                    e.printStackTrace();

                    // 停止并修改该规则的应用
                    ruleCacheFactory.forceCloseRule(alertRuleConfig.getId());

                    RealTimeAlert realTimeAlert = new RealTimeAlert();
                    realTimeAlert.setTitle("表达式异常");
                    realTimeAlert.setErrorMessage(e.getMessage() + " -> " + fieldValue);
                    realTimeAlert.setDataId(alertRuleConfig.getId());
                    realTimeAlert.setGroupKeyName(alertRuleConfig.getRuleName());
                    realTimeAlert.setGroupName(alertRuleConfig.getTitle());

                    AlertDto alertDto = new AlertDto(alertRuleConfig.getId(), realTimeAlert);
                    alertSendProcess.send(alertDto);
                }

                // 符合告警规则
                if (match) {

                    RealTimeAlert realTimeAlert = new RealTimeAlert();

                    org.springframework.beans.BeanUtils.copyProperties(commonDataDTO, realTimeAlert);

                    AlertDto alertDto = new AlertDto(alertRuleConfig.getId(), realTimeAlert);

                    alertSendProcess.send(alertDto);
                }
            }
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        GroupFactory.getINSTANCE().registerObject(prefixCache, matchValueConditions, (bean) -> {
            Function<MatchValueCondition, MatchRuleEnums> matchRule = MatchValueCondition::matchRule;
            MatchRuleEnums apply = matchRule.apply((MatchValueCondition)bean);
            if (apply != null) {
                return apply.name();
            }
            return null;
        });
    }
}
