package org.example.Utils;

import com.github.pagehelper.PageHelper;
import jakarta.annotation.PostConstruct;
import org.example.Enums.*;
import org.example.Impl.BaseImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.stereotype.Component;
import org.example.PageBreaksApi.PageBreaksMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.sql.DataSource;
import java.sql.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


@Component
public class DbOperator {
    private static final Logger log = LoggerFactory.getLogger(DbOperator.class);
    private final Map<String, Boolean> slowQuerys = new ConcurrentHashMap<>();
    private boolean isLocal = true;
    private boolean closeCon = true;
    @Value("${custom.database.type}")
    private String databaseType;
    @Value("${app.sql.read-only-guard.enabled:false}")
    private boolean readOnlyGuardEnabled;
    @Autowired // 字段注入
    private JdbcTemplate jdbcTemplate;
    @Autowired
    PageBreaksMapper pagebreaksmapper;

    @Autowired // 直接注入NamedParameterJdbcTemplate
    private NamedParameterJdbcTemplate namedJdbcTemplate;
    // 构造注入JdbcTemplate

    // 在构造方法中初始化
    public DbOperator() {

    }

    private PreparedStatement preparedStatement;
    private CallableStatement callableStatement;

    // 4. 关键：用@PostConstruct在字段注入完成后初始化currentDataSource
    @PostConstruct
    public void initDataSource() {
        // 此时jdbcTemplate已被注入，可安全调用
        configureJdbcTemplate(this.jdbcTemplate);
        log.info("SqlSafetyGuard rule version: {}, readOnlyGuardEnabled={}",
                SqlSafetyGuard.RULE_VERSION, readOnlyGuardEnabled);

        // 验证数据源是否有效
        if (this.currentDataSource == null) {
            throw new IllegalStateException("初始化失败：JdbcTemplate未关联数据源！请检查spring.datasource配置");
        }
        log.debug(String.valueOf("currentDataSource初始化成功！"));
    }


    // 3. 初始化方法：Spring容器初始化DbOperator时自动执行，设置默认连接字符串
    @PostConstruct // 此注解确保该方法在对象创建后、依赖注入完成时自动调用
    public void initDefaultConnectionString() {
        // 仅当默认连接字符串不为空时设置（避免覆盖账套切换时的字符串）
        if (ConfigUtil.getDefaultConnectionString() != null && !ConfigUtil.getDefaultConnectionString().trim().isEmpty()) {
            this.connectionString = ConfigUtil.getDefaultConnectionString();
            log.debug("Default datasource connection string initialized");
        }
    }


    @Autowired
    public DbOperator(JdbcTemplate jdbcTemplate) {
        configureJdbcTemplate(jdbcTemplate);
    }

    public JdbcTemplate getJdbcTemplate() {
        return jdbcTemplate;
    }

    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        configureJdbcTemplate(jdbcTemplate);
    }

    private void configureJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = Objects.requireNonNull(jdbcTemplate, "JdbcTemplate must not be null");
        this.currentDataSource = Objects.requireNonNull(
                this.jdbcTemplate.getDataSource(),
                "JdbcTemplate must be associated with a DataSource"
        );
        this.namedJdbcTemplate = new NamedParameterJdbcTemplate(this.jdbcTemplate);
    }

    private String connectionString;

    public String getConnectionString() {
        log.debug("DbOperator connection string requested: {}", connectionString != null && !connectionString.isBlank());
        if (connectionString == null) {
            return ConfigUtil.getDefaultConnectionString();
        }
        return connectionString;
    }

    public void setConnectionString(String connectionString) {
        this.connectionString = connectionString;
    }


    // 基于当前ConnectionString的数据源（连接池）
    private DataSource currentDataSource;

    public void setCurrentDataSource(DataSource currentDataSource) {
        this.currentDataSource = currentDataSource;
    }

    /**
     * 对应C#的 ConnectionTest(out Exception ex)
     * 修复：移除conn.open()调用，因为Java的Connection获取时已打开
     */
    public boolean connectionTest(Exception[] outParam) {
        log.debug(String.valueOf("进来了"));
        if (outParam == null || outParam.length == 0) {
            log.debug(String.valueOf("test1"));
            throw new IllegalArgumentException("outParam数组不能为空且长度需≥1");
        }
        boolean isSuccess = false;
        outParam[0] = null;
        Connection conn = null;

        try {
            log.debug(String.valueOf("test2" + currentDataSource));
            if (currentDataSource == null) {
                throw new IllegalStateException("数据源未初始化，请先调用 setDataSourceConfig()");
            }

            // Java中：getConnection()直接返回已打开的连接，无需open()
            conn = currentDataSource.getConnection();

            // 验证连接是否有效（替代C#的Open()逻辑）
            if (conn.isValid(3)) { // 3秒超时验证
                isSuccess = true;
                log.debug("Connection test succeeded");
            } else {
                throw new SQLException("获取的连接无效");
            }

        } catch (Exception e) {
            isSuccess = false;
            outParam[0] = e;
            log.debug("Connection test failed: {}", e.getMessage());

        } finally {
            // 释放连接（归还到连接池）
            if (conn != null) {
                try {
                    conn.close(); // 对应C#的Dispose()
                } catch (SQLException closeEx) {
                    log.debug(String.format("关闭连接时发生异常：%s%n", closeEx.getMessage()));
                }
            }
        }

        return isSuccess;
    }

    /**
     * 对应C#的 ConnectionTest()
     */
    public boolean connectionTest() {
        Exception[] outParam = new Exception[1];
        log.debug(String.valueOf("进入测试"));
        return connectionTest(outParam);
    }

    // 转换参数方向
    private int getParameterDirection(int columnType) {
        switch (columnType) {
            case 2:
                return ParameterMetaData.parameterModeOut;
            case 3:
                return ParameterMetaData.parameterModeInOut;
            case 4:
                return -1; // 表示返回值
            default:
                return ParameterMetaData.parameterModeIn;
        }
    }

    // 创建参数
    public Parameter getParameter(String name, Object value, int type, int length, int direction) {
        Parameter param = new Parameter();
        param.setName(name);
        param.setValue(value);
        param.setType(type);
        param.setLength(length);
        param.setDirection(direction);
        return param;
    }

    public List<Map<String, Object>> executeDMDataSet(String storeName, Parameter[] pmList) {
        // 入参校验
        if (storeName == null || storeName.trim().isEmpty()) {
            throw new IllegalArgumentException("存储过程名称不能为空");
        }
        if (pmList == null || pmList.length == 0) {
            throw new IllegalArgumentException("存储过程参数列表不能为空");
        }

        // 1. 分离OUT参数和IN参数（保留原始顺序）
        List<Parameter> outParams = Arrays.stream(pmList)
                .filter(parameter -> parameter.getDirection() == 2) // 2=OUT方向
                .collect(Collectors.toList());
        // 存储参数名->参数对象的映射，方便快速取值
        Map<String, Parameter> paramMap = new LinkedHashMap<>();
        for (Parameter param : pmList) {
            // 统一参数名格式（小写，去掉@/p_前缀，便于匹配）
            String key = param.getName().toLowerCase().replace("@", "").replace("p_", "");
            paramMap.put(key, param);
        }

        StringBuilder sql = new StringBuilder();
        sql.append("DECLARE ");

        // 遍历OUT参数，声明对应的DM变量
        for (int i = 0; i < outParams.size(); i++) {
            Parameter outParam = outParams.get(i);
            String varName = getVarName(outParam); // 生成变量名（如@p_msg → var_msg）
            String dbType = getDMParamType(outParam); // 获取DM对应的数据库类型

            sql.append(varName).append(" ").append(dbType).append("; ");
        }
        sql.append("BEGIN ");
        sql.append("CALL ").append(storeName).append("(");

        // 按pmList的原始顺序拼接参数
        for (int i = 0; i < pmList.length; i++) {
            Parameter param = pmList[i];
            if (i > 0) {
                sql.append(", "); // 参数分隔符
            }

            // OUT参数：使用声明的变量名
            if (param.getDirection() == 2) {
                sql.append(getVarName(param));
            }
            // IN参数：获取参数值并格式化
            else {
                String paramValue = getParamValue(paramMap, param.getName());
                sql.append(paramValue);
            }
        }
        sql.append("); ");

        // 4. 构建SELECT段（返回OUT参数值）
        if (!outParams.isEmpty()) {
            sql.append("SELECT ");
            for (int i = 0; i < outParams.size(); i++) {
                Parameter outParam = outParams.get(i);
                if (i > 0) {
                    sql.append(", ");
                }
                // 变量名 AS 别名（别名统一为参数名去掉特殊字符）
                String varName = getVarName(outParam);
                String alias = outParam.getName().toLowerCase().replace("@", "").replace("p_", "").replace("return", "returncode");
                sql.append(varName).append(" AS ").append(alias);
            }
            sql.append(" FROM DUAL; ");
        }

        // 5. 结束SQL
        sql.append("END;");

        try (Connection conn = jdbcTemplate.getDataSource().getConnection()) {
            // 获取数据库元数据，打印当前连接的用户名
            DatabaseMetaData metaData = conn.getMetaData();
            String currentUser = metaData.getUserName();
            log.debug(String.valueOf("当前数据库连接用户名：" + currentUser));
            log.debug(String.valueOf("数据库连接成功：" + (conn != null && !conn.isClosed())));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return jdbcTemplate.queryForList(sql.toString());
    }

    /**
     * 生成OUT参数对应的变量名（避免特殊字符）
     *
     * @param param 参数对象
     * @return 标准化变量名（如@p_return_code → var_return_code）
     */
    private String getVarName(Parameter param) {
        String name = param.getName().toLowerCase()
                .replace("@", "")
                .replace("p_", "");
        return "var_" + name;
    }

    /**
     * 根据Parameter类型获取DM数据库对应的类型字符串
     *
     * @param param 参数对象
     * @return DM数据库类型（如VARCHAR(32000)、INT等）
     */
    private String getDMParamType(Parameter param) {
        switch (param.getType()) {
            case java.sql.Types.INTEGER:
                return "INT";
            case java.sql.Types.SMALLINT:
                return "SMALLINT";
            case java.sql.Types.BIGINT:
                return "BIGINT";
            case java.sql.Types.DECIMAL:
            case java.sql.Types.NUMERIC:
                return "DECIMAL(18,6)"; // 默认精度，可根据实际调整
            case java.sql.Types.VARCHAR:
            case java.sql.Types.CHAR:
                // DM的VARCHAR最大长度可设为32000，适配大部分场景
                return "VARCHAR(" + (param.getLength() > 0 ? param.getLength() : 32000) + ")";
            case java.sql.Types.DATE:
                return "DATE";
            case java.sql.Types.TIMESTAMP:
                return "TIMESTAMP";
            case java.sql.Types.BOOLEAN:
                return "BOOLEAN";
            default:
                // 默认使用VARCHAR，适配大部分场景
                return "VARCHAR(32000)";
        }
    }

    /**
     * 获取IN参数的值并格式化（适配DM语法）
     *
     * @param paramMap  参数名->参数对象的映射
     * @param paramName 原始参数名（如@typeCode、p_billDocumentId）
     * @return 格式化后的参数值（字符串加单引号，数字直接返回，null返回NULL）
     */
    private String getParamValue(Map<String, Parameter> paramMap, String paramName) {
        // 统一参数名格式，便于匹配
        String key = paramName.toLowerCase().replace("@", "").replace("p_", "");
        Parameter param = paramMap.get(key);

        if (param == null || param.getValue() == null) {
            return "NULL";
        }

        Object value = param.getValue();
        // 根据参数类型格式化值
        switch (param.getType()) {
            // 数字类型：直接返回值
            case java.sql.Types.INTEGER:
            case java.sql.Types.SMALLINT:
            case java.sql.Types.BIGINT:
            case java.sql.Types.DECIMAL:
            case java.sql.Types.DOUBLE:
            case java.sql.Types.FLOAT:
                return value.toString();

            // 布尔类型：DM中BOOLEAN用TRUE/FALSE，或1/0
            case java.sql.Types.BOOLEAN:
                return ((Boolean) value) ? "TRUE" : "FALSE";

            // 字符串类型：加单引号，转义内部单引号
            case java.sql.Types.VARCHAR:
            case java.sql.Types.CHAR:
                String strValue = value.toString().replace("'", "''");
                return "'" + strValue + "'";

            // 日期类型：按DM格式拼接
            case java.sql.Types.DATE:
            case java.sql.Types.TIMESTAMP:
                return "TO_DATE('" + value.toString() + "', 'YYYY-MM-DD HH24:MI:SS')";

            // 其他类型默认按字符串处理
            default:
                String defaultStr = value.toString().replace("'", "''");
                return "'" + defaultStr + "'";
        }
    }

    // 参数类
    public class Parameter {
        private String name;
        private Object value;
        private int type;
        private int length;
        private int direction; // 1:in, 2:out, 3:inout, -1:return
        private int scale;

        // getter和setter方法
        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }

        public int getType() {
            return type;
        }

        public void setType(int type) {
            this.type = type;
        }

        public int getLength() {
            return length;
        }

        public void setLength(int length) {
            this.length = length;
        }

        public int getDirection() {
            return direction;
        }

        public void setDirection(int direction) {
            this.direction = direction;
        }

        // 新增：scale的getter/setter（用于处理小数位数）
        public int getScale() {
            return scale;
        }

        public void setScale(int scale) {
            this.scale = scale;
        }
    }

    // 执行存储过程并返回数据集
    public ResultSet executeDataSet(String storeName, Parameter[] parameters) throws SQLException {
        Connection connection = null;
        CallableStatement callableStatement = null;
        ResultSet resultSet = null;

        try {
            connection = getConnection();
            // 1. 关闭自动提交（开启手动事务管理）
            connection.setAutoCommit(false);

            // 2. 构建存储过程调用SQL（原逻辑不变）
            StringBuilder callSql = new StringBuilder("{call " + storeName + "(");
            for (int i = 0; i < parameters.length; i++) {
                if (i > 0) callSql.append(",");
                callSql.append("?");
            }
            callSql.append(")}");

            callableStatement = connection.prepareCall(callSql.toString());

            // 3. 设置参数（原逻辑不变）
            for (int i = 0; i < parameters.length; i++) {
                Parameter param = parameters[i];
                int paramIndex = i + 1;

                // 注册输出参数（注意：SQL Server 部分类型需指定精度，如 DECIMAL）
                if (param.getDirection() == ParameterMetaData.parameterModeOut ||
                        param.getDirection() == ParameterMetaData.parameterModeInOut) {
                    // 处理特殊类型：若为 DECIMAL，需补充精度（避免 SQL Server 类型不匹配）
                    if (param.getType() == Types.DECIMAL) {
                        callableStatement.registerOutParameter(paramIndex, param.getType(), param.getScale());
                    } else {
                        callableStatement.registerOutParameter(paramIndex, param.getType(), param.getLength());
                    }
                }

                // 设置输入参数值
                if (param.getDirection() == ParameterMetaData.parameterModeIn
                    //param.getDirection() == ParameterMetaData.parameterModeInOut
                ) {
                    if (param.getValue() != null) {
                        callableStatement.setObject(paramIndex, param.getValue());
                    } else {
                        callableStatement.setNull(paramIndex, param.getType());
                    }
                }
            }

            log.debug(String.valueOf(callSql + " callSql"));
            // 4. 执行存储过程
            boolean hasResultSet = callableStatement.execute();
            // 处理多结果集（SQL Server 存储过程可能返回多个结果集，需遍历获取最后一个）
            while (callableStatement.getMoreResults()) {
                if (resultSet != null) resultSet.close(); // 关闭前一个结果集，避免资源泄漏
                resultSet = callableStatement.getResultSet();
            }
            // 若未获取到结果集，直接取当前结果集
            if (resultSet == null && hasResultSet) {
                resultSet = callableStatement.getResultSet();
            }
            // 5. 若存储过程无异常，手动提交事务（若存储过程内部已提交，可注释此句）
            // 注意：若存储过程内部有 COMMIT/ROLLBACK，需与存储过程逻辑对齐，避免重复提交
            connection.commit();
            return resultSet;

        } catch (SQLException e) {
            // 6. 异常时回滚事务（确保事务闭环）
            if (connection != null && !connection.isClosed()) {
                try {
                    connection.rollback();
                    log.info("执行存储过程失败，已回滚事务: " + storeName + " " + e.getMessage());
                } catch (SQLException rollbackEx) {
                    log.info("事务回滚失败: " + storeName + " " + rollbackEx.getMessage());
                }
            }
            throw new SQLException("执行存储过程失败，已回滚事务: " + storeName + " " + e.getMessage()); // 重新抛出异常，让上层处理

        } finally {
            // 7. 释放资源（按 ResultSet → Statement → Connection 顺序关闭）
            if (resultSet != null) try {
                resultSet.close();
            } catch (SQLException e) {
                log.info("ResultSet关闭失败" + e.getMessage());
            }
            if (callableStatement != null) try {
                callableStatement.close();
            } catch (SQLException e) {
                log.info("CallableStatement关闭失败" + e.getMessage());
            }
            if (connection != null) {
                try {
                    // 恢复自动提交（避免影响后续连接复用，尤其使用连接池时）
                    connection.setAutoCommit(true);
                    connection.close();
                } catch (SQLException e) {
                    log.info("Connection关闭失败" + e.getMessage());
                }
            }
        }
    }

    // 释放资源
    public void dispose() {
        try {
            Connection connection = getConnection();
            if (callableStatement != null) callableStatement.close();
            if (preparedStatement != null) preparedStatement.close();
            if (connection != null) connection.close();
        } catch (SQLException e) {
            log.info("关闭数据库资源失败");
        }
    }

    /**
     * 获取存储过程参数列表
     *
     * @param storeName 存储过程名称（格式：[schema.]procedureName）
     * @return 存储过程参数列表
     */
    public Parameter[] getStoreParams(String storeName) throws SQLException {
        List<Parameter> parameters = new ArrayList<>();
        ResultSet rs = null;
        Connection connection = null;
        PreparedStatement pstmt = null;
        // 达梦数据库标识
        boolean isDM = ConfigUtil.getProviderName().equals("dm");
        // 达梦存储过程所属模式（确认是LSERP_JTCS，若查询不到可改为PUBLIC/数据库名）
        String dmSchema = "LSERP_JTCS";
        // 人大金仓/其他库默认schema为null
        String otherSchema = null;
        try {
            // 1. 获取数据库连接
            connection = jdbcTemplate.getDataSource().getConnection();
            log.debug(String.valueOf("当前解析存储过程：" + storeName + "，数据库类型：" + (isDM ? "达梦" : "其他")));
            // ===================== 核心改造：达梦端直接查系统表（替代元数据） =====================
            if (isDM) {
                /*
                 * 达梦系统表SYS.ALL_ARGUMENTS：存储所有可访问的存储过程/函数参数
                 * 关键字段：
                 * OWNER：存储过程所属模式（schema）
                 * OBJECT_NAME：存储过程名
                 * ARGUMENT_NAME：参数名（NULL表示返回值）
                 * IN_OUT：参数方向（IN/OUT/IN OUT）
                 * DATA_TYPE：参数数据类型
                 * DATA_LENGTH：参数长度（字节）
                 * POSITION：参数位置（从1开始，顺序严格对应存储过程定义）
                 */
                String dmSql = "SELECT " +
                        "ARGUMENT_NAME AS COLUMN_NAME, " +
                        "DATA_TYPE AS DATA_TYPE_NAME, " +
                        "IN_OUT AS PARAM_DIRECTION, " +
                        "DATA_LENGTH AS LEN, " +
                        "POSITION AS PARAM_POSITION, " +
                        "DATA_PRECISION AS PRECISION, " +
                        "DATA_SCALE AS SCALE " +
                        "FROM SYS.ALL_ARGUMENTS " +
                        "WHERE OWNER = ? " +
                        "  AND OBJECT_NAME = ? " +
                        "ORDER BY POSITION"; // 按位置排序，保证和存储过程定义一致

                // 预编译达梦查询SQL
                pstmt = connection.prepareStatement(dmSql);
                pstmt.setString(1, dmSchema); // 模式名
                pstmt.setString(2, storeName.toUpperCase()); // 达梦对象名默认大写，强制转大写避免匹配不到
                rs = pstmt.executeQuery();

                // 遍历达梦系统表结果，解析参数
                while (rs.next()) {
                    String colName = rs.getString("COLUMN_NAME");
                    // 过滤空参数名（部分存储过程的返回值会显示为NULL，可根据实际情况调整）
                    if (colName == null || colName.trim().isEmpty()) {
                        continue;
                    }
                    Parameter param = new Parameter();
                    param.setName(colName); // 参数名：DM_retVal/DM_workno等
                    // 转换达梦数据类型为JDBC Types（核心：和存储过程类型匹配）
                    String dmDataType = rs.getString("DATA_TYPE_NAME").toUpperCase();
                    int jdbcType = convertDmTypeToJdbcType(dmDataType);
                    param.setType(jdbcType);
                    // 转换参数方向（IN/OUT/IN OUT → 1/2/3）
                    String dmDirection = rs.getString("PARAM_DIRECTION").toUpperCase();
                    param.setDirection(convertDmDirectionToCode(dmDirection));
                    // 参数长度（达梦DATA_LENGTH是真实字节长度，直接用）
                    int len = rs.getInt("LEN");
                    param.setLength(len > 0 ? len : 0);
                    // 小数位数：仅DECIMAL/NUMERIC
                    if (jdbcType == Types.DECIMAL || jdbcType == Types.NUMERIC) {
                        param.setScale(rs.getInt("SCALE") > 0 ? rs.getInt("SCALE") : 0);
                    }
                    // 调试输出达梦解析的参数
                    log.debug(String.valueOf("达梦系统表解析参数：" + colName +
                            " | 达梦类型：" + dmDataType +
                            " | JDBC类型：" + jdbcType +
                            " | 方向：" + dmDirection +
                            " | 长度：" + len));
                    parameters.add(param);
                }
            }
            // ===================== 其他库（人大金仓）：保留原有元数据解析逻辑 =====================
            else {
                // 预编译存储过程调用语句，移除冗余占位符
                String callSql = "{call " + storeName + "}";
                callableStatement = connection.prepareCall(callSql);
                // 获取数据库元数据
                DatabaseMetaData metaData = connection.getMetaData();
                // 查询存储过程参数元数据
                rs = metaData.getProcedureColumns(null, otherSchema, storeName, null);
                // 遍历解析参数
                while (rs.next()) {
                    int paramType = rs.getInt("COLUMN_TYPE");
                    // 过滤有效参数：1输入/2输出/3输入输出/4返回值
                    if (paramType == 1 || paramType == 2 || paramType == 3 || paramType == 4) {
                        Parameter param = new Parameter();
                        param.setName(rs.getString("COLUMN_NAME"));
                        param.setType(rs.getInt("DATA_TYPE"));
                        param.setDirection(getParameterDirection(paramType));
                        param.setLength(rs.getInt("PRECISION") > 0 ? rs.getInt("PRECISION") : 0);
                        if (param.getType() == Types.DECIMAL || paramType == Types.NUMERIC) {
                            param.setScale(rs.getInt("SCALE") > 0 ? rs.getInt("SCALE") : 0);
                        }
                        parameters.add(param);
                        log.debug(String.valueOf("元数据解析参数：" + rs.getString("COLUMN_NAME") + " | 类型：" + rs.getInt("DATA_TYPE")));
                    }
                }
            }

        } catch (SQLException e) {
            // 异常时取消执行，释放资源
            if (callableStatement != null) {
                try {
                    callableStatement.cancel();
                } catch (SQLException ex) {
                    log.warn(String.valueOf("取消存储过程预编译失败：" + ex.getMessage()));
                }
            }
            String errMsg = String.format("解析存储过程参数错误: %s，异常信息：%s", storeName, e.getMessage());
            log.warn(String.valueOf(errMsg));
            log.debug(String.valueOf(errMsg)); // 页面输出异常，方便调试
            throw new SQLException(errMsg, e);
        } finally {
            // 【统一关闭所有资源】避免泄漏，按ResultSet→PreparedStatement→CallableStatement→Connection顺序
            try {
                if (rs != null) rs.close();
            } catch (SQLException ex) {
                log.debug(String.valueOf("关闭ResultSet失败：" + ex.getMessage()));
            }
            try {
                if (pstmt != null) pstmt.close();
            } catch (SQLException ex) {
                log.debug(String.valueOf("关闭PreparedStatement失败：" + ex.getMessage()));
            }
            try {
                if (callableStatement != null) callableStatement.close();
            } catch (SQLException ex) {
                log.debug(String.valueOf("关闭CallableStatement失败：" + ex.getMessage()));
            }
            try {
                if (connection != null) connection.close();
            } catch (SQLException ex) {
                log.debug(String.valueOf("关闭Connection失败：" + ex.getMessage()));
            }
        }

        // 调试输出最终解析结果（关键：看参数总数和参数名是否正确）
        Parameter[] paramArray = parameters.toArray(new Parameter[0]);
        log.debug(String.valueOf("===== 解析完成 ====="));
        log.debug(String.valueOf("存储过程：" + storeName));
        log.debug(String.valueOf("参数总数：" + paramArray.length));
        log.debug(String.valueOf("参数列表："));
        for (Parameter p : paramArray) {
            log.debug(String.valueOf("→ " + p.getName() + " | 方向：" + p.getDirection() + " | 类型：" + p.getType() + " | 长度：" + p.getLength()));
        }
        return paramArray;
    }

    private int convertDmTypeToJdbcType(String dmDataType) {
        if (dmDataType == null) return Types.OTHER;
        return switch (dmDataType) {
            case "INT", "INTEGER", "NUMBER" -> Types.INTEGER; // 达梦INT/NUMBER映射JDBC INTEGER
            case "VARCHAR2", "VARCHAR", "CHAR" -> Types.VARCHAR; // 达梦VARCHAR2映射JDBC VARCHAR
            case "DECIMAL", "NUMERIC" -> Types.DECIMAL;
            case "DATE", "TIMESTAMP" -> Types.TIMESTAMP;
            default -> Types.OTHER; // 其他类型默认
        };
    }

    // ===================== 辅助方法2：达梦参数方向 → 自定义Parameter方向码（和你的Parameter类匹配） =====================
// 达梦IN_OUT值：IN/OUT/IN OUT → 对应你的Parameter方向码（1=IN，2=OUT，3=INOUT）
    private int convertDmDirectionToCode(String dmDirection) {
        if (dmDirection == null) return 0;
        return switch (dmDirection) {
            case "IN" -> 1; // 输入参数
            case "OUT" -> 2; // 输出参数
            case "IN OUT" -> 3; // 输入输出参数
            default -> 0; // 未知方向
        };
    }

    /**
     * 查询存储过程的参数定义顺序（按 parameter_id 排序，即定义顺序）
     */
    private List<String> getStoreParamOrder(String procedureName, String schema) {
        List<String> paramOrder = new ArrayList<>();
        String sql = "SELECT p.name AS PARAMETER_NAME " +
                "FROM sys.parameters p " +
                "JOIN sys.procedures pr ON p.object_id = pr.object_id " +
                "WHERE pr.name = ? " +
                (schema != null ? "AND SCHEMA_NAME(pr.schema_id) = ? " : "") +
                "ORDER BY p.parameter_id"; // 按定义顺序排序（关键）
        Object[] params = schema != null ? new Object[]{procedureName, schema} : new Object[]{procedureName};

        jdbcTemplate.query(sql, rs -> {
            while (rs.next()) {
                paramOrder.add(rs.getString("PARAMETER_NAME"));
            }
        }, params);

        // 调试：打印存储过程定义的参数顺序
        log.debug(String.valueOf("存储过程 " + procedureName + " 的参数顺序：" + paramOrder));
        return paramOrder;
    }

    /**
     * 获取当前数据库schema（适配MySQL）
     */
    private String getCurrentSchema() {
        return jdbcTemplate.queryForObject("SELECT DATABASE()", String.class);
    }

    /**
     * 数据库类型转换为JDBC SQL类型
     */
    private int getSqlType(String dataType) {
        switch (dataType.toLowerCase()) {
            case "int":
            case "integer":
                return Types.INTEGER;
            case "varchar":
            case "char":
                return Types.VARCHAR;
            case "datetime":
            case "timestamp":
                return Types.TIMESTAMP;
            case "decimal":
            case "numeric":
                return Types.DECIMAL;
            case "bit":
            case "boolean":
                return Types.BOOLEAN;
            default:
                return Types.OTHER;
        }
    }

    public List<Map<String, Object>> executeDataTable(String cmdText, Integer start, Integer count, int[] tot) {
        return executeDataTable(cmdText, CommandType.TEXT, null, start, count, tot);
    }

    public List<Map<String, Object>> executeDataTable(String cmdText, Object[] params, Integer start, Integer count, int[] tot) {
        return executeDataTable(cmdText, CommandType.TEXT, params, start, count, tot);
    }

    /**
     * 执行查询并返回结果集
     *
     * @param cmdText SQL语句
     * @param cmdType 命令类型
     * @param params  参数数组
     * @param start   起始位置
     * @param count   记录数
     * @return 结果集列表，每个元素为一行数据的Map
     */
    public List<Map<String, Object>> executeDataTable(String cmdText, CommandType cmdType, Object[] params,
                                                      int start, int count, int[] tot) {
        List<Map<String, Object>> resultList = new ArrayList<>();
        long startTime = System.currentTimeMillis();
        String excSql = "";
        String queryKey = String.valueOf(cmdText.hashCode());
        StringBuilder indexCol = new StringBuilder();
        String indexColName = "";
        try {
            // 判断是否为SQLServer且需要分页处理
            if (isSqlHandler() && (!isLocal || slowQuerys.containsKey(queryKey))) {
                SqlAnalyzer sqlAnalyzer = new SqlAnalyzer(cmdText);
                excSql = sqlAnalyzer.buildSplitPageCmdText1(start, count, indexCol);
                indexColName = indexCol.toString();
            }

            if (excSql != null && !excSql.isEmpty()) {
                try {
                    // 执行分页查询（返回两个结果集：总数和数据）
                    List<List<Map<String, Object>>> dataSets = executePagedQuery(excSql, params);

                    if (dataSets.size() > 1) {
                        // 获取数据结果集
                        resultList = dataSets.get(1);
                        // 移除索引列
                        if (!indexColName.isEmpty()) {
                            String finalIndexColName = indexColName;
                            resultList.forEach(row -> row.remove(finalIndexColName));
                        }
                    }
                } catch (Exception e) {
                    String errMsg = String.format("execute sql error:sourceSql:%s%n\t execSql:%s%n\t try executeDataTableByReader", cmdText, excSql);
                    if (cmdText.equals(excSql)) {
                        errMsg = String.format("execute sql error:sourceSql:%s%n\t try executeDataTableByReader", cmdText);
                    }
                    if (log.isErrorEnabled()) {
                        log.error("{}\n{}", errMsg, e.getMessage());
                    }
                    // 失败时使用Reader方式查询
                    resultList = executeDataTableByReader(cmdText, cmdType, params, start, count, tot);
                }
            } else {
                // 非分页查询直接使用Reader方式
                resultList = executeDataTableByReader(cmdText, cmdType, params, start, count, tot);
            }

            // 记录慢查询
            long endTime = System.currentTimeMillis();
            if ((endTime - startTime) / 1000.0 > 50 && !slowQuerys.containsKey(queryKey)) {
                slowQuerys.put(queryKey, true);
            }
            // 记录执行时间超过500ms的查询
            if (endTime - startTime > 500) {
                proLog(endTime - startTime, cmdText, params);
            }

            return resultList;
        } catch (Exception e) {
            String errMsg = String.format("execute sql error:sourceSql:%s%n\t execSql:%s", cmdText, excSql);
            if (cmdText.equals(excSql) || (excSql == null || excSql.isEmpty())) {
                errMsg = String.format("execute sql error:%s,pms:%s,mag:%s", cmdText, pmsToString(params), e.getMessage());
            }
            if (log.isErrorEnabled()) {
                log.error("{}\n{}", errMsg, e.getMessage());
            }
            throw new RuntimeException(errMsg, e);
        }
        // JdbcTemplate自动管理连接，无需手动关闭
    }

    /**
     * 通过Reader方式执行查询并返回结果集
     *
     * @param cmdText SQL语句
     * @param cmdType 命令类型
     * @param params  参数数组
     * @param start   起始位置
     * @param count   记录数
     * @return 结果集列表，每个元素为一行数据的Map
     */
    public List<Map<String, Object>> executeDataTableByReader(
            String cmdText, CommandType cmdType, Object[] params,
            int start, int count, int[] tot) {

        List<Map<String, Object>> resultList = new ArrayList<>();
        final int[] totalCount = {0};
        final int[] currentRow = {0};
        int endCount = start + count;
        boolean readCount = true;
        int startpage = start / count + 1;
        // 尝试获取总记录数
        try {
            SqlAnalyzer sqlAnalyzer = new SqlAnalyzer(cmdText);
            String countSql = sqlAnalyzer.BuildCoutCmdText("count(1) tot", true);
            countSql = RegexUtil.processDmServerSql(countSql);
            if (countSql != null && !countSql.isEmpty()) {
                // 执行count查询获取总记录数
                totalCount[0] = jdbcTemplate.queryForObject(countSql, params, Integer.class);
                tot[0] = totalCount[0];
                readCount = false;
            }
        } catch (Exception e) {
            // 忽略count查询异常，后续通过读取数据计算总数
            log.debug("Count query failed, will calculate total by reading data", e);
        }
        // 执行主查询并处理结果集
        boolean finalReadCount = readCount;
        try {
            if (!databaseType.equals("dm")) {
                jdbcTemplate.query(cmdText, params, new RowCallbackHandler() {
                    @Override
                    public void processRow(ResultSet rs) throws SQLException {
                        currentRow[0]++;
                        // 记录总记录数（当count查询失败时）
                        if (finalReadCount) {
                            totalCount[0] = currentRow[0];
                        }

                        // 判断是否在查询范围内
                        if (count < 0 || (currentRow[0] > start && currentRow[0] <= endCount)) {
                            Map<String, Object> rowMap = new HashMap<>();
                            ResultSetMetaData metaData = rs.getMetaData();
                            int columnCount = metaData.getColumnCount();

                            // 处理列名和数据
                            for (int i = 1; i <= columnCount; i++) {
                                String columnName = metaData.getColumnName(i);
                                // 处理重复列名
                                if (rowMap.containsKey(columnName)) {
                                    columnName = columnName + "_" + i;
                                }
                                rowMap.put(columnName, rs.getObject(i));
                            }
                            resultList.add(rowMap);
                        }
                        // 修复后代码
                        else if (!finalReadCount && currentRow[0] >= endCount) {
                            // 抛出自定义异常终止查询，JdbcTemplate会捕获并终止结果集处理
                            throw new RuntimeException("Reached end of required record range");
                        }
                    }
                });
            } else {
                List<Map<String, Object>> Pagelist = new ArrayList<>();
                if (!readCount) {
                    cmdText = SqlSafetyGuard.sanitizeReadOnlySelectForExecution(cmdText);
                    cmdText = RegexUtil.processDmServerSql(cmdText);
//                if (databaseType.equals("dm")) {
                    cmdText = RegexUtil.processDmServerSql(cmdText);
                    cmdText = cmdText.replace(";", "");
//                }
                    if (count > 0) {
                        PageHelper.startPage(startpage, count);
                    }
//                cmdText = RegexUtil.removeSemicolonInBrackets(cmdText);
                    if (readOnlyGuardEnabled) {
                        cmdText = SqlSafetyGuard.requireSafeReadOnlySelect(cmdText);
                    }
                    Pagelist = pagebreaksmapper.getPageBreaks(cmdText);
                    BlobUtil.convertBlobToByteArray(Pagelist);
                    BlobUtil.convertTextToNvarcharString(Pagelist);
                    return Pagelist;
                } else {
                    cmdText = SqlSafetyGuard.sanitizeReadOnlySelectForExecution(cmdText);
                    cmdText = RegexUtil.processDmServerSql(cmdText);
                    List<Map<String, Object>> finalPagelist = Pagelist;
                    jdbcTemplate.query(cmdText, params, new RowCallbackHandler() {
                        @Override
                        public void processRow(ResultSet rs) throws SQLException {
                            currentRow[0]++;
                            // 记录总记录数（当count查询失败时）
                            if (finalReadCount) {
                                totalCount[0] = currentRow[0];
                            }

                            // 判断是否在查询范围内
                            if (count < 0 || (currentRow[0] > start && currentRow[0] <= endCount)) {
                                Map<String, Object> rowMap = new HashMap<>();
                                ResultSetMetaData metaData = rs.getMetaData();
                                int columnCount = metaData.getColumnCount();

                                // 处理列名和数据
                                for (int i = 1; i <= columnCount; i++) {
                                    String columnName = metaData.getColumnName(i);
                                    // 处理重复列名
                                    if (rowMap.containsKey(columnName)) {
                                        columnName = columnName + "_" + i;
                                    }
                                    rowMap.put(columnName, rs.getObject(i));
                                }
                                finalPagelist.add(rowMap);
                            }
                            // 修复后代码
                            else if (!finalReadCount && currentRow[0] >= endCount) {
                                // 抛出自定义异常终止查询，JdbcTemplate会捕获并终止结果集处理
                                throw new RuntimeException("Reached end of required record range");
                            }
                        }
                    });
                    return finalPagelist;
                }
               // return Pagelist;
            }
        } catch (RuntimeException e) {
            // 仅忽略自定义的终止异常，其他异常正常抛出
            if (!"Reached end of required record range".equals(e.getMessage())) {
                throw e;
            }
            // 异常消息符合预期，说明是正常终止，无需处理
            log.debug("Query terminated normally after reaching required range", e);
        }
        return resultList;
    }


    /**
     * 执行分页查询，返回多结果集
     */
    private List<List<Map<String, Object>>> executePagedQuery(String sql, Object[] params) {
        List<List<Map<String, Object>>> dataSets = new ArrayList<>();

        // 使用RowMapper处理结果集，支持多结果集（需数据库驱动支持）
        jdbcTemplate.query(sql, params, rs -> {
            List<Map<String, Object>> table = new ArrayList<>();
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            while (rs.next()) {
                Map<String, Object> row = new HashMap<>();
                for (int i = 1; i <= columnCount; i++) {
                    row.put(metaData.getColumnName(i), rs.getObject(i));
                }
                table.add(row);
            }
            dataSets.add(table);
        });

        return dataSets;
    }

    // 辅助方法：参数格式化
    private String pmsToString(Object[] params) {
        if (params == null || params.length == 0) {
            return "[]";
        }
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < params.length; i++) {
            sb.append(params[i]);
            if (i < params.length - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    // 辅助方法：日志记录
    private void proLog(long durationMs, String cmdText, Object[] params) {
        log.info("Slow query detected: {} ms", durationMs);
        log.debug("Slow query detail omitted from production logs; sqlLength={}, paramCount={}",
                cmdText == null ? 0 : cmdText.length(),
                params == null ? 0 : params.length);
    }

    // 判断是否为SQLServer处理类型（需根据实际情况实现）
    private boolean isSqlHandler() {
        // 实际应用中根据数据库类型判断
        return true;
    }

    /// <summary>
    /// 创建读取总数的sql
    /// </summary>
    /// <param name="cmdText">The command text.</param>
    /// <param name="aggSql">The aggregate SQL.</param>
    /// <returns>System.String.</returns>
    public String BuildCountSql(String cmdText, String aggSql) {
        return new SqlAnalyzer(cmdText).BuildCoutCmdText(aggSql, false);

    }

    public String BuildCountSql(String cmdText) {
        return BuildCountSql(cmdText, "count(1) tot");
    }

    // 命令类型枚举
    public enum CommandType {
        TEXT, STORED_PROCEDURE, TABLE_DIRECT
    }

    // setter方法
    public void setLocal(boolean local) {
        isLocal = local;
    }

    public void setCloseCon(boolean closeCon) {
        this.closeCon = closeCon;
    }

    /**
     * 验证SQL命令是否合法（语法校验）
     *
     * @param cmdText 需要验证的SQL语句
     * @return 语法合法返回true，否则返回false
     */
    public boolean validateCmd(String cmdText) {
        Connection connection = null;
        Statement statement = null;
        boolean result = false;

        try {
            // 获取数据库连接（由Spring管理事务时使用该方法）
            connection = DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
            statement = connection.createStatement();

            // 开启SQL解析模式（仅检查语法不执行）
            statement.execute("SET PARSEONLY ON");

            try {
                // 执行待验证的SQL（此时仅解析不执行）
                statement.execute(cmdText);
                result = true; // 无异常则语法合法
            } catch (SQLException e) {
                // SQL语法错误会进入此异常
                result = false;
            } finally {
                // 关闭解析模式
                statement.execute("SET PARSEONLY OFF");
            }
        } catch (SQLException e) {
            result = false;
        } finally {
            // 关闭Statement
            if (statement != null) {
                try {
                    statement.close();
                } catch (SQLException e) {
                }
            }

            // 根据配置决定是否关闭连接
            if (closeCon && connection != null) {
                DataSourceUtils.releaseConnection(connection, jdbcTemplate.getDataSource());
            }
            // 不关闭连接的情况由Spring事务管理处理
        }

        return result;
    }

    /**
     * 执行查询并返回单行单列结果
     *
     * @param cmdText    SQL语句
     * @param cmdType    命令类型
     * @param pma        参数数组
     * @param isCloseCon 是否关闭连接
     * @return 查询结果
     */
    public Object executeScalar(String cmdText, CommandType cmdType, CustomSqlParameter[] pma, boolean isCloseCon) {
        if (cmdText == null || cmdText.isEmpty()) {
            return null;
        }

        Connection connection = null;
        try {
            connection = getConnection();
            MapSqlParameterSource paramSource = new MapSqlParameterSource();
            if (pma != null && pma.length > 0) {
                for (CustomSqlParameter param : pma) {
                    paramSource.addValue(param.getName(), param.getValue(), param.getSqlType());
                }
            }

            Object result;
            if (cmdType == CommandType.STORED_PROCEDURE) {
                // 使用NamedParameterJdbcTemplate执行带命名参数的查询
                result = namedJdbcTemplate.queryForObject(cmdText, paramSource, new RowMapper<Object>() {
                    @Override
                    public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
                        return rs.getObject(1); // 获取第一列结果，符合Scalar语义
                    }
                });
            } else {
                // 文本命令仍使用JdbcTemplate处理位置参数
                if (pma == null || pma.length == 0) {
                    result = jdbcTemplate.queryForObject(cmdText, Object.class);
                } else {
                    List<Object> params = new ArrayList<>();
                    for (CustomSqlParameter param : pma) {
                        params.add(param.getValue());
                    }
                    result = jdbcTemplate.queryForObject(cmdText, params.toArray(), Object.class);
                }
            }

            return result;
        } catch (Exception e) {
            // 异常处理保持不变
            String errMsg = String.format("execute sql error:%s,pms:%s,msg:%s", cmdText, pmsToString(pma), e.getMessage());
            if (log.isErrorEnabled()) {
                log.error("{}\n{}", errMsg, e.getMessage());
            }
            throw new RuntimeException(errMsg, e);
        } finally {
            // 连接关闭逻辑保持不变
            if (isCloseCon && closeCon && connection != null) {
                DataSourceUtils.releaseConnection(connection, jdbcTemplate.getDataSource());
            }
        }
    }

    /**
     * 重载方法，默认关闭连接
     */
    public Object executeScalar(String cmdText, CommandType cmdType, CustomSqlParameter[] pma) {
        return executeScalar(cmdText, cmdType, pma, true);
    }

    /**
     * 获取数据库连接
     */
    private Connection getConnection() throws SQLException {
        return DataSourceUtils.getConnection(jdbcTemplate.getDataSource());
    }

    /**
     * 参数格式化工具方法
     */
    private String pmsToString(CustomSqlParameter[] params) {
        if (params == null || params.length == 0) {
            return "[]";
        }
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        for (int i = 0; i < params.length; i++) {
            sb.append(params[i].getName()).append("=").append(params[i].getValue());
            if (i < params.length - 1) {
                sb.append(", ");
            }
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * SQL参数防注入处理（针对字符串类型参数）
     */
    public static String escapeSqlParam(String param) {
        if (param == null) {
            return "null";
        }
        // 转义单引号（防止SQL注入）
        return "'" + param.replace("'", "''") + "'";
    }

    /**
     * 执行多语句SQL，返回多结果集（支持UPDATE后接SELECT等场景）
     *
     * @param querySql 多语句SQL（如"UPDATE ...; SELECT ...;"）
     * @return 多结果集：外层List=多个结果集，内层List=单个结果集的行，Map=行的列名-值
     */
    public List<List<Map<String, Object>>> executeDataSet(String querySql) {
        List<List<Map<String, Object>>> dataSets = new ArrayList<>();

        // 使用 JdbcTemplate 执行原生JDBC，手动处理多结果集
        jdbcTemplate.execute((Connection connection) -> {
            Statement statement = null;
            ResultSet rs = null;
            try {
                // 1. 创建Statement（支持多结果集）
                statement = connection.createStatement();
                // 2. 执行SQL（多语句需配置 allowMultiQueries=true）
                boolean hasResults = statement.execute(querySql);

                // 3. 循环处理所有结果集（包括更新计数和查询结果）
                while (true) {
                    if (hasResults) {
                        // 3.1 处理查询结果集（ResultSet）
                        rs = statement.getResultSet();
                        List<Map<String, Object>> currentDataSet = parseResultSetToMapList(rs);
                        if (!currentDataSet.isEmpty()) {
                            dataSets.add(currentDataSet);
                        }
                    } else {
                        // 3.2 处理更新计数（如UPDATE/INSERT/DELETE的影响行数，可忽略或记录）
                        int updateCount = statement.getUpdateCount();
                        if (updateCount == -1) {
                            // 无更多结果，退出循环
                            break;
                        }
                        // （可选）记录更新行数：System.out.println("影响行数：" + updateCount);
                    }
                    // 3.3 检查是否有下一个结果集
                    hasResults = statement.getMoreResults();
                }
            } catch (SQLException e) {
                String errMsg = String.format("execute sql error:%s\r\n msg:%s", querySql, e.getMessage());
                throw new SQLException(errMsg, e);
            } finally {
                // 4. 关闭资源（ResultSet → Statement，Connection由JdbcTemplate管理）
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        log.error("Exception caught", e);
                    }
                }
                if (statement != null) {
                    try {
                        statement.close();
                    } catch (SQLException e) {
                        log.error("Exception caught", e);
                    }
                }
            }
            return null;
        });

        return dataSets;
    }

    /**
     * 将单个ResultSet转换为 List<Map<String, Object>>（行列表）
     *
     * @param rs 单个查询结果集
     * @return 行列表：每个Map对应一行，key=列名，value=列值
     */
    public List<Map<String, Object>> parseResultSetToMapList(ResultSet rs) throws SQLException {
        List<Map<String, Object>> rowList = new ArrayList<>();
        if (rs == null) {
            return rowList;
        }

        // 获取结果集元数据（列信息）
        ResultSetMetaData metaData = rs.getMetaData();
        int columnCount = metaData.getColumnCount();

        // 遍历每一行数据
        while (rs.next()) {
            Map<String, Object> rowMap = new HashMap<>();
            for (int i = 1; i <= columnCount; i++) { // ResultSet列索引从1开始
                String columnName = metaData.getColumnName(i);
                Object columnValue = rs.getObject(i);

                // 处理重复列名（若有）：在重复列名后加索引
                if (rowMap.containsKey(columnName)) {
                    columnName = columnName + "_" + i;
                }
                rowMap.put(columnName, columnValue);
            }
            rowList.add(rowMap);
        }
        return rowList;
    }


}

