package nccloud.api.uapbd;


import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class QuerySyncSqlUtils {

    /**
     * 构建SQL IN子句。
     * 例如：fieldName IN ('value1', 123, NULL)
     * 此方法假定传入的 `values` 列表是非空的（由调用方 `buildUniversalCondition` 保证）。
     *
     * @param fieldName 字段名
     * @param values   值的列表 (来自非空数组或List)
     * @return 构建好的IN子句字符串
     */
    private static String buildInClause(String fieldName, List<?> values) {
        String inValues = values.stream()
                .map(val -> {
                    if (val == null) {
                        return "NULL"; // SQL中的NULL字面量
                    }
                    if (val instanceof String) {
                        return "'" + escapeSql((String) val) + "'";
                    }
                    if (val instanceof Number || val instanceof Boolean) {
                        return val.toString(); // 数字和布尔值不需要单引号
                    }
                    // 对于其他类型（例如日期、自定义对象等），默认按其toString()处理，进行转义和加单引号
                    return "'" + escapeSql(val.toString()) + "'";
                })
                .collect(Collectors.joining(", ")); // 注意用逗号和空格分隔，更美观
        return fieldName + " IN (" + inValues + ")";
    }

    /**
     * 通用构建SQL条件
     * 根据参数Map动态生成SQL WHERE子句的条件部分。
     * - 对于简单值（非null、非空字符串），使用相等匹配 (field = value)。
     * - 对于非空数组或List类型的值，使用IN匹配 (field IN (value1, value2, ...))。
     * - 如果参数值为null、空字符串、空List或空数组，则不处理该字段。
     * - 最终生成的条件会被圆括号包裹。
     * - 如果没有有效的条件生成（例如map为空或所有值都无效），则返回 "(1=1)" 以确保SQL语法正确。
     *
     * @param paramMap 参数Map，键为字段名，值为字段值。
     * @return 构建好的SQL条件字符串，例如 "(field1 = 'value1' AND field2 IN ('a', 'b'))" 或 "(1=1)"。
     */
    public static String buildUniversalCondition(Map<String, Object> paramMap) {
        if (paramMap == null || paramMap.isEmpty()) {
            return "(1=1)"; // 如果参数map本身为null或空，直接返回(1=1)
        }

        List<String> conditions = new ArrayList<>();

        for (Map.Entry<String, Object> entry : paramMap.entrySet()) {
            String fieldName = entry.getKey();
            Object value = entry.getValue();

            // 1. 如果值本身为 null，则不处理此条目
            if (value == null) {
                continue;
            }

            // 2. 根据值的类型进行处理
            if (value instanceof String) {
                String stringValue = (String) value;
                if (stringValue.trim().isEmpty()) { // 如果是空字符串（或仅含空格）
                    continue; // 不处理
                }
                conditions.add(fieldName + " = " + formatSqlValue(stringValue));
            } else if (value instanceof List) {
                List<?> listValue = (List<?>) value;
                if (listValue.isEmpty()) { // 如果列表为空
                    continue; // 不处理
                }
                conditions.add(buildInClause(fieldName, listValue));
            } else if (value.getClass().isArray()) {
                int length = Array.getLength(value);
                if (length == 0) { // 如果数组为空
                    continue; // 不处理
                }
                List<Object> arrayAsList = new ArrayList<>(length);
                for (int i = 0; i < length; i++) {
                    arrayAsList.add(Array.get(value, i));
                }
                conditions.add(buildInClause(fieldName, arrayAsList)); // 数组元素已转为List处理
            } else {
                // 其他非null、非空字符串、非空集合/数组的类型（例如数字、布尔值、日期等）
                // formatSqlValue 会处理它们的格式化
                conditions.add(fieldName + " = " + formatSqlValue(value));
            }
        }

        if (conditions.isEmpty()) {
            return "(1=1)"; // 如果没有收集到任何有效条件，返回(1=1)
        }

        return "(" + String.join(" AND ", conditions) + ")"; // 用AND连接并用括号包裹
    }

    private static String escapeSql(String value) {
        return value == null ? null : value.replace("'", "''");
    }

    /**
     * 格式化SQL查询中的单个值，用于相等条件。
     * 此方法假定传入的 `value` 非null且（如果是字符串）非空
     *
     * @param value 要格式化的值 (不为null)
     * @return 格式化后的SQL值字符串
     */
    private static String formatSqlValue(Object value) {
        // value 在这里保证不为null
        if (value instanceof String) {
            // 空字符串的检查已在 buildUniversalCondition 中完成
            return "'" + escapeSql((String) value) + "'";
        } else if (value instanceof Number || value instanceof Boolean) {
            return value.toString(); // 数字和布尔值直接使用其字符串表示，不加单引号
        }
        return "'" + escapeSql(value.toString()) + "'";
    }

}
