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

import com.jay.monitor.data.server.enums.MatchRuleEnums;
import com.jay.monitor.data.server.report.alert.rule.MatchValueCondition;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

/**
 * 支持Spring的Expression表达式
 * <p>
 * 具体的使用方式可以参考:
 * - 表达式语法 : {@link 'org.springframework.expression.spel.standard.TokenKind'}
 *
 * @author liukaixiong
 * @Email liukx@elab-plus.com
 * @date 2021/9/8 - 14:07
 */
@Component
public class ExpressionValueCondition implements MatchValueCondition {

    private final ExpressionParser PARSER = new SpelExpressionParser();

    private final StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext();

    private final ParserContext templateParserContext = new TemplateParserContext("${", "}");

    private List<PropertyAccessor> propertyAccessors;

    public ExpressionValueCondition() {
        this.propertyAccessors = new ArrayList<>();
        propertyAccessors.add(new ReflectivePropertyAccessor());
        propertyAccessors.add(new MapAccessor());
        standardEvaluationContext.setPropertyAccessors(propertyAccessors);
    }

    public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
        this.propertyAccessors = propertyAccessors;
    }

    @Override
    public MatchRuleEnums matchRule() {
        return MatchRuleEnums.expression;
    }

    public Expression getExpression(String matchValue) {
        return PARSER.parseExpression(matchValue, templateParserContext);
    }

    @Override
    public boolean match(Object value, String matchValue) {
        Expression expression = PARSER.parseExpression(matchValue, templateParserContext);
        return expression.getValue(standardEvaluationContext, value, Boolean.class);
    }
}
