package com.ruoyi.ems.strategy.evaluator;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Map;

/**
 * 条件表达式求值器（支持前端简单和复杂格式）
 */
@Slf4j
@Component
public class ConditionEvaluator {

    /**
     * 评估条件表达式
     *
     * @param conditionExpr 条件表达式JSON
     * @param context       上下文变量
     * @return 是否满足条件
     */
    public boolean evaluate(String conditionExpr, Map<String, Object> context) {
        if (conditionExpr == null || conditionExpr.trim().isEmpty()) {
            return true;
        }

        try {
            JSONObject condition = JSON.parseObject(conditionExpr);

            // 支持简单格式: {"left":"Switch","op":"==","right":"1"}
            if (condition.containsKey("left") && condition.containsKey("op")) {
                return evaluateSimple(condition, context);
            }

            // 支持复杂格式: {"logic":"AND","conditions":[...]}
            if (condition.containsKey("logic")) {
                return evaluateComplex(condition, context);
            }

            // 支持旧格式: {"operator":"AND","conditions":[...]}
            if (condition.containsKey("operator")) {
                return evaluateLegacy(condition, context);
            }

            log.warn("未识别的条件格式: {}", conditionExpr);
            return false;

        }
        catch (Exception e) {
            log.error("条件表达式解析失败: {}", conditionExpr, e);
            return false;
        }
    }

    /**
     * 评估简单条件
     * 格式: {"left":"Switch","op":"==","right":"1"}
     */
    private boolean evaluateSimple(JSONObject condition, Map<String, Object> context) {
        String left = condition.getString("left");
        String op = condition.getString("op");
        Object right = condition.get("right");

        // 从上下文获取左侧值
        Object leftValue = getValueFromContext(left, context);

        return compare(leftValue, op, right);
    }

    /**
     * 评估复杂条件（AND/OR）
     * 格式: {"logic":"AND","conditions":[...]}
     */
    private boolean evaluateComplex(JSONObject condition, Map<String, Object> context) {
        String logic = condition.getString("logic");
        JSONArray conditions = condition.getJSONArray("conditions");

        if ("AND".equals(logic)) {
            return conditions.stream().allMatch(c -> evaluateSimple((JSONObject) c, context));
        }
        else if ("OR".equals(logic)) {
            return conditions.stream().anyMatch(c -> evaluateSimple((JSONObject) c, context));
        }

        return false;
    }

    /**
     * 评估旧格式条件（兼容）
     * 格式: {"operator":"AND","conditions":[...]}
     */
    private boolean evaluateLegacy(JSONObject condition, Map<String, Object> context) {
        String operator = condition.getString("operator");
        JSONArray conditions = condition.getJSONArray("conditions");

        if ("AND".equals(operator)) {
            return conditions.stream().allMatch(c -> evaluateCondition((JSONObject) c, context));
        }
        else if ("OR".equals(operator)) {
            return conditions.stream().anyMatch(c -> evaluateCondition((JSONObject) c, context));
        }
        else {
            return evaluateSimpleCondition(condition, context);
        }
    }

    private boolean evaluateCondition(JSONObject condition, Map<String, Object> context) {
        String operator = condition.getString("operator");

        if ("AND".equals(operator) || "OR".equals(operator)) {
            return evaluateLegacy(condition, context);
        }
        else {
            return evaluateSimpleCondition(condition, context);
        }
    }

    private boolean evaluateSimpleCondition(JSONObject condition, Map<String, Object> context) {
        String field = condition.getString("field");
        String operator = condition.getString("operator");
        Object expectedValue = condition.get("value");

        Object actualValue = getValueFromContext(field, context);

        return compare(actualValue, operator, expectedValue);
    }

    /**
     * 从上下文获取值（支持嵌套路径）
     * 支持格式:
     * - "Switch" → context.get("Switch")
     * - "context.Switch" → context.get("Switch")
     * - "newValue" → context.get("newValue")（用于属性变化触发）
     * - "data.temperature" → context.get("data").temperature
     */
    private Object getValueFromContext(String field, Map<String, Object> context) {
        if (field == null || field.trim().isEmpty()) {
            return null;
        }

        // 移除 "context." 前缀
        if (field.startsWith("context.")) {
            field = field.substring(8);
        }

        // 支持嵌套路径
        if (field.contains(".")) {
            String[] parts = field.split("\\.");
            Object current = context.get(parts[0]);

            for (int i = 1; i < parts.length && current != null; i++) {
                if (current instanceof Map) {
                    current = ((Map<?, ?>) current).get(parts[i]);
                }
                else if (current instanceof JSONObject) {
                    current = ((JSONObject) current).get(parts[i]);
                }
                else {
                    return null;
                }
            }

            return current;
        }

        return context.get(field);
    }

    /**
     * 比较两个值
     */
    private boolean compare(Object actual, String operator, Object expected) {
        if (actual == null)
            return false;

        // 数值类型统一转字符串比较（去除小数点后的0）
        String actualStr = String.valueOf(actual).replaceAll("\\.0+$", "");
        String expectedStr = String.valueOf(expected).replaceAll("\\.0+$", "");

        switch (operator) {
            case "==":
            case "equals":
                return actualStr.equals(expectedStr);

            case "!=":
            case "notEquals":
                return !actualStr.equals(expectedStr);

            case ">":
            case "greaterThan":
                return compareNumeric(actual, expected) > 0;

            case ">=":
            case "greaterThanOrEqual":
                return compareNumeric(actual, expected) >= 0;

            case "<":
            case "lessThan":
                return compareNumeric(actual, expected) < 0;

            case "<=":
            case "lessThanOrEqual":
                return compareNumeric(actual, expected) <= 0;

            case "contains":
                return actualStr.contains(expectedStr);

            case "in":
                return expectedStr.contains(actualStr);

            default:
                log.warn("未知的比较运算符: {}", operator);
                return false;
        }
    }

    /**
     * 数值比较
     */
    private int compareNumeric(Object a, Object b) {
        try {
            double va = Double.parseDouble(String.valueOf(a));
            double vb = Double.parseDouble(String.valueOf(b));
            return Double.compare(va, vb);
        }
        catch (NumberFormatException e) {
            log.warn("数值比较失败: {} vs {}", a, b);
            return 0;
        }
    }
}