/**************************************************************************************** 
 Copyright © 2003-2012 hbasesoft Corporation. All rights reserved. Reproduction or       <br>
 transmission in whole or in part, in any form or by any means, electronic, mechanical <br>
 or otherwise, is prohibited without the prior written consent of the copyright owner. <br>
 ****************************************************************************************/
package com.hbasesoft.framework.db.mongo;

import static com.hbasesoft.framework.common.ErrorCodeDef.DAO_PROPERTY_IS_EMPTY;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import org.springframework.data.mongodb.core.aggregation.MatchOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.aggregation.SortOperation;
import org.springframework.data.mongodb.core.aggregation.TypedAggregation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import com.alibaba.fastjson2.JSONObject;
import com.hbasesoft.framework.common.ErrorCodeDef;
import com.hbasesoft.framework.common.GlobalConstants;
import com.hbasesoft.framework.common.utils.Assert;
import com.hbasesoft.framework.common.utils.logger.Logger;
import com.hbasesoft.framework.db.core.BaseEntity;
import com.hbasesoft.framework.db.core.DaoConstants;
import com.hbasesoft.framework.db.core.DaoException;
import com.hbasesoft.framework.db.core.config.DataParam;
import com.hbasesoft.framework.db.core.criteria.AbstractQueryWrapper;
import com.hbasesoft.framework.db.core.criteria.AbstractWrapper;
import com.hbasesoft.framework.db.core.criteria.DeleteWrapper;
import com.hbasesoft.framework.db.core.criteria.LambdaDeleteWrapper;
import com.hbasesoft.framework.db.core.criteria.LambdaQueryWrapper;
import com.hbasesoft.framework.db.core.criteria.LambdaUpdateWrapper;
import com.hbasesoft.framework.db.core.criteria.Operator;
import com.hbasesoft.framework.db.core.criteria.QueryWrapper;
import com.hbasesoft.framework.db.core.criteria.TempSelection;
import com.hbasesoft.framework.db.core.criteria.UpdateWrapper;
import com.hbasesoft.framework.db.core.utils.PagerList;
import com.hbasesoft.framework.db.core.utils.SQlCheckUtil;
import com.mongodb.BasicDBObject;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;

/**
 * <Description> <br>
 *
 * @param <T> t
 * @author 王伟<br>
 * @version 1.0<br>
 * @taskId <br>
 * @CreateDate 2024年12月30日 <br>
 * @since V1.0<br>
 * @see com.hbasesoft.framework.db.mongo <br>
 */
public class MongoBaseDao<T extends BaseEntity> implements BaseMongoDao<T> {

    /** */
    private static Logger logger = new Logger(MongoBaseDao.class);

    /** */
    private static final int MAX_SIZE = 1000;

    /** */
    private Class<T> entityClazz;

    /** */
    public static final Map<Class<?>, Object> NUMBER_DEFAULT = new HashMap<Class<?>, Object>() {
        {
            put(Integer.class, 0);
            put(int.class, 0);
            put(Long.class, 0L);
            put(long.class, 0L);
            put(Double.class, 0.0d);
            put(double.class, 0.0d);
            put(Float.class, 0.0f);
            put(float.class, 0.0f);
            put(Short.class, (short) 0);
            put(short.class, (short) 0);
            put(Byte.class, (byte) 0);
            put(byte.class, (byte) 0);
        }
    };

    /** */
    private static final int PAGE_SIZE = 10;

    /**
     * Description: <br>
     *
     * @param sqls
     * @param param
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public int[] batchExcuteSql(final String[] sqls, final DataParam param) {
        try {

            int[] result = new int[sqls.length];
            for (int i = 0; i < sqls.length; i++) {
                String sql = sqls[i];
                result[i] = excuteSql(sql, param);
            }
            return result;
        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new DaoException(ErrorCodeDef.BATCH_EXECUTE_ERROR, e);
        }
    }

    /**
     * Description: <br>
     *
     * @param specification <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void delete(final DeleteSpecification<T> specification) {
        deleteBySpecification(specification.toSpecification(new DeleteWrapper<>()));
    }

    /**
     * Description: <br>
     *
     * @param entity <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void delete(final T entity) {
        // 解析实体类并获取表结构信息 （true表示忽略空值）
        Map<String, Object> columnValues = parseEntity(entity, true);
        if (MapUtils.isEmpty(columnValues)) {
            throw new DaoException(ErrorCodeDef.ANALYSIS_ENTITY_ERROR);
        }
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entity.getClass());
        // 构建查询条件
        Query query = buildQueryFromColumnValues(columnValues);
        if (Objects.isNull(query.getQueryObject()) || query.getQueryObject().isEmpty()) {
            throw new DaoException(ErrorCodeDef.PARAM_NOT_NULL, "删除条件");
        }
        getMongoTemplate().remove(query, collectionName);
    }

    /**
     * Description: <br>
     *
     * @param entities <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void deleteBatch(final Collection<T> entities) {
        if (entities.size() > GlobalConstants.DEFAULT_LINES) {
            throw new DaoException(ErrorCodeDef.TOO_MANY_OBJECTS);
        }
        // 构建查询条件，这里假设每个实体都有一个 getId 方法返回其唯一标识符
        Field field = MongoBaseDaoUtil.findPrimaryKeyField(entities.iterator().next().getClass());
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entities.iterator().next().getClass());
        if (null == field || StringUtils.isBlank(collectionName)) {
            throw new IllegalStateException("Entity does not have an @Id annotated field.");
        }
        String key = field.getAnnotation(Column.class) != null ? "_id" : field.getName();

        List<Object> idList = entities.stream().map(entity -> {
            try {
                return field.get(entity);
            }
            catch (IllegalAccessException e) {
                throw new DaoException(e);
            }
        }).collect(Collectors.toList());

        Query query = new Query(Criteria.where(key).in(idList));
        // 使用 MongoTemplate 执行批量删除
        getMongoTemplate().remove(query, collectionName);
    }

    /**
     * Description: <br>
     *
     * @param id <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void deleteById(final Serializable id) {
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entityClazz);
        Field field = MongoBaseDaoUtil.findPrimaryKeyField(getEntityClazz());
        if (null == field || StringUtils.isBlank(collectionName)) {
            throw new IllegalStateException("Entity does not have an @Id annotated field.");
        }
        String key = field.getAnnotation(Column.class) != null ? "_id" : field.getName();
        Query query = new Query(Criteria.where(key).is(id));
        getMongoTemplate().remove(query, collectionName);
    }

    /**
     * Description: <br>
     *
     * @param ids <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void deleteByIds(final Collection<? extends Serializable> ids) {
        if (ids == null || ids.isEmpty()) {
            return;
        }
        Field field = MongoBaseDaoUtil.findPrimaryKeyField(getEntityClazz());
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entityClazz);
        if (null == field || StringUtils.isBlank(collectionName)) {
            throw new IllegalStateException("Entity does not have an @Id annotated field.");
        }
        String key = field.getAnnotation(Column.class) != null ? "_id" : field.getName();
        Query query = new Query(Criteria.where(key).in(new ArrayList<>(ids)));
        getMongoTemplate().remove(query, collectionName);
    }

    /**
     * Description: <br>
     *
     * @param specification <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void deleteByLambda(final LambdaDeleteSpecification<T> specification) {
        deleteBySpecification(specification.toSpecification(new LambdaDeleteWrapper<>()));
    }

    /**
     * Description: <br>
     *
     * @param wrapper <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public void deleteByLambda(final LambdaDeleteWrapper<T> wrapper) {
        deleteBySpecification(wrapper);
    }

    /**
     * Description: <br>
     *
     * @param sql
     * @param param
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public int excuteSql(final String sql, final DataParam param) {
        try {
            SQlCheckUtil.checkSql(sql);
            Document commandDocument = Document.parse(sql);
            MongoBaseDaoUtil.replacePlaceholders(commandDocument, param.getParamMap());

            Document document = getMongoTemplate().getDb().runCommand(commandDocument);
            // 根据不同的操作类型获取受影响的文档数
            if (document.containsKey("n") && document.get("n") instanceof Number) {
                return ((Number) document.get("n")).intValue();
            }
            else if (document.containsKey("deletedCount") && document.get("deletedCount") instanceof Number) {
                return ((Number) document.get("deletedCount")).intValue();
            }
            else if (document.containsKey("upsertedCount") && document.get("upsertedCount") instanceof Number) {
                return ((Number) document.get("upsertedCount")).intValue();
            }
            else if (document.containsKey("matchedCount") && document.get("matchedCount") instanceof Number) {
                return ((Number) document.get("matchedCount")).intValue();
            }
            else if (document.containsKey("insertedCount") && document.get("insertedCount") instanceof Number) {
                return ((Number) document.get("insertedCount")).intValue();
            }
            else {
                logger.warn("无法确定受影响的文档数，返回0。");
                return 0;
            }
        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new DaoException(ErrorCodeDef.EXECUTE_ERROR, e);
        }
    }

    /**
     * Description: <br>
     *
     * @param specification
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public T get(final QuerySpecification<T> specification) {
        return getBySpecification(specification.toSpecification(new QueryWrapper<>()));
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param specification
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> M get(final QuerySpecification<T> specification, final Class<M> clazz) {
        return getBySpecification(specification.toSpecification(new QueryWrapper<>()), clazz);
    }

    /**
     * Description: <br>
     *
     * @param wrapper
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public T get(final QueryWrapper<T> wrapper) {
        return getBySpecification(wrapper);
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param wrapper
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> M get(final QueryWrapper<T> wrapper, final Class<M> clazz) {
        return getBySpecification(wrapper, clazz);
    }

    /**
     * Description: <br>
     *
     * @param id
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public T get(final Serializable id) {
        Field field = MongoBaseDaoUtil.findPrimaryKeyField(getEntityClazz());
        if (null == field) {
            throw new IllegalStateException("Entity does not have an @Id annotated field.");
        }
        String key = field.getAnnotation(Column.class) != null ? "_id" : field.getName();
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entityClazz);
        Query query = new Query(Criteria.where(key).is(id));

        Map one = getMongoTemplate().findOne(query, Map.class, collectionName);

        Map<String, Object> columnMapping = MongoBaseDaoUtil.parseEntityName(entityClazz, false);
        T t = queryMapToEntity(one, entityClazz, columnMapping);
        return t;
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param specification
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> M getByLambda(final LambdaQuerySpecification<T, M> specification, final Class<M> clazz) {
        return getBySpecification(specification.toSpecification(new LambdaQueryWrapper<>()), clazz);
    }

    /**
     * Description: <br>
     *
     * @param specification
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public T getByLambda(final LambdaQuerySpecification<T, T> specification) {
        return getBySpecification(specification.toSpecification(new LambdaQueryWrapper<>()));
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param wrapper
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> M getByLambda(final LambdaQueryWrapper<T, M> wrapper, final Class<M> clazz) {
        return getBySpecification(wrapper, clazz);
    }

    /**
     * Description: <br>
     *
     * @param wrapper
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public T getByLambda(final LambdaQueryWrapper<T, T> wrapper) {
        return getBySpecification(wrapper);
    }

    /**
     * @param specification
     * @return T
     */
    public T getBySpecification(final AbstractQueryWrapper<T> specification) {
        return getBySpecification(specification, entityClazz);
    }

    /**
     * @param specification
     * @param clazz
     * @param <M>
     * @return <M> M
     */
    public <M> M getBySpecification(final AbstractQueryWrapper<T> specification, final Class<M> clazz) {
        Assert.notNull(entityClazz, ErrorCodeDef.PROXY_TARGET_NOT_FOUND);
        if (!entityClazz.isAnnotationPresent(Entity.class)) {
            throw new IllegalArgumentException("The provided class is not an Entity.");
        }
        Assert.notNull(specification, ErrorCodeDef.PARAM_NOT_NULL, "查询条件");
        Map<String, Object> parseEntityNameMap = MongoBaseDaoUtil.parseEntityName(entityClazz, true);
        Aggregation aggregation = toQueryPredicate(parseEntityNameMap, specification, null, null);
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entityClazz);
        if (MongoBaseDaoUtil.SCALAR_TYPES.contains(clazz)) {
            // 执行 sql
            AggregationResults<Map> results = getMongoTemplate().aggregate(aggregation, collectionName, Map.class);
            Assert.isTrue(Objects.nonNull(results) && Objects.nonNull(results.getMappedResults()),
                ErrorCodeDef.EXECUTE_ERROR);
            // 基本数据类型如计算等 操作 查询不到的时候结果是null 返回基本数据类型默认值
            if (results.getMappedResults().isEmpty() && NUMBER_DEFAULT.keySet().contains(clazz)) {
                return (M) NUMBER_DEFAULT.get(clazz);
            }
            for (Map<String, Object> result : results.getMappedResults()) {
                // 假设specification中指定了要查询的字段名
                String targetField = specification.getSelectionList().get(0).getField(); // 需要在specification中定义此方法
                return (M) result.get(targetField);
            }
        }
        AggregationResults<Map> results = getMongoTemplate().aggregate(aggregation, collectionName, Map.class);
        Assert.isTrue(Objects.nonNull(results) && Objects.nonNull(results.getMappedResults()),
            ErrorCodeDef.EXECUTE_ERROR);
        // 解析实体类，获取字段映射关系
        Map<String, Object> columnMapping = MongoBaseDaoUtil.parseEntityName(clazz, false);
        T t = queryMapToEntity(results.getMappedResults().stream().findFirst().get(), (Class<T>) clazz, columnMapping);
        return (M) t;
    }

    /**
     * Description: <br>
     *
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    protected Class<T> getEntityClazz() {
        Assert.notNull(entityClazz, ErrorCodeDef.PROXY_TARGET_NOT_FOUND);
        return entityClazz;
    }

    protected MongoTemplate getMongoTemplate() {
        // 事务必须是开启的(Required)，否则获取不到
        return TransactionManagerHolder.getMongoTemplate();
    }

    /**
     * Description: <br>
     *
     * @param specification
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public List<T> query(final QuerySpecification<T> specification) {
        return queryBySpecification(specification.toSpecification(new QueryWrapper<>()));
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param specification
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> List<M> query(final QuerySpecification<T> specification, final Class<M> clazz) {
        return queryBySpecification(specification.toSpecification(new QueryWrapper<>()), clazz);
    }

    /**
     * Description: <br>
     *
     * @param wrapper
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public List<T> query(final QueryWrapper<T> wrapper) {
        return queryBySpecification(wrapper);
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param wrapper
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> List<M> query(final QueryWrapper<T> wrapper, final Class<M> clazz) {
        return queryBySpecification(wrapper, clazz);
    }

    /**
     * Description: <br>
     *
     * @param mongodbSql
     * @param param
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public Object query(final String mongodbSql, final DataParam param) {
        try {
            SQlCheckUtil.checkSql(mongodbSql);

            // Redis缓存序列化时不能有void返回类型，特殊处理一下
            if (param.getReturnType() == null) { // @sql返回值类型
                param.setReturnType(void.class);
            }

            Map<String, Object> dataMap = param.getParamMap();
            MongoTemplate mongoTemplate = getMongoTemplate();
            // 将dataMap中的参数设置到mongodbSql中对应的占位符上
            Document commandDocument = Document.parse(mongodbSql);
            MongoBaseDaoUtil.replacePlaceholders(commandDocument, dataMap);

            // 处理分页逻辑
            if (dataMap.containsKey(DaoConstants.PAGE_INDEX)) {
                int pageIndex = Integer.parseInt(dataMap.get(DaoConstants.PAGE_INDEX).toString());
                if (pageIndex <= 0) {
                    pageIndex = 1;
                }
                int pageSize = dataMap.containsKey(DaoConstants.PAGE_SIZE)
                    ? Integer.parseInt(dataMap.get(DaoConstants.PAGE_SIZE).toString())
                    : PAGE_SIZE;
                if (pageSize <= 0 || pageSize > MAX_SIZE) {
                    pageSize = PAGE_SIZE;
                }
                // 首先查询总记录数
                Document countCommand = new Document(commandDocument);
                Document document = MongoBaseDaoUtil.prepareCountCommand(countCommand); // 修改命令为统计数量
                Document countResult = mongoTemplate.getDb().runCommand(document);
                List<Document> documents = countResult.get("cursor", Document.class).getList("firstBatch",
                    Document.class);

                // 执行分页查询
                long totalDocuments = CollectionUtils.isEmpty(documents) ? 0 : documents.get(0).getInteger("total");
                Document resultDocument = mongoTemplate.getDb().runCommand(commandDocument);
                // 提取查询结果列表
                List<Document> list1 = resultDocument.get("cursor", Document.class).getList("firstBatch",
                    Document.class);
                List<Object> resultList = new ArrayList<>();
                list1 = CollectionUtils.isEmpty(list1) ? new ArrayList<>() : list1;
                for (Document document1 : list1) {
                    Object entity = MongoBaseDaoUtil.mapToEntity(document1, param.getBeanType());
                    resultList.add(entity);
                }
                PagerList list = new PagerList();
                list.setPageIndex(pageIndex);
                list.setPageSize(pageSize);
                list.setTotalCount(totalDocuments);
                list.addAll(resultList);

                return list;
            }
            else {
                Document document = mongoTemplate.getDb().runCommand(commandDocument);
                // 根据param.getReturnType()转换结果
                Class<?> returnType = param.getReturnType();
                Class<?> beanType = param.getBeanType();
                if (returnType == void.class && beanType == void.class) {
                    return null; // 或者按照业务需要处理
                }
                else if (returnType == void.class && Serializable.class.isAssignableFrom(beanType)) {
                    List<Document> list = document.get("cursor", Document.class).getList("firstBatch", Document.class);
                    // 基本数据类型 就获取 第一个对象的 value值
                    if (MongoBaseDaoUtil.SCALAR_TYPES.contains(beanType)) {
                        if (CollectionUtils.isEmpty(list)) {
                            return NUMBER_DEFAULT.get(beanType);
                        }
                        return list.get(0).values().iterator().next();
                    }
                    // 其他类型 ，默认是 引用数据类型
                    if (CollectionUtils.isEmpty(list)) {
                        return null;
                    }
                    Object entity = MongoBaseDaoUtil.mapToEntity(list.get(0), beanType);
                    return entity;
                }
                else if (List.class.isAssignableFrom(returnType) && Serializable.class.isAssignableFrom(beanType)) {
                    // 返回的是list集合
                    List<Document> documents = document.get("cursor", Document.class).getList("firstBatch",
                        Document.class);
                    List<Object> resultList = new ArrayList<>();
                    for (Document document1 : documents) {
                        Object entity = MongoBaseDaoUtil.mapToEntity(document1, beanType);
                        resultList.add(entity);
                    }
                    return resultList;
                }
                else {
                    // 其他的 就返回 数组 集合自行处理
                    return document.get("cursor", Document.class).getList("firstBatch", Document.class);
                }
            }
        }
        catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new DaoException(ErrorCodeDef.QUERY_ERROR, e);
        }
    }

    /**
     * Description: <br>
     *
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public List<T> queryAll() {
        Assert.notNull(entityClazz, ErrorCodeDef.PROXY_TARGET_NOT_FOUND);
        // 创建一个空的 Query 对象，这将匹配集合中的所有文档
        Query query = new Query();
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entityClazz);
        // 执行查询并返回结果列表
        List<Map> objects = getMongoTemplate().find(query, Map.class, collectionName);

        Map<String, Object> columnMapping = MongoBaseDaoUtil.parseEntityName(entityClazz, false);
        List<T> resultList = objects.stream().map(result -> queryMapToEntity(result, entityClazz, columnMapping))
            .collect(Collectors.toList());
        return resultList;
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param specification
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> List<M> queryByLambda(final LambdaQuerySpecification<T, M> specification, final Class<M> clazz) {
        return queryBySpecification(specification.toSpecification(new LambdaQueryWrapper<>()), clazz);
    }

    /**
     * Description: <br>
     *
     * @param specification
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public List<T> queryByLambda(final LambdaQuerySpecification<T, T> specification) {
        return queryBySpecification(specification.toSpecification(new LambdaQueryWrapper<>()));
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param wrapper
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> List<M> queryByLambda(final LambdaQueryWrapper<T, M> wrapper, final Class<M> clazz) {
        return queryBySpecification(wrapper, clazz);
    }

    /**
     * Description: <br>
     *
     * @param wrapper
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public List<T> queryByLambda(final LambdaQueryWrapper<T, T> wrapper) {
        return queryBySpecification(wrapper);
    }

    /**
     * @param wrapper
     * @param clazz
     * @param <M>
     * @return <M> List<M>
     */
    public <M> List<M> queryBySpecification(final AbstractQueryWrapper<T> wrapper, final Class<M> clazz) {
        Assert.notNull(entityClazz, ErrorCodeDef.PROXY_TARGET_NOT_FOUND);
        if (!entityClazz.isAnnotationPresent(Entity.class)) {
            throw new IllegalArgumentException("The provided class is not an Entity.");
        }
        Assert.notNull(wrapper, ErrorCodeDef.PARAM_NOT_NULL, "查询条件");
        Map<String, Object> parseEntityNameMap = MongoBaseDaoUtil.parseEntityName(entityClazz, true);

        Aggregation queryPredicate = toQueryPredicate(parseEntityNameMap, wrapper, null, null);
        // 获取文档名称（集合名称）
        String collectionName = MongoBaseDaoUtil.getTableName(entityClazz);
        // 使用 MongoTemplate 执行聚合查询，并将结果映射到指定的类
        List<Map> results = getMongoTemplate().aggregate(queryPredicate, collectionName, Map.class).getMappedResults();

        Map<String, Object> columnMapping = MongoBaseDaoUtil.parseEntityName(clazz, false);
        List<M> resultList = (List<M>) results.stream()
            .map(result -> queryMapToEntity(result, (Class<T>) clazz, columnMapping)).collect(Collectors.toList());
        return resultList;
    }

    /**
     * Description: <br>
     *
     * @param specification
     * @param pageIndex
     * @param pageSize
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public PagerList<T> queryPager(final QuerySpecification<T> specification, final int pageIndex, final int pageSize) {
        return queryPagerBySpecification(specification.toSpecification(new QueryWrapper<>()), pageIndex, pageSize);
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param specification
     * @param pageIndex
     * @param pageSize
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> PagerList<M> queryPager(final QuerySpecification<T> specification, final int pageIndex,
        final int pageSize, final Class<M> clazz) {
        return queryPagerBySpecification(specification.toSpecification(new QueryWrapper<>()), pageIndex, pageSize,
            clazz);
    }

    /**
     * Description: <br>
     *
     * @param wrapper
     * @param pageIndex
     * @param pageSize
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public PagerList<T> queryPager(final QueryWrapper<T> wrapper, final int pageIndex, final int pageSize) {
        return queryPagerBySpecification(wrapper, pageIndex, pageSize);
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param wrapper
     * @param pageIndex
     * @param pageSize
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> PagerList<M> queryPager(final QueryWrapper<T> wrapper, final int pageIndex, final int pageSize,
        final Class<M> clazz) {
        return queryPagerBySpecification(wrapper, pageIndex, pageSize, clazz);
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param specification
     * @param pageIndex
     * @param pageSize
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> PagerList<M> queryPagerByLambda(final LambdaQuerySpecification<T, M> specification, final int pageIndex,
        final int pageSize, final Class<M> clazz) {
        return queryPagerBySpecification(specification.toSpecification(new LambdaQueryWrapper<>()), pageIndex, pageSize,
            clazz);
    }

    /**
     * Description: <br>
     *
     * @param specification
     * @param pageIndex
     * @param pageSize
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public PagerList<T> queryPagerByLambda(final LambdaQuerySpecification<T, T> specification, final int pageIndex,
        final int pageSize) {
        return queryPagerBySpecification(specification.toSpecification(new LambdaQueryWrapper<>()), pageIndex,
            pageSize);
    }

    /**
     * Description: <br>
     *
     * @param <M>
     * @param wrapper
     * @param pageIndex
     * @param pageSize
     * @param clazz
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public <M> PagerList<M> queryPagerByLambda(final LambdaQueryWrapper<T, M> wrapper, final int pageIndex,
        final int pageSize, final Class<M> clazz) {
        return queryPagerBySpecification(wrapper, pageIndex, pageSize, clazz);
    }

    /**
     * Description: <br>
     *
     * @param wrapper
     * @param pageIndex
     * @param pageSize
     * @return <br>
     * @author 王伟<br>
     * @taskId <br>
     */
    @Override
    public PagerList<T> queryPagerByLambda(final LambdaQueryWrapper<T, T> wrapper, final int pageIndex,
        final int pageSize) {
        return queryPagerBySpecification(wrapper, pageIndex, pageSize);
    }

    /**
     * Description: <br>
     *
     * @param entity <br>
     * @author 王伟<br>
