package com.qqchen.deploy.backend.framework.utils;

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.AccessException;
import org.springframework.expression.TypedValue;

import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Spring EL 表达式解析工具
 * 
 * <p>支持三种表达式格式：
 * <ul>
 *   <li>变量引用: <code>${deploy.applicationName}</code> → "SSO管理后台"</li>
 *   <li>条件判断: <code>${deploy.status == 'SUCCESS' ? '成功' : '失败'}</code> → "成功"</li>
 *   <li>复杂运算: <code>${deploy.duration > 60 ? '耗时较长' : '正常'}</code> → "耗时较长"</li>
 *   <li>模板字符串: <code>"应用 ${deploy.applicationName} 部署${deploy.status == 'SUCCESS' ? '成功' : '失败'}"</code></li>
 * </ul>
 * 
 * <p>使用示例：
 * <pre>{@code
 * Map<String, Object> variables = new HashMap<>();
 * Map<String, Object> deploy = new HashMap<>();
 * deploy.put("applicationName", "SSO管理后台");
 * deploy.put("status", "SUCCESS");
 * deploy.put("duration", 120);
 * variables.put("deploy", deploy);
 * 
 * // 简单变量
 * String result1 = SpelExpressionResolver.resolve("${deploy.applicationName}需要部署", variables);
 * // 结果: "SSO管理后台需要部署"
 * 
 * // 条件判断
 * String result2 = SpelExpressionResolver.resolve(
 *     "部署${deploy.status == 'SUCCESS' ? '成功' : '失败'}", variables);
 * // 结果: "部署成功"
 * 
 * // 复杂表达式
 * String result3 = SpelExpressionResolver.resolve(
 *     "应用 ${deploy.applicationName} 部署耗时 ${deploy.duration > 60 ? '较长' : '正常'}", variables);
 * // 结果: "应用 SSO管理后台 部署耗时 较长"
 * }</pre>
 * 
 * @author qqchen
 * @date 2025-11-04
 */
@Slf4j
public class SpelExpressionResolver {

    /**
     * 表达式解析器（线程安全，可复用）
     */
    private static final ExpressionParser PARSER = new SpelExpressionParser();

    /**
     * 表达式匹配正则：${...}
     * 使用非贪婪匹配，支持嵌套表达式
     */
    private static final Pattern EXPRESSION_PATTERN = Pattern.compile("\\$\\{([^}]+)\\}");

    /**
     * 解析包含 EL 表达式的字符串模板
     * 
     * @param template 模板字符串，可包含多个 ${...} 表达式
     * @param variables 上下文变量（支持嵌套 Map）
     * @return 解析后的字符串
     */
    public static String resolve(String template, Map<String, Object> variables) {
        if (template == null || template.isEmpty()) {
            return template;
        }

        // 如果不包含表达式，直接返回
        if (!template.contains("${")) {
            return template;
        }

        try {
            // 创建表达式上下文，支持 Map 的属性式访问
            StandardEvaluationContext context = createContext(variables);

            // 解析模板中的所有表达式
            Matcher matcher = EXPRESSION_PATTERN.matcher(template);
            StringBuffer result = new StringBuffer();

            while (matcher.find()) {
                String expression = matcher.group(1); // 提取 ${} 中的表达式
                
                try {
                    // 解析表达式
                    Expression exp = PARSER.parseExpression(expression);
                    Object value = exp.getValue(context);
                    
                    // 替换表达式为值
                    String replacement = value != null ? value.toString() : "";
                    matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
                    
                    log.debug("解析表达式: ${{{}}}} -> {}", expression, value);
                } catch (Exception e) {
                    log.warn("表达式解析失败: ${{{}}}, 保留原样, 错误: {}", expression, e.getMessage());
                    // 解析失败时保留原始表达式
                    matcher.appendReplacement(result, Matcher.quoteReplacement("${" + expression + "}"));
                }
            }
            matcher.appendTail(result);

            return result.toString();
        } catch (Exception e) {
            log.error("模板解析失败: {}", template, e);
            return template; // 失败时返回原始模板
        }
    }

    /**
     * 解析单个纯表达式（返回原始类型）
     * 
     * <p>示例：
     * <pre>{@code
     * // 返回 Boolean
     * Boolean result = SpelExpressionResolver.evaluateExpression(
     *     "deploy.status == 'SUCCESS'", variables, Boolean.class);
     * 
     * // 返回 Integer
     * Integer duration = SpelExpressionResolver.evaluateExpression(
     *     "deploy.duration", variables, Integer.class);
     * }</pre>
     * 
     * @param expression 纯表达式（不需要 ${} 包裹）
     * @param variables 上下文变量
     * @param resultType 期望的返回类型
     * @param <T> 返回类型
     * @return 表达式计算结果
     */
    public static <T> T evaluateExpression(String expression, Map<String, Object> variables, Class<T> resultType) {
        if (expression == null || expression.isEmpty()) {
            return null;
        }

        try {
            // 创建支持 Map 属性访问的上下文
            StandardEvaluationContext context = createContext(variables);

            Expression exp = PARSER.parseExpression(expression);
            return exp.getValue(context, resultType);
        } catch (Exception e) {
            log.error("表达式计算失败: {}", expression, e);
            throw new RuntimeException("表达式计算失败: " + expression, e);
        }
    }

    /**
     * 创建支持 Map 属性式访问的 SpEL 上下文
     * 
     * <p>关键：添加自定义 PropertyAccessor，允许像访问对象属性一样访问 Map 的 key
     * 这样可以直接使用 `deploy.xxx` 语法，而不需要 `#deploy.xxx` 或 `['deploy'].xxx`
     * 
     * @param variables 变量 Map
     * @return SpEL 执行上下文
     */
    private static StandardEvaluationContext createContext(Map<String, Object> variables) {
        StandardEvaluationContext context = new StandardEvaluationContext(variables);
        
        // 添加自定义的 Map 属性访问器
        context.addPropertyAccessor(new MapPropertyAccessor());
        
        return context;
    }

    /**
     * 自定义 Map 属性访问器
     * 
     * <p>允许像访问对象属性一样访问 Map 的 key，支持嵌套访问
     */
    private static class MapPropertyAccessor implements PropertyAccessor {

        @Override
        public Class<?>[] getSpecificTargetClasses() {
            return new Class<?>[]{Map.class};
        }

        @Override
        public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
            return target instanceof Map && ((Map<?, ?>) target).containsKey(name);
        }

        @Override
        public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
            if (target instanceof Map) {
                Object value = ((Map<?, ?>) target).get(name);
                return new TypedValue(value);
            }
            return TypedValue.NULL;
        }

        @Override
        public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
            return false; // 只读
        }

        @Override
        public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
            throw new UnsupportedOperationException("不支持写入操作");
        }
    }

    /**
     * 批量解析模板字段
     * 
     * @param templates 模板字符串数组
     * @param variables 上下文变量
     * @return 解析后的字符串数组
     */
    public static String[] resolveAll(String[] templates, Map<String, Object> variables) {
        if (templates == null) {
            return null;
        }

        String[] results = new String[templates.length];
        for (int i = 0; i < templates.length; i++) {
            results[i] = resolve(templates[i], variables);
        }
        return results;
    }

    /**
     * 检查字符串是否包含 EL 表达式
     * 
     * @param text 文本
     * @return true 如果包含 ${...} 表达式
     */
    public static boolean containsExpression(String text) {
        return text != null && text.contains("${");
    }

    /**
     * 通用方法：自动解析对象中所有包含 EL 表达式的字符串字段
     * 
     * <p>使用反射遍历对象的所有字段，自动识别并解析包含 ${} 的字符串字段。
     * 避免了硬编码字段名，支持动态扩展。
     * 
     * <p>使用示例：
     * <pre>{@code
     * ApprovalTaskDTO dto = new ApprovalTaskDTO();
     * dto.setTaskDescription("${deploy.applicationName}需要部署");
     * dto.setApprovalTitle("部署${deploy.status == 'SUCCESS' ? '成功' : '失败'}");
     * 
     * // 自动解析 dto 中所有包含表达式的字段
     * SpelExpressionResolver.resolveObject(dto, variables);
     * 
     * // dto 的字段已被自动解析：
     * // taskDescription: "SSO管理后台需要部署"
     * // approvalTitle: "部署成功"
     * }</pre>
     * 
     * @param target 目标对象（会直接修改其字段值）
     * @param variables 上下文变量
     */
    public static void resolveObject(Object target, Map<String, Object> variables) {
        if (target == null) {
            return;
        }

        Class<?> clazz = target.getClass();
        
        // 遍历所有字段（包括父类字段）
        while (clazz != null && clazz != Object.class) {
            for (java.lang.reflect.Field field : clazz.getDeclaredFields()) {
                // 只处理 String 类型字段
                if (field.getType() != String.class) {
                    continue;
                }

                try {
                    field.setAccessible(true);
                    String value = (String) field.get(target);
                    
                    // 如果字段值包含表达式，则解析
                    if (containsExpression(value)) {
                        String resolved = resolve(value, variables);
                        field.set(target, resolved);
                        log.debug("自动解析字段 {}.{}: {} -> {}", 
                            clazz.getSimpleName(), field.getName(), value, resolved);
                    }
                } catch (IllegalAccessException e) {
                    log.warn("无法访问字段 {}.{}: {}", 
                        clazz.getSimpleName(), field.getName(), e.getMessage());
                }
            }
            
            // 处理父类字段
            clazz = clazz.getSuperclass();
        }
    }

    // ==================== Flowable 集成方法 ====================

    /**
     * 解析包含 EL 表达式的字符串模板（Flowable DelegateExecution 版本）
     * 
     * <p>自动从 Flowable 执行上下文中提取变量，支持复杂表达式：
     * <ul>
     *   <li>简单变量: <code>${deploy.applicationName}</code></li>
     *   <li>条件判断: <code>${deploy.status == 'SUCCESS' ? '成功' : '失败'}</code></li>
     *   <li>复杂运算: <code>${deploy.duration > 60 ? '耗时较长' : '正常'}</code></li>
     * </ul>
     * 
     * <p>使用示例：
     * <pre>{@code
     * // 在 Flowable Delegate 中使用
     * String message = SpelExpressionResolver.resolve(execution,
     *     "应用 ${deploy.applicationName} 部署${deploy.status == 'SUCCESS' ? '成功' : '失败'}");
     * }</pre>
     * 
     * @param execution Flowable 执行上下文
     * @param template 模板字符串，可包含多个 ${...} 表达式
     * @return 解析后的字符串
     */
    public static String resolve(DelegateExecution execution, String template) {
        if (execution == null || template == null) {
            return template;
        }
        
        // 从 Flowable 执行上下文中获取所有变量
        Map<String, Object> variables = execution.getVariables();
        
        // 委托给通用解析方法
        return resolve(template, variables);
    }

    /**
     * 解析包含 EL 表达式的字符串模板（Flowable DelegateTask 版本）
     * 
     * @param task Flowable 任务上下文
     * @param template 模板字符串
     * @return 解析后的字符串
     */
    public static String resolve(DelegateTask task, String template) {
        if (task == null || template == null) {
            return template;
        }
        
        // 从 Flowable 任务上下文中获取所有变量
        Map<String, Object> variables = task.getVariables();
        
        // 委托给通用解析方法
        return resolve(template, variables);
    }

    /**
     * 解析单个纯表达式（返回原始类型）- Flowable DelegateExecution 版本
     * 
     * @param execution Flowable 执行上下文
     * @param expression 纯表达式（不需要 ${} 包裹）
     * @param resultType 期望的返回类型
     * @param <T> 返回类型
     * @return 表达式计算结果
     */
    public static <T> T evaluateExpression(DelegateExecution execution, String expression, Class<T> resultType) {
        if (execution == null || expression == null) {
            return null;
        }
        
        Map<String, Object> variables = execution.getVariables();
        return evaluateExpression(expression, variables, resultType);
    }

    /**
     * 解析单个纯表达式（返回原始类型）- Flowable DelegateTask 版本
     * 
     * @param task Flowable 任务上下文
     * @param expression 纯表达式（不需要 ${} 包裹）
     * @param resultType 期望的返回类型
     * @param <T> 返回类型
     * @return 表达式计算结果
     */
    public static <T> T evaluateExpression(DelegateTask task, String expression, Class<T> resultType) {
        if (task == null || expression == null) {
            return null;
        }
        
        Map<String, Object> variables = task.getVariables();
        return evaluateExpression(expression, variables, resultType);
    }

    /**
     * 解析表达式并返回原始类型 - 自动去除 ${} 包装（Flowable DelegateExecution 版本）
     * 
     * <p>便捷方法，自动处理带或不带 ${} 的表达式
     * 
     * <p>使用示例：
     * <pre>{@code
     * // 自动去除 ${}，返回原始类型
     * Object userIds = SpelExpressionResolver.evaluateAuto(execution, "${approval.userIds}", Object.class);
     * // 如果是列表：userIds instanceof List = true
     * 
     * // 也支持不带 ${} 的表达式
     * Object userIds2 = SpelExpressionResolver.evaluateAuto(execution, "approval.userIds", Object.class);
     * }</pre>
     * 
     * @param execution Flowable 执行上下文
     * @param expression 表达式（可以带 ${} 也可以不带）
     * @param resultType 期望的返回类型
     * @param <T> 返回类型
     * @return 表达式计算结果（原始类型）
     */
    public static <T> T evaluateAuto(DelegateExecution execution, String expression, Class<T> resultType) {
        if (execution == null || expression == null) {
            return null;
        }
        
        // 自动去除 ${} 包装
        String cleanExpression = expression.trim();
        if (cleanExpression.startsWith("${") && cleanExpression.endsWith("}")) {
            cleanExpression = cleanExpression.substring(2, cleanExpression.length() - 1).trim();
        }
        
        return evaluateExpression(execution, cleanExpression, resultType);
    }

    /**
     * 解析表达式并返回原始类型 - 自动去除 ${} 包装（Flowable DelegateTask 版本）
     * 
     * @param task Flowable 任务上下文
     * @param expression 表达式（可以带 ${} 也可以不带）
     * @param resultType 期望的返回类型
     * @param <T> 返回类型
     * @return 表达式计算结果（原始类型）
     */
    public static <T> T evaluateAuto(DelegateTask task, String expression, Class<T> resultType) {
        if (task == null || expression == null) {
            return null;
        }
        
        // 自动去除 ${} 包装
        String cleanExpression = expression.trim();
        if (cleanExpression.startsWith("${") && cleanExpression.endsWith("}")) {
            cleanExpression = cleanExpression.substring(2, cleanExpression.length() - 1).trim();
        }
        
        return evaluateExpression(task, cleanExpression, resultType);
    }

    /**
     * 通用方法：自动解析对象中所有包含 EL 表达式的字符串字段 - Flowable DelegateExecution 版本
     * 
     * @param target 目标对象（会直接修改其字段值）
     * @param execution Flowable 执行上下文
     */
    public static void resolveObject(Object target, DelegateExecution execution) {
        if (execution == null) {
            return;
        }
        
        Map<String, Object> variables = execution.getVariables();
        resolveObject(target, variables);
    }

    /**
     * 通用方法：自动解析对象中所有包含 EL 表达式的字符串字段 - Flowable DelegateTask 版本
     * 
     * @param target 目标对象（会直接修改其字段值）
     * @param task Flowable 任务上下文
     */
    public static void resolveObject(Object target, DelegateTask task) {
        if (task == null) {
            return;
        }
        
        Map<String, Object> variables = task.getVariables();
        resolveObject(target, variables);
    }
}

