/*
 * 文 件 名:  DynamicSqlBuilder
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2026/1/30
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.util;

import com.ruoyi.ems.domain.ReportDatasource;
import com.ruoyi.ems.domain.ReportField;
import com.ruoyi.ems.domain.ReportQueryConfig;
import com.ruoyi.ems.domain.ReportRelation;
import com.ruoyi.ems.model.ReportQueryResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 动态SQL构建器
 * 根据报表配置动态生成安全的SQL语句
 *
 * @author ruoyi
 * @date 2026-01-30
 */
public class DynamicSqlBuilder {

    private static final Logger logger = LoggerFactory.getLogger(DynamicSqlBuilder.class);

    /** SQL注入检测正则 */
    private static final Pattern SQL_INJECTION_PATTERN = Pattern.compile(
        "(?i)(\\b(select|insert|update|delete|drop|truncate|alter|create|exec|execute|xp_|sp_|0x)\\b)|" +
            "(--|#|/\\*|\\*/|;|'|\")"
    );

    /** 变量占位符正则 ${xxx} */
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{(\\w+)}");

    /** 支持的操作符 */
    private static final Set<String> VALID_OPERATORS = new HashSet<>(Arrays.asList(
        "eq", "ne", "gt", "gte", "lt", "lte", "like", "notLike", "in", "notIn", "between", "isNull", "isNotNull"
    ));

    /** 支持的聚合函数 */
    private static final Set<String> VALID_AGGREGATE_FUNCS = new HashSet<>(Arrays.asList(
        "SUM", "AVG", "MAX", "MIN", "COUNT"
    ));

    /** 支持的排序方向 */
    private static final Set<String> VALID_ORDER_DIRECTIONS = new HashSet<>(Arrays.asList(
        "ASC", "DESC"
    ));

    /**
     * 构建结果对象
     */
    public static class BuildResult {
        private String sql;
        private String countSql;
        private Map<String, Object> params;
        private List<ReportQueryResult.ColumnDefine> columns;
        private boolean success;
        private String errorMsg;

        public BuildResult() {
            this.params = new HashMap<>();
            this.columns = new ArrayList<>();
            this.success = true;
        }

        public static BuildResult error(String msg) {
            BuildResult result = new BuildResult();
            result.success = false;
            result.errorMsg = msg;
            return result;
        }

        // Getters and Setters
        public String getSql() { return sql; }
        public void setSql(String sql) { this.sql = sql; }
        public String getCountSql() { return countSql; }
        public void setCountSql(String countSql) { this.countSql = countSql; }
        public Map<String, Object> getParams() { return params; }
        public void setParams(Map<String, Object> params) { this.params = params; }
        public List<ReportQueryResult.ColumnDefine> getColumns() { return columns; }
        public void setColumns(List<ReportQueryResult.ColumnDefine> columns) { this.columns = columns; }
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }
        public String getErrorMsg() { return errorMsg; }
        public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; }
    }

    /**
     * 构建查询SQL
     *
     * @param datasource  数据源配置
     * @param fields      字段配置Map（key: fieldCode）
     * @param relations   关联配置Map（key: relationCode）
     * @param fieldRelations 字段关联映射Map（key: fieldCode, value: relationCodes）
     * @param queryConfig 查询配置
     * @return 构建结果
     */
    public static BuildResult buildQuerySql(
        ReportDatasource datasource,
        Map<String, ReportField> fields,
        Map<String, ReportRelation> relations,
        Map<String, List<String>> fieldRelations,
        ReportQueryConfig queryConfig) {

        BuildResult result = new BuildResult();

        try {
            // 1. 验证查询配置
            String validateError = validateQueryConfig(queryConfig, fields);
            if (validateError != null) {
                return BuildResult.error(validateError);
            }

            // 2. 确定需要查询的字段
            List<String> selectedFields = queryConfig.getSelectedFields();
            if (CollectionUtils.isEmpty(selectedFields)) {
                // 使用默认字段
                selectedFields = fields.values().stream()
                    .filter(f -> f.getIsDefault() != null && f.getIsDefault() == 1)
                    .map(ReportField::getFieldCode)
                    .collect(Collectors.toList());
            }

            if (CollectionUtils.isEmpty(selectedFields)) {
                return BuildResult.error("请至少选择一个字段");
            }

            // 3. 确定需要的关联
            Set<String> requiredRelations = determineRequiredRelations(selectedFields, fieldRelations, queryConfig);

            // 4. 构建SELECT子句
            StringBuilder selectBuilder = new StringBuilder();
            boolean hasAggregate = queryConfig.getAggregateFields() != null && !queryConfig.getAggregateFields().isEmpty();
            List<String> groupByFields = queryConfig.getGroupBy();
            boolean hasGroupBy = CollectionUtils.isNotEmpty(groupByFields);

            for (int i = 0; i < selectedFields.size(); i++) {
                if (i > 0) selectBuilder.append(", ");
                String fieldCode = selectedFields.get(i);
                ReportField field = fields.get(fieldCode);
                if (field == null) {
                    return BuildResult.error("字段不存在: " + fieldCode);
                }

                String selectExpr = buildSelectExpr(field, queryConfig, hasGroupBy);
                selectBuilder.append(selectExpr);

                // 构建列定义
                result.getColumns().add(new ReportQueryResult.ColumnDefine(field));
            }

            // 5. 构建FROM子句
            StringBuilder fromBuilder = new StringBuilder();
            fromBuilder.append(datasource.getMainTable()).append(" ").append(datasource.getMainAlias());

            // 6. 构建JOIN子句
            StringBuilder joinBuilder = new StringBuilder();
            for (String relationCode : requiredRelations) {
                ReportRelation relation = relations.get(relationCode);
                if (relation != null && relation.getStatus() != null && relation.getStatus() == 1) {
                    joinBuilder.append(" ")
                        .append(relation.getJoinType()).append(" JOIN ")
                        .append(relation.getJoinTable()).append(" ").append(relation.getJoinAlias())
                        .append(" ON ").append(relation.getJoinCondition());
                }
            }

            // 7. 构建WHERE子句
            StringBuilder whereBuilder = new StringBuilder();
            int paramIndex = 0;

            // 基础条件
            if (StringUtils.isNotBlank(datasource.getBaseWhere())) {
                whereBuilder.append(datasource.getBaseWhere());
            }

            // 用户条件
            if (CollectionUtils.isNotEmpty(queryConfig.getConditions())) {
                for (ReportQueryConfig.QueryCondition condition : queryConfig.getConditions()) {
                    // 跳过可选的空条件
                    if (Boolean.TRUE.equals(condition.getOptional()) && isConditionValueEmpty(condition)) {
                        continue;
                    }

                    ReportField field = fields.get(condition.getField());
                    if (field == null) {
                        logger.warn("条件字段不存在: {}", condition.getField());
                        continue;
                    }

                    String conditionSql = buildConditionSql(field, condition, result.getParams(), paramIndex++);
                    if (StringUtils.isNotBlank(conditionSql)) {
                        if (whereBuilder.length() > 0) {
                            String logic = StringUtils.isNotBlank(condition.getLogic()) ? condition.getLogic() : "AND";
                            whereBuilder.append(" ").append(logic.toUpperCase()).append(" ");
                        }
                        whereBuilder.append(conditionSql);
                    }
                }
            }

            // 8. 构建GROUP BY子句
            StringBuilder groupByBuilder = new StringBuilder();
            if (hasGroupBy) {
                for (int i = 0; i < groupByFields.size(); i++) {
                    if (i > 0) groupByBuilder.append(", ");
                    String fieldCode = groupByFields.get(i);
                    ReportField field = fields.get(fieldCode);
                    if (field != null) {
                        groupByBuilder.append(field.getFieldExpr());
                    }
                }
            }

            // 9. 构建ORDER BY子句
            StringBuilder orderByBuilder = new StringBuilder();
            if (CollectionUtils.isNotEmpty(queryConfig.getOrderBy())) {
                for (int i = 0; i < queryConfig.getOrderBy().size(); i++) {
                    if (i > 0) orderByBuilder.append(", ");
                    ReportQueryConfig.OrderByConfig orderBy = queryConfig.getOrderBy().get(i);
                    ReportField field = fields.get(orderBy.getField());
                    if (field != null) {
                        String direction = orderBy.getDirection();
                        if (!VALID_ORDER_DIRECTIONS.contains(direction.toUpperCase())) {
                            direction = "ASC";
                        }
                        // 使用别名或字段表达式
                        String orderExpr = field.getFieldAlias() != null ? field.getFieldAlias() : field.getFieldExpr();
                        orderByBuilder.append(orderExpr).append(" ").append(direction.toUpperCase());
                    }
                }
            } else if (StringUtils.isNotBlank(datasource.getDefaultOrder())) {
                orderByBuilder.append(datasource.getDefaultOrder());
            }

            // 10. 组装完整SQL
            StringBuilder sqlBuilder = new StringBuilder();
            sqlBuilder.append("SELECT ");
            if (Boolean.TRUE.equals(queryConfig.getDistinct())) {
                sqlBuilder.append("DISTINCT ");
            }
            sqlBuilder.append(selectBuilder);
            sqlBuilder.append(" FROM ").append(fromBuilder);
            sqlBuilder.append(joinBuilder);

            if (whereBuilder.length() > 0) {
                sqlBuilder.append(" WHERE ").append(whereBuilder);
            }

            if (groupByBuilder.length() > 0) {
                sqlBuilder.append(" GROUP BY ").append(groupByBuilder);
            }

            if (orderByBuilder.length() > 0) {
                sqlBuilder.append(" ORDER BY ").append(orderByBuilder);
            }

            // 11. 构建COUNT SQL
            StringBuilder countSqlBuilder = new StringBuilder();
            countSqlBuilder.append("SELECT COUNT(");
            if (hasGroupBy) {
                countSqlBuilder.append("DISTINCT ").append(groupByBuilder);
            } else if (Boolean.TRUE.equals(queryConfig.getDistinct())) {
                countSqlBuilder.append("DISTINCT ").append(datasource.getMainAlias()).append(".*");
            } else {
                countSqlBuilder.append("1");
            }
            countSqlBuilder.append(") AS total");
            countSqlBuilder.append(" FROM ").append(fromBuilder);
            countSqlBuilder.append(joinBuilder);
            if (whereBuilder.length() > 0) {
                countSqlBuilder.append(" WHERE ").append(whereBuilder);
            }

            result.setSql(sqlBuilder.toString());
            result.setCountSql(countSqlBuilder.toString());

            logger.debug("Generated SQL: {}", result.getSql());
            logger.debug("Generated Count SQL: {}", result.getCountSql());
            logger.debug("SQL Parameters: {}", result.getParams());

            return result;

        } catch (Exception e) {
            logger.error("构建SQL异常", e);
            return BuildResult.error("构建SQL失败: " + e.getMessage());
        }
    }

    /**
     * 构建汇总查询SQL
     */
    public static BuildResult buildSummarySql(
        ReportDatasource datasource,
        Map<String, ReportField> fields,
        Map<String, ReportRelation> relations,
        Map<String, List<String>> fieldRelations,
        ReportQueryConfig queryConfig) {

        BuildResult result = new BuildResult();

        try {
            // 1. 确定需要的关联
            Set<String> requiredRelations = new HashSet<>();
            if (CollectionUtils.isNotEmpty(queryConfig.getConditions())) {
                for (ReportQueryConfig.QueryCondition condition : queryConfig.getConditions()) {
                    List<String> rels = fieldRelations.get(condition.getField());
                    if (rels != null) requiredRelations.addAll(rels);
                }
            }

            // 2. 构建SELECT子句（只包含聚合字段）
            StringBuilder selectBuilder = new StringBuilder();
            Map<String, String> aggregateFields = queryConfig.getAggregateFields();
            if (aggregateFields == null || aggregateFields.isEmpty()) {
                // 使用可聚合字段的默认聚合函数
                aggregateFields = new HashMap<>();
                for (ReportField field : fields.values()) {
                    if (field.getIsAggregatable() != null && field.getIsAggregatable() == 1
                        && StringUtils.isNotBlank(field.getAggregateFunc())) {
                        aggregateFields.put(field.getFieldCode(), field.getAggregateFunc());
                    }
                }
            }

            if (aggregateFields.isEmpty()) {
                return BuildResult.error("没有可聚合的字段");
            }

            int idx = 0;
            for (Map.Entry<String, String> entry : aggregateFields.entrySet()) {
                if (idx > 0) selectBuilder.append(", ");
                String fieldCode = entry.getKey();
                String aggFunc = entry.getValue().toUpperCase();

                if (!VALID_AGGREGATE_FUNCS.contains(aggFunc)) {
                    logger.warn("无效的聚合函数: {}", aggFunc);
                    continue;
                }

                ReportField field = fields.get(fieldCode);
                if (field == null) {
                    logger.warn("聚合字段不存在: {}", fieldCode);
                    continue;
                }

                String alias = "sum_" + fieldCode;
                selectBuilder.append("ROUND(").append(aggFunc).append("(COALESCE(")
                    .append(field.getFieldExpr()).append(", 0)), 2) AS ").append(alias);

                // 列定义
                ReportQueryResult.ColumnDefine col = new ReportQueryResult.ColumnDefine(field);
                col.setProp(alias);
                col.setLabel(field.getFieldName() + "(" + aggFunc + ")");
                result.getColumns().add(col);
                idx++;
            }

            // 3. 构建FROM子句
            StringBuilder fromBuilder = new StringBuilder();
            fromBuilder.append(datasource.getMainTable()).append(" ").append(datasource.getMainAlias());

            // 4. 构建JOIN子句
            StringBuilder joinBuilder = new StringBuilder();
            for (String relationCode : requiredRelations) {
                ReportRelation relation = relations.get(relationCode);
                if (relation != null && relation.getStatus() != null && relation.getStatus() == 1) {
                    joinBuilder.append(" ")
                        .append(relation.getJoinType()).append(" JOIN ")
                        .append(relation.getJoinTable()).append(" ").append(relation.getJoinAlias())
                        .append(" ON ").append(relation.getJoinCondition());
                }
            }

            // 5. 构建WHERE子句
            StringBuilder whereBuilder = new StringBuilder();
            int paramIndex = 0;

            if (StringUtils.isNotBlank(datasource.getBaseWhere())) {
                whereBuilder.append(datasource.getBaseWhere());
            }

            if (CollectionUtils.isNotEmpty(queryConfig.getConditions())) {
                for (ReportQueryConfig.QueryCondition condition : queryConfig.getConditions()) {
                    if (Boolean.TRUE.equals(condition.getOptional()) && isConditionValueEmpty(condition)) {
                        continue;
                    }

                    ReportField field = fields.get(condition.getField());
                    if (field == null) continue;

                    String conditionSql = buildConditionSql(field, condition, result.getParams(), paramIndex++);
                    if (StringUtils.isNotBlank(conditionSql)) {
                        if (whereBuilder.length() > 0) {
                            String logic = StringUtils.isNotBlank(condition.getLogic()) ? condition.getLogic() : "AND";
                            whereBuilder.append(" ").append(logic.toUpperCase()).append(" ");
                        }
                        whereBuilder.append(conditionSql);
                    }
                }
            }

            // 6. 组装SQL
            StringBuilder sqlBuilder = new StringBuilder();
            sqlBuilder.append("SELECT ").append(selectBuilder);
            sqlBuilder.append(" FROM ").append(fromBuilder);
            sqlBuilder.append(joinBuilder);
            if (whereBuilder.length() > 0) {
                sqlBuilder.append(" WHERE ").append(whereBuilder);
            }

            result.setSql(sqlBuilder.toString());
            logger.debug("Generated Summary SQL: {}", result.getSql());

            return result;

        } catch (Exception e) {
            logger.error("构建汇总SQL异常", e);
            return BuildResult.error("构建汇总SQL失败: " + e.getMessage());
        }
    }

    /**
     * 验证查询配置
     */
    private static String validateQueryConfig(ReportQueryConfig config, Map<String, ReportField> fields) {
        if (config == null) {
            return "查询配置不能为空";
        }

        // 验证字段
        if (CollectionUtils.isNotEmpty(config.getSelectedFields())) {
            for (String fieldCode : config.getSelectedFields()) {
                if (hasSqlInjection(fieldCode)) {
                    return "字段编码包含非法字符: " + fieldCode;
                }
                if (!fields.containsKey(fieldCode)) {
                    return "字段不存在: " + fieldCode;
                }
            }
        }

        // 验证条件
        if (CollectionUtils.isNotEmpty(config.getConditions())) {
            for (ReportQueryConfig.QueryCondition condition : config.getConditions()) {
                if (StringUtils.isNotBlank(condition.getOperator()) && !VALID_OPERATORS.contains(condition.getOperator())) {
                    return "不支持的操作符: " + condition.getOperator();
                }
            }
        }

        // 验证排序
        if (CollectionUtils.isNotEmpty(config.getOrderBy())) {
            for (ReportQueryConfig.OrderByConfig orderBy : config.getOrderBy()) {
                if (hasSqlInjection(orderBy.getField())) {
                    return "排序字段包含非法字符: " + orderBy.getField();
                }
            }
        }

        return null;
    }

    /**
     * 确定需要的关联
     */
    private static Set<String> determineRequiredRelations(
        List<String> selectedFields,
        Map<String, List<String>> fieldRelations,
        ReportQueryConfig queryConfig) {

        Set<String> required = new HashSet<>();

        // 选中字段需要的关联
        for (String fieldCode : selectedFields) {
            List<String> rels = fieldRelations.get(fieldCode);
            if (rels != null) required.addAll(rels);
        }

        // 条件字段需要的关联
        if (CollectionUtils.isNotEmpty(queryConfig.getConditions())) {
            for (ReportQueryConfig.QueryCondition condition : queryConfig.getConditions()) {
                List<String> rels = fieldRelations.get(condition.getField());
                if (rels != null) required.addAll(rels);
            }
        }

        // 分组字段需要的关联
        if (CollectionUtils.isNotEmpty(queryConfig.getGroupBy())) {
            for (String fieldCode : queryConfig.getGroupBy()) {
                List<String> rels = fieldRelations.get(fieldCode);
                if (rels != null) required.addAll(rels);
            }
        }

        // 排序字段需要的关联
        if (CollectionUtils.isNotEmpty(queryConfig.getOrderBy())) {
            for (ReportQueryConfig.OrderByConfig orderBy : queryConfig.getOrderBy()) {
                List<String> rels = fieldRelations.get(orderBy.getField());
                if (rels != null) required.addAll(rels);
            }
        }

        return required;
    }

    /**
     * 构建SELECT表达式
     */
    private static String buildSelectExpr(ReportField field, ReportQueryConfig queryConfig, boolean hasGroupBy) {
        StringBuilder expr = new StringBuilder();

        String fieldExpr = field.getFieldExpr();
        String alias = field.getFieldAlias() != null ? field.getFieldAlias() : field.getFieldCode();

        // 检查是否需要聚合
        boolean needAggregate = false;
        String aggFunc = null;

        if (hasGroupBy && queryConfig.getAggregateFields() != null) {
            aggFunc = queryConfig.getAggregateFields().get(field.getFieldCode());
            if (StringUtils.isNotBlank(aggFunc) && VALID_AGGREGATE_FUNCS.contains(aggFunc.toUpperCase())) {
                needAggregate = true;
            }
        }

        if (needAggregate) {
            // 数值类型聚合需要处理NULL值和小数位数
            if ("number".equals(field.getFieldType())) {
                int decimals = field.getDecimals() != null ? field.getDecimals() : 2;
                expr.append("ROUND(").append(aggFunc.toUpperCase())
                    .append("(COALESCE(").append(fieldExpr).append(", 0)), ")
                    .append(decimals).append(")");
            } else {
                expr.append(aggFunc.toUpperCase()).append("(").append(fieldExpr).append(")");
            }
        } else {
            // 非聚合字段
            if ("number".equals(field.getFieldType()) && field.getDecimals() != null) {
                expr.append("ROUND(COALESCE(").append(fieldExpr).append(", 0), ")
                    .append(field.getDecimals()).append(")");
            } else {
                expr.append(fieldExpr);
            }
        }

        expr.append(" AS ").append(alias);
        return expr.toString();
    }

    /**
     * 构建条件SQL
     */
    private static String buildConditionSql(
        ReportField field,
        ReportQueryConfig.QueryCondition condition,
        Map<String, Object> params,
        int paramIndex) {

        String fieldExpr = field.getFieldExpr();
        String operator = condition.getOperator();
        Object value = condition.getValue();
        Object value2 = condition.getValue2();

        String paramName = "p" + paramIndex;

        switch (operator.toLowerCase()) {
            case "eq":
                params.put(paramName, value);
                return fieldExpr + " = #{params." + paramName + "}";

            case "ne":
                params.put(paramName, value);
                return fieldExpr + " != #{params." + paramName + "}";

            case "gt":
                params.put(paramName, value);
                return fieldExpr + " > #{params." + paramName + "}";

            case "gte":
                params.put(paramName, value);
                return fieldExpr + " >= #{params." + paramName + "}";

            case "lt":
                params.put(paramName, value);
                return fieldExpr + " < #{params." + paramName + "}";

            case "lte":
                params.put(paramName, value);
                return fieldExpr + " <= #{params." + paramName + "}";

            case "like":
                params.put(paramName, "%" + value + "%");
                return fieldExpr + " LIKE #{params." + paramName + "}";

            case "notlike":
                params.put(paramName, "%" + value + "%");
                return fieldExpr + " NOT LIKE #{params." + paramName + "}";

            case "in":
                if (value instanceof Collection) {
                    params.put(paramName, value);
                    return fieldExpr + " IN <foreach collection='params." + paramName + "' item='item' open='(' separator=',' close=')'>#{item}</foreach>";
                } else if (value instanceof String) {
                    // 逗号分隔的字符串
                    List<String> list = Arrays.asList(((String) value).split(","));
                    params.put(paramName, list);
                    return fieldExpr + " IN <foreach collection='params." + paramName + "' item='item' open='(' separator=',' close=')'>#{item}</foreach>";
                }
                return null;

            case "notin":
                if (value instanceof Collection) {
                    params.put(paramName, value);
                    return fieldExpr + " NOT IN <foreach collection='params." + paramName + "' item='item' open='(' separator=',' close=')'>#{item}</foreach>";
                }
                return null;

            case "between":
                params.put(paramName + "_1", value);
                params.put(paramName + "_2", value2);
                return fieldExpr + " BETWEEN #{params." + paramName + "_1} AND #{params." + paramName + "_2}";

            case "isnull":
                return fieldExpr + " IS NULL";

            case "isnotnull":
                return fieldExpr + " IS NOT NULL";

            default:
                logger.warn("未知操作符: {}", operator);
                return null;
        }
    }

    /**
     * 判断条件值是否为空
     */
    private static boolean isConditionValueEmpty(ReportQueryConfig.QueryCondition condition) {
        String operator = condition.getOperator();
        if ("isNull".equalsIgnoreCase(operator) || "isNotNull".equalsIgnoreCase(operator)) {
            return false;
        }
        Object value = condition.getValue();
        if (value == null) return true;
        if (value instanceof String && StringUtils.isBlank((String) value)) return true;
        if (value instanceof Collection && ((Collection<?>) value).isEmpty()) return true;
        return false;
    }

    /**
     * 替换模板变量
     */
    public static String replaceVariables(String template, Map<String, Object> params) {
        if (StringUtils.isBlank(template) || params == null) {
            return template;
        }

        Matcher matcher = VARIABLE_PATTERN.matcher(template);
        StringBuffer sb = new StringBuffer();
        while (matcher.find()) {
            String varName = matcher.group(1);
            Object value = params.get(varName);
            String replacement = value != null ? value.toString() : "";
            // 防止SQL注入
            if (hasSqlInjection(replacement)) {
                logger.warn("变量值包含SQL注入风险: {} = {}", varName, replacement);
                replacement = "";
            }
            matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(sb);
        return sb.toString();
    }

    /**
     * SQL注入检测
     */
    public static boolean hasSqlInjection(String value) {
        if (StringUtils.isBlank(value)) {
            return false;
        }
        return SQL_INJECTION_PATTERN.matcher(value).find();
    }

    /**
     * 安全转义
     */
    public static String escapeValue(String value) {
        if (value == null) return null;
        return value.replace("'", "''").replace("\\", "\\\\");
    }
}