package shop.alien.util.myBaticsPlus;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.Data;
import lombok.experimental.Accessors;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 通用查询构建器
 * <p>
 * 功能：根据对象非空字段自动构建查询条件，支持分页、模糊、批量等多种查询方式
 * <p>
 * 使用示例：
 * <pre>{@code
 * // 1. 简单查询
 * QueryBuilder.of(query).build().list(service);
 * 
 * // 2. 分页查询
 * QueryBuilder.of(query).page(1, 10).build().page(service);
 * 
 * // 3. 批量查询（字段名以_List结尾，如：id_List）
 * QueryBuilder.of(query).build().list(service);
 * 
 * // 4. 范围查询（字段名以_Start/_End结尾，如：createdTime_Start, createdTime_End）
 * QueryBuilder.of(query).build().list(service);
 * 
 * // 5. 模糊查询（字段名以_Like结尾，如：name_Like）
 * QueryBuilder.of(query).build().list(service);
 * }</pre>
 *
 * @author system
 * @since 2025-01-XX
 */
public class QueryBuilder<T> {

    // ==================== 常量定义 ====================
    
    /** 特殊查询字段后缀（统一使用下划线前缀，避免与普通字段冲突） */
    private static final String SUFFIX_LIST = "_List";
    private static final String SUFFIX_START = "_Start";
    private static final String SUFFIX_END = "_End";
    private static final String SUFFIX_LIKE = "_Like";
    
    /** 模糊查询通配符 */
    private static final String LIKE_WILDCARD = "%";
    
    /** 模糊查询模式枚举 */
    public enum LikeMode {
        /** 前后模糊：%value% */
        BOTH,
        /** 前模糊：%value */
        LEFT,
        /** 后模糊：value% */
        RIGHT
    }

    // ==================== 成员变量 ====================
    
    private final T queryEntity;
    private final QueryWrapper<T> wrapper;
    private boolean ignoreEmptyStr = true;
    private boolean stringFieldLike = false;  // String类型字段是否默认使用模糊查询
    private final List<String> likeFields = new ArrayList<>();  // 指定哪些字段使用模糊查询
    private LikeMode likeMode = LikeMode.BOTH;  // 模糊查询模式（默认前后模糊）
    private Page<T> page;

    // ==================== 构造函数 ====================
    
    private QueryBuilder(T queryEntity) {
        this.queryEntity = queryEntity;
        this.wrapper = new QueryWrapper<>();
    }

    // ==================== 公开API ====================
    
    /**
     * 创建查询构建器
     */
    public static <T> QueryBuilder<T> of(T queryEntity) {
        return new QueryBuilder<>(queryEntity);
    }

    /**
     * 设置是否忽略空字符串（默认true）
     */
    public QueryBuilder<T> ignoreEmptyStr(boolean ignore) {
        this.ignoreEmptyStr = ignore;
        return this;
    }

    /**
     * 设置String类型字段是否默认使用模糊查询（默认false，即等值查询）
     */
    public QueryBuilder<T> stringFieldLike(boolean like) {
        this.stringFieldLike = like;
        return this;
    }

    /**
     * 指定哪些字段使用模糊查询（可指定多个字段）
     * 例如：.likeFields("name", "code") 表示 name 和 code 字段使用模糊查询
     */
    public QueryBuilder<T> likeFields(String... fieldNames) {
        if (fieldNames != null) {
            for (String fieldName : fieldNames) {
                if (fieldName != null && !fieldName.trim().isEmpty()) {
                    likeFields.add(fieldName.trim());
                }
            }
        }
        return this;
    }

    /**
     * 设置模糊查询模式（默认前后模糊：%value%）
     * 
     * @param mode 模糊查询模式
     *   - BOTH: 前后模糊 %value%（默认）
     *   - LEFT: 前模糊 %value
     *   - RIGHT: 后模糊 value%
     * 
     * 使用示例：
     * <pre>{@code
     * QueryBuilder.of(query)
     *     .likeFields("name")
     *     .likeMode(LikeMode.LEFT)  // 前模糊查询
     *     .build()
     * }</pre>
     */
    public QueryBuilder<T> likeMode(LikeMode mode) {
        if (mode != null) {
            this.likeMode = mode;
        }
        return this;
    }

    /**
     * 设置分页参数
     */
    public QueryBuilder<T> page(int pageNum, int pageSize) {
        this.page = new Page<>(pageNum, pageSize);
        return this;
    }

    /**
     * 设置分页对象
     */
    public QueryBuilder<T> page(Page<T> page) {
        this.page = page;
        return this;
    }

    /**
     * 构建查询条件
     */
    public QueryResult<T> build() {
        buildBaseQueryConditions();
        processSpecialQueries();
        return new QueryResult<>(this.wrapper, this.page);
    }

    // ==================== 核心构建逻辑 ====================
    
    /**
     * 构建基础查询条件（等值查询）
     */
    private void buildBaseQueryConditions() {
        if (queryEntity == null) {
            return;
        }

        List<Field> allFields = getAllFields(queryEntity.getClass());

        for (Field field : allFields) {
            if (shouldSkipField(field)) {
                continue;
            }

            Object value = getFieldValue(field);
            if (value == null || shouldSkipValue(value)) {
                continue;
            }

            String columnName = getColumnName(field);
            if (columnName == null) {
                continue;
            }

            Object serializableValue = ensureSerializable(value);
            if (serializableValue != null) {
                String fieldName = field.getName();
                
                // 判断是否使用模糊查询
                boolean shouldUseLike = false;
                
                // 1. 检查是否在指定的模糊查询字段列表中
                if (likeFields.contains(fieldName)) {
                    shouldUseLike = true;
                }
                // 2. 检查是否全局启用String字段模糊查询
                else if (stringFieldLike && value instanceof String) {
                    shouldUseLike = true;
                }
                
                if (shouldUseLike && value instanceof String) {
                    String likeValue = buildLikeValue(serializableValue.toString());
                    wrapper.like(columnName, likeValue);
                } else {
                    wrapper.eq(columnName, serializableValue);
                }
            }
        }
    }

    /**
     * 处理特殊查询场景（批量、范围、模糊查询）
     */
    private void processSpecialQueries() {
        if (queryEntity == null) {
            return;
        }

        List<Field> allFields = getAllFields(queryEntity.getClass());

        for (Field field : allFields) {
            if (isStaticField(field)) {
                continue;
            }

            Object value = getFieldValue(field);
            if (value == null) {
                continue;
            }

            String fieldName = field.getName();

            // 批量查询：集合类型字段
            if (value instanceof Collection) {
                processBatchQuery(fieldName, (Collection<?>) value);
                continue;
            }

            // 范围查询：Start/End 后缀
            if (isRangeQueryField(fieldName)) {
                processRangeQuery(fieldName, value);
                continue;
            }

            // 模糊查询：Like 后缀
            if (isLikeQueryField(fieldName)) {
                processLikeQuery(fieldName, value);
            }
        }
    }

    // ==================== 字段过滤判断 ====================
    
    /**
     * 判断是否应该跳过该字段
     */
    private boolean shouldSkipField(Field field) {
        String fieldName = field.getName();
        
        // 跳过特殊查询字段
        if (isSpecialQueryField(fieldName)) {
            return true;
        }
        
        // 跳过 transient 字段
        return Modifier.isTransient(field.getModifiers());
    }

    /**
     * 判断是否为特殊查询字段（_List/_Start/_End/_Like后缀）
     */
    private boolean isSpecialQueryField(String fieldName) {
        return fieldName.endsWith(SUFFIX_LIST) ||
               fieldName.endsWith(SUFFIX_START) ||
               fieldName.endsWith(SUFFIX_END) ||
               fieldName.endsWith(SUFFIX_LIKE);
    }

    /**
     * 判断是否为范围查询字段
     */
    private boolean isRangeQueryField(String fieldName) {
        return fieldName.endsWith(SUFFIX_START) || fieldName.endsWith(SUFFIX_END);
    }

    /**
     * 判断是否为模糊查询字段
     */
    private boolean isLikeQueryField(String fieldName) {
        return fieldName.endsWith(SUFFIX_LIKE);
    }

    /**
     * 判断是否为静态字段
     */
    private boolean isStaticField(Field field) {
        return Modifier.isStatic(field.getModifiers());
    }

    /**
     * 判断是否应该跳过该值
     */
    private boolean shouldSkipValue(Object value) {
        // 空字符串
        if (ignoreEmptyStr && value instanceof String && ((String) value).trim().isEmpty()) {
            return true;
        }
        
        // 空集合
        return value instanceof Collection && ((Collection<?>) value).isEmpty();
    }

    // ==================== 查询类型处理 ====================
    
    /**
     * 处理批量查询（IN查询）
     */
    private void processBatchQuery(String fieldName, Collection<?> collection) {
        String baseFieldName = removeSuffix(fieldName, SUFFIX_LIST);
        String columnName = getColumnNameByFieldName(baseFieldName, fieldName);
        
        if (columnName != null) {
            List<Object> serializableList = filterSerializableItems(collection);
            if (!serializableList.isEmpty()) {
                wrapper.in(columnName, serializableList);
            }
        }
    }

    /**
     * 处理范围查询
     */
    private void processRangeQuery(String fieldName, Object value) {
        String baseFieldName = removeSuffix(fieldName, SUFFIX_START, SUFFIX_END);
        String columnName = getColumnNameByFieldName(baseFieldName);
        
        if (columnName != null) {
            Object serializableValue = ensureSerializable(value);
            if (serializableValue != null) {
                if (fieldName.endsWith(SUFFIX_START)) {
                    wrapper.ge(columnName, serializableValue);
                } else {
                    wrapper.le(columnName, serializableValue);
                }
            }
        }
    }

    /**
     * 处理模糊查询
     */
    private void processLikeQuery(String fieldName, Object value) {
        String baseFieldName = removeSuffix(fieldName, SUFFIX_LIKE);
        String columnName = getColumnNameByFieldName(baseFieldName);
        
        if (columnName != null && value != null) {
            String likeValue = buildLikeValue(value);
            if (likeValue != null) {
                wrapper.like(columnName, likeValue);
            }
        }
    }

    // ==================== 工具方法 ====================
    
    /**
     * 获取字段值
     */
    private Object getFieldValue(Field field) {
        try {
            field.setAccessible(true);
            return field.get(queryEntity);
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    /**
     * 获取数据库字段名（通过字段对象）
     */
    private String getColumnName(Field field) {
        TableField tableField = field.getAnnotation(TableField.class);
        
        // 检查字段是否标记为不存在
        if (tableField != null && !tableField.exist()) {
            return null;
        }
        
        // 优先使用注解指定的字段名
        if (tableField != null && !tableField.value().isEmpty()) {
            return tableField.value();
        }
        
        // 默认：驼峰转下划线
        return camelToUnderscore(field.getName());
    }

    /**
     * 获取数据库字段名（通过字段名，支持fallback）
     */
    private String getColumnNameByFieldName(String... fieldNames) {
        for (String fieldName : fieldNames) {
            try {
                Field field = findField(queryEntity.getClass(), fieldName);
                String columnName = getColumnName(field);
                if (columnName != null) {
                    return columnName;
                }
            } catch (Exception e) {
                // 继续尝试下一个字段名
            }
        }
        return null;
    }

    /**
     * 移除字段名后缀（精确实现：只移除末尾的后缀）
     * 
     * 示例：
     * - removeSuffix("id_List", "_List") → "id"
     * - removeSuffix("createdTime_Start", "_Start") → "createdTime"
     * - removeSuffix("name_Like", "_Like") → "name"
     * - removeSuffix("id_List_List", "_List") → "id_List"（只移除末尾的）
     * 
     * @param fieldName 字段名
     * @param suffixes 要移除的后缀（按顺序尝试，找到第一个匹配的就移除）
     * @return 移除后缀后的字段名
     */
    private String removeSuffix(String fieldName, String... suffixes) {
        if (fieldName == null || fieldName.isEmpty()) {
            return fieldName;
        }
        
        // 按顺序尝试每个后缀，找到第一个匹配的就移除
        for (String suffix : suffixes) {
            if (suffix != null && !suffix.isEmpty() && fieldName.endsWith(suffix)) {
                // 只移除末尾的后缀，使用 substring 精确移除
                return fieldName.substring(0, fieldName.length() - suffix.length());
            }
        }
        
        // 如果没有匹配的后缀，返回原字段名
        return fieldName;
    }

    /**
     * 构建模糊查询值（根据likeMode模式）
     * 
     * 模式说明：
     * - BOTH: %value%  （前后模糊，默认）
     * - LEFT: %value   （前模糊）
     * - RIGHT: value%  （后模糊）
     */
    private String buildLikeValue(Object value) {
        if (value == null) {
            return null;
        }
        
        String strValue = value instanceof String ? (String) value : value.toString();
        
        switch (likeMode) {
            case LEFT:
                return LIKE_WILDCARD + strValue;  // %value
            case RIGHT:
                return strValue + LIKE_WILDCARD;  // value%
            case BOTH:
            default:
                return LIKE_WILDCARD + strValue + LIKE_WILDCARD;  // %value%
        }
    }

    /**
     * 过滤集合中的可序列化元素
     */
    private List<Object> filterSerializableItems(Collection<?> collection) {
        List<Object> result = new ArrayList<>();
        for (Object item : collection) {
            if (item != null && isSerializableType(item)) {
                result.add(item);
            }
        }
        return result;
    }

    /**
     * 确保对象是可序列化的类型
     */
    private Object ensureSerializable(Object value) {
        if (value == null) {
            return null;
        }
        
        if (isSerializableType(value)) {
            return value;
        }
        
        // 尝试转换为字符串
        try {
            return value.toString();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 判断对象是否为可序列化的基本类型
     */
    private boolean isSerializableType(Object obj) {
        if (obj == null) {
            return false;
        }
        
        Class<?> clazz = obj.getClass();
        
        return clazz.isPrimitive() ||
               Number.class.isAssignableFrom(clazz) ||
               String.class.equals(clazz) ||
               Boolean.class.equals(clazz) ||
               Character.class.equals(clazz) ||
               java.util.Date.class.isAssignableFrom(clazz) ||
               java.sql.Date.class.isAssignableFrom(clazz) ||
               java.sql.Timestamp.class.isAssignableFrom(clazz) ||
               java.time.LocalDate.class.isAssignableFrom(clazz) ||
               java.time.LocalDateTime.class.isAssignableFrom(clazz);
    }

    /**
     * 驼峰命名转下划线命名
     */
    private String camelToUnderscore(String camelCase) {
        if (camelCase == null || camelCase.isEmpty()) {
            return camelCase;
        }
        
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < camelCase.length(); i++) {
            char c = camelCase.charAt(i);
            if (Character.isUpperCase(c) && i > 0) {
                result.append('_');
            }
            result.append(Character.toLowerCase(c));
        }
        return result.toString();
    }

    /**
     * 查找字段（支持父类）
     */
    private Field findField(Class<?> clazz, String fieldName) {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null && superClass != Object.class) {
                return findField(superClass, fieldName);
            }
            throw new RuntimeException("字段不存在: " + fieldName + " in " + clazz.getName(), e);
        }
    }

    /**
     * 获取实体类所有字段（包括父类，排除静态字段）
     */
    private List<Field> getAllFields(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null && clazz != Object.class) {
            for (Field field : clazz.getDeclaredFields()) {
                if (!isStaticField(field)) {
                    fieldList.add(field);
                }
            }
            clazz = clazz.getSuperclass();
        }
        return fieldList;
    }

    // ==================== 内部类 ====================
    
    /**
     * 查询结果包装类
     */
    @Data
    @Accessors(chain = true)
    public static class QueryResult<T> {
        private final QueryWrapper<T> wrapper;
        private final Page<T> page;

        public QueryResult(QueryWrapper<T> wrapper, Page<T> page) {
            this.wrapper = wrapper;
            this.page = page;
        }

        /**
         * 执行列表查询
         */
        public List<T> list(IService<T> service) {
            return service.list(wrapper);
        }

        /**
         * 执行分页查询
         */
        public IPage<T> page(IService<T> service) {
            if (page == null) {
                throw new IllegalStateException("未设置分页参数，请先调用page()方法");
            }
            return service.page(page, wrapper);
        }

        /**
         * 执行单条查询
         */
        public T one(IService<T> service) {
            return service.getOne(wrapper);
        }

        /**
         * 执行计数查询
         */
        public long count(IService<T> service) {
            return service.count(wrapper);
        }

        /**
         * 获取查询条件（用于调试）
         */
        public QueryWrapper<T> getWrapper() {
            return wrapper;
        }
    }
}
