package org.hzhub.erp.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import lombok.RequiredArgsConstructor;
import org.hzhub.erp.common.domain.R;
import org.hzhub.erp.common.page.TableDataInfo;
import org.hzhub.erp.domain.entity.ErpApiConfig;
import org.hzhub.erp.domain.vo.ApiExecutionResult;
import org.hzhub.erp.util.SqlValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 动态API执行引擎
 * 使用SQL Server数据源执行动态SQL查询（只读）
 *
 * @author HZHub Team
 */
@Service
@DS("erp")  // 使用SQL Server数据源（erp）执行动态SQL
@RequiredArgsConstructor
public class DynamicApiExecutor {

    private static final Logger log = LoggerFactory.getLogger(DynamicApiExecutor.class);

    private final JdbcTemplate jdbcTemplate;

    /**
     * 执行动态API
     *
     * @param config API配置
     * @param params 参数Map
     * @return 执行结果（包含数据和实际执行的SQL）
     */
    public ApiExecutionResult execute(ErpApiConfig config, Map<String, Object> params) {
        String sqlTemplate = config.getSqlTemplate();

        // 1. SQL安全验证
        if (!SqlValidator.validate(sqlTemplate)) {
            throw new SecurityException("SQL验证失败，可能存在安全风险");
        }

        // 2. 处理SQL模板（参数占位符转换）
        ProcessedSql processedSql = processSqlTemplate(sqlTemplate, params);
        String processedSqlStr = processedSql.getSql();
        List<Object> paramValues = processedSql.getParamValues();

        log.info("执行SQL: {}", processedSqlStr);
        log.info("参数值: {}", paramValues);

        // 3. 根据结果类型执行
        try {
            Object result;
            String finalExecutedSql;

            switch (config.getResultType()) {
                case "LIST":
                    if (config.getSupportPagination() == 1) {
                        result = executePaginatedQuery(config, processedSqlStr, paramValues);
                        // 分页SQL需要重新构建完整SQL
                        finalExecutedSql = buildFinalSqlWithParams(processedSqlStr, paramValues);
                    } else {
                        result = executeListQuery(processedSqlStr, paramValues);
                        finalExecutedSql = buildFinalSqlWithParams(processedSqlStr, paramValues);
                    }
                    break;
                case "SINGLE":
                    result = executeSingleQuery(processedSqlStr, paramValues);
                    finalExecutedSql = buildFinalSqlWithParams(processedSqlStr, paramValues);
                    break;
                case "COUNT":
                    result = executeCountQuery(processedSqlStr, paramValues);
                    finalExecutedSql = buildFinalSqlWithParams(processedSqlStr, paramValues);
                    break;
                default:
                    throw new IllegalArgumentException("不支持的结果类型: " + config.getResultType());
            }

            return ApiExecutionResult.success(result, finalExecutedSql);

        } catch (Exception e) {
            log.error("SQL执行失败: {}", e.getMessage(), e);
            throw new RuntimeException("SQL执行失败: " + e.getMessage(), e);
        }
    }

    /**
     * 构建包含参数值的最终SQL（用于日志和统计）
     * 注意：这只是展示用，实际执行使用PreparedStatement
     */
    private String buildFinalSqlWithParams(String sql, List<Object> paramValues) {
        StringBuilder finalSql = new StringBuilder(sql);
        int paramIndex = 0;

        // 替换 ? 为实际参数值（仅用于展示）
        for (int i = 0; i < finalSql.length() && paramIndex < paramValues.size(); i++) {
            if (finalSql.charAt(i) == '?') {
                Object value = paramValues.get(paramIndex++);
                String valueStr;

                if (value == null) {
                    valueStr = "NULL";
                } else if (value instanceof String) {
                    valueStr = "'" + value + "'";
                } else if (value instanceof Boolean) {
                    valueStr = ((Boolean) value) ? "1" : "0";
                } else {
                    valueStr = String.valueOf(value);
                }

                finalSql.replace(i, i + 1, valueStr);
                i += valueStr.length() - 1;
            }
        }

        return finalSql.toString();
    }

    /**
     * 处理SQL模板（将 #{param} 转换为 ? 占位符，并提取参数值）
     *
     * @param sqlTemplate SQL模板
     * @param params 参数Map
     * @return 处理后的SQL和参数值列表
     */
    private ProcessedSql processSqlTemplate(String sqlTemplate, Map<String, Object> params) {
        // 正则表达式匹配 #{paramName}
        Pattern pattern = Pattern.compile("#\\{(\\w+)\\}");
        Matcher matcher = pattern.matcher(sqlTemplate);

        List<Object> paramValues = new ArrayList<>();
        StringBuffer processedSql = new StringBuffer();

        while (matcher.find()) {
            String paramName = matcher.group(1);
            Object paramValue = params.get(paramName);

            // 替换 #{param} 为 ?
            matcher.appendReplacement(processedSql, "?");

            // 记录参数值
            paramValues.add(paramValue != null ? paramValue : null);
        }

        matcher.appendTail(processedSql);

        // 处理 WHERE 条件中的 IS NOT NULL THEN ... 逻辑
        String finalSql = processWhereConditions(processedSql.toString(), params);

        return new ProcessedSql(finalSql, paramValues);
    }

    /**
     * 处理 WHERE 条件中的动态逻辑（IS NOT NULL THEN ...）
     * 例如：WHERE #{customerCode} IS NOT NULL THEN customer_code = #{customerCode}
     * 如果 customerCode 为 null，则移除该条件
     *
     * @param sql SQL语句
     * @param params 参数Map
     * @return 处理后的SQL
     */
    private String processWhereConditions(String sql, Map<String, Object> params) {
        // 处理 #{param} IS NOT NULL THEN ... 的条件
        // 这种条件格式用于动态WHERE条件，只有当参数不为null时才生效
        Pattern pattern = Pattern.compile("AND\\s+#\\{(\\w+)\\}\\s+IS\\s+NOT\\s+NULL\\s+THEN\\s+(.+?)(?=\\s+AND|#|$)");
        Matcher matcher = pattern.matcher(sql);

        StringBuffer result = new StringBuffer();
        while (matcher.find()) {
            String paramName = matcher.group(1);
            String condition = matcher.group(2);

            Object paramValue = params.get(paramName);
            if (paramValue != null) {
                // 参数不为null，保留条件（替换 #{param} 为 ?）
                String processedCondition = condition.replaceAll("#\\{" + paramName + "\\}", "?");
                matcher.appendReplacement(result, "AND " + processedCondition);
            } else {
                // 参数为null，移除整个条件
                matcher.appendReplacement(result, "");
            }
        }
        matcher.appendTail(result);

        return result.toString();
    }

    /**
     * 执行分页查询（SQL Server语法：OFFSET FETCH）
     *
     * @param config API配置
     * @param sql SQL语句
     * @param paramValues 参数值列表
     * @return 分页结果
     */
    /**
     * 执行分页查询（SQL Server 2008 R2兼容版本，使用ROW_NUMBER）
     *
     * @param config API配置
     * @param sql SQL语句
     * @param paramValues 参数值列表
     * @return 分页结果
     */
    private TableDataInfo<Map<String, Object>> executePaginatedQuery(ErpApiConfig config, String sql, List<Object> paramValues) {
        // 从配置中获取分页参数名
        String pageParamName = config.getPageParamName() != null ? config.getPageParamName() : "pageNum";
        String sizeParamName = config.getSizeParamName() != null ? config.getSizeParamName() : "pageSize";

        // 注意：paramValues是从SQL模板中的#{param}提取的，不包含分页参数
        // 分页参数需要通过其他方式传递，这里使用默认值
        // TODO: 改进参数传递，支持动态分页参数
        int pageNum = 1;
        int pageSize = 10;

        // 查询总数
        String countSql = "SELECT COUNT(*) AS total FROM (" + sql + ") AS count_query";
        Long total = jdbcTemplate.queryForObject(countSql, paramValues.toArray(), Long.class);

        // SQL Server 2008 R2兼容分页（使用ROW_NUMBER）
        // 注意：原始SQL不能有ORDER BY（ROW_NUMBER需要自己指定排序）
        int offset = (pageNum - 1) * pageSize;
        String paginatedSql = "SELECT * FROM (" +
            "  SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) AS rn, * FROM (" +
            sql +
            ") AS inner_query" +
            ") AS numbered_query WHERE rn > " + offset + " AND rn <= " + (offset + pageSize);

        // 查询数据
        List<Map<String, Object>> rows = jdbcTemplate.query(paginatedSql, paramValues.toArray(), new DynamicRowMapper());

        // 移除ROW_NUMBER列（rn字段）
        rows.forEach(row -> row.remove("rn"));

        return new TableDataInfo<>(rows, total);
    }

    /**
     * 执行列表查询
     *
     * @param sql SQL语句
     * @param paramValues 参数值列表
     * @return 列表结果
     */
    private R<List<Map<String, Object>>> executeListQuery(String sql, List<Object> paramValues) {
        List<Map<String, Object>> rows = jdbcTemplate.query(sql, paramValues.toArray(), new DynamicRowMapper());
        return R.ok(rows);
    }

    /**
     * 执行单条查询
     *
     * @param sql SQL语句
     * @param paramValues 参数值列表
     * @return 单条结果
     */
    private R<Map<String, Object>> executeSingleQuery(String sql, List<Object> paramValues) {
        List<Map<String, Object>> rows = jdbcTemplate.query(sql, paramValues.toArray(), new DynamicRowMapper());
        if (rows.isEmpty()) {
            return R.fail("未找到数据");
        }
        return R.ok(rows.get(0));
    }

    /**
     * 执行计数查询
     *
     * @param sql SQL语句
     * @param paramValues 参数值列表
     * @return 计数结果
     */
    private R<Long> executeCountQuery(String sql, List<Object> paramValues) {
        Long count = jdbcTemplate.queryForObject(sql, paramValues.toArray(), Long.class);
        return R.ok(count);
    }

    /**
     * 动态RowMapper（将SQL结果映射为Map）
     */
    private static class DynamicRowMapper implements RowMapper<Map<String, Object>> {

        @Override
        public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            Map<String, Object> row = new LinkedHashMap<>();
            for (int i = 1; i <= columnCount; i++) {
                String columnName = metaData.getColumnLabel(i);
                Object value = rs.getObject(i);
                row.put(columnName, value);
            }
            return row;
        }
    }

    /**
     * 处理后的SQL和参数值
     */
    private static class ProcessedSql {
        private final String sql;
        private final List<Object> paramValues;

        public ProcessedSql(String sql, List<Object> paramValues) {
            this.sql = sql;
            this.paramValues = paramValues;
        }

        public String getSql() {
            return sql;
        }

        public List<Object> getParamValues() {
            return paramValues;
        }
    }
}