package com.persagy.dmp.basic.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.persagy.dmp.basic.model.QueryCriteria;
import com.persagy.dmp.basic.model.QueryOperator;
import com.persagy.dmp.common.model.entity.BaseEntity;

import java.util.Iterator;
import java.util.List;

/**
 * 查询条件 助手
 * @author Charlie Yu
 * @date 2021-06-25
 */
public class QueryCriteriaHelper {

    /**
     * 转换为Page分页信息
     * @param criteria
     * @return
     */
    public static <T> Page<T> toPage(QueryCriteria criteria) {
        if(criteria == null) {
            criteria = new QueryCriteria();
        }
        // 当前页默认为1
        if(criteria.getPage() == null || criteria.getPage() < 1) {
            criteria.setPage(1L);
        }
        // 没有每页行数表示不分页
        if(criteria.getSize() == null || criteria.getSize() < 1) {
            // 20210923 为避免接口滥用引发内存溢出，限制返回条数
            criteria.setSize(Long.MAX_VALUE);
        }
        Page<T> pageInfo = new Page<>();
        pageInfo.setCurrent(criteria.getPage());
        pageInfo.setSize(criteria.getSize());
        /// 20210819 size<-1时，拦截器不执行page的配置，因此改为在wrapper中排序
//        pageInfo.setOrders(criteria.getOrders());
        pageInfo.setSearchCount(!criteria.isWithoutCount());
        return pageInfo;
    }

    /**
     * 转换为查询条件
     * @param wrapper
     * @param criteria
     * @param clazz 用于判定属性是否存在. - 通过反射无法从wrapper中获取到泛型class，还是显式传参吧
     */
    public static <T extends BaseEntity> void toWrapper(QueryWrapper<T> wrapper, QueryCriteria criteria, Class<T> clazz) {
        if(criteria == null) {
            return;
        }
        toWrapper(wrapper, criteria.getCriteria());
        ensureOrders(wrapper, criteria.getOrders(), clazz);
    }

    /**
     * 转换为查询条件
     * @param wrapper
     */
    public static <T extends BaseEntity> void toWrapper(QueryWrapper<T> wrapper, ObjectNode criteria) {
        if(criteria == null || criteria.isEmpty(null)) {
            return;
        }
        Iterator<String> fields = criteria.fieldNames();
        // 按字段循环
        while(fields.hasNext()) {
            String field = fields.next();
            JsonNode fieldValue = criteria.get(field);
            // #JSON#开关的不转驼峰
            String dbField = toUnderlineCase(field);
            // 20210813增加ADM传sql特殊处理 - 不公开到接口文档中
            if("$sql".equalsIgnoreCase(field)) {
                wrapper.apply((String) JsonNodeUtils.getNodeValue(fieldValue));
                continue;
            }
            // 20210816增加or条件支持
            if(QueryOperator.OR.getIndex().equalsIgnoreCase(field)) {
                // 内部重新创建QueryWrapper
                wrapper.or(orWrapper -> addOrCondition(orWrapper, fieldValue));
                continue;
            }
            // 20210827增加and(condition OR condition)条件支持
            if(QueryOperator.AND_OR.getIndex().equalsIgnoreCase(field)) {
                // 内部重新创建QueryWrapper
                wrapper.and(orWrapper -> addAndOrCondition(orWrapper, fieldValue));
                continue;
            }
            commonAddCondition(wrapper,fieldValue,dbField);
        }
    }
    /***
     * Description: andOr的条件
     * @param wrapper : 查询条件
     * @param fieldObj : 字段对象
     * @return : void
     * @author : lijie
     * @date :2021/8/27 21:39
     * Update By lijie 2021/8/27 21:39
     */
    private static <T extends BaseEntity> void addAndOrCondition(QueryWrapper<T> wrapper, JsonNode fieldObj) {
        if (!fieldObj.isObject()){
            return;
        }
        Iterator<String> fieldNames = fieldObj.fieldNames();
        while (fieldNames.hasNext()){
            String field = fieldNames.next();
            JsonNode fieldValue = fieldObj.get(field);
            // #JSON#开关的不转驼峰
            String dbField = toUnderlineCase(field);
            wrapper.or(sonWrapper->commonAddCondition(sonWrapper,fieldValue,dbField));
        }
    }
    /***
     * Description: 通用查询条件组装语句
     * @param wrapper : 查询对象
     * @param fieldValue : 字段值
     * @param dbField : 数据库字段
     * @return : void
     * @author : lijie
     * @date :2021/8/27 21:41
     * Update By lijie 2021/8/27 21:41
     */
    private static <T extends BaseEntity> void commonAddCondition(QueryWrapper<T> wrapper,JsonNode fieldValue,String dbField) {
        // 值节点
        if(fieldValue.isValueNode()) {
            wrapper.eq(dbField, JsonNodeUtils.getNodeValue(fieldValue));
            return;
        }
        // 数组
        if(fieldValue.isArray()) {
            List listValue = JsonNodeUtils.getListValue(fieldValue);
            if (CollUtil.isEmpty(listValue)){
                return;
            }
            wrapper.in(dbField, listValue);
            return;
        }
        // 对象
        if(fieldValue.isObject()) {
            Iterator<String> valueOperators = fieldValue.fieldNames();
            while(valueOperators.hasNext()) {
                String valueOperator = valueOperators.next();
                JsonNode operatorValue = fieldValue.get(valueOperator);
                addCondition(wrapper, dbField, valueOperator,operatorValue);
            }
        }
    }

    /**
     * 添加or条件
     * @param wrapper
     * @param node
     * @param <T>
     */
    private static <T extends BaseEntity> void addOrCondition(QueryWrapper<T> wrapper, JsonNode node) {
        if(node == null || node.isNull()) {
            return;
        }
        // 如果是数组 - 递归继续处理即可
        if(node.isArray()) {
            Iterator<JsonNode> elements = node.elements();
            while (elements.hasNext()) {
                // 递归继续处理
                JsonNode objNode = elements.next();
                addOrCondition(wrapper, objNode);
            }
            return;
        }
        // 如果是对象，则转换条件
        if(node.isObject()) {
            // 对象 递归处理
            ObjectNode obj = (ObjectNode) node;
            toWrapper(wrapper, obj);
            return;
        }
    }

    /**
     * 驼峰字段转下划线
     * @param column
     * @return
     */
    public static String toUnderlineCase(String column) {
        // #JSON#开关的不转驼峰
        return StrUtil.startWith(column, "#JSON#")?column.substring(6):StrUtil.toUnderlineCase(column);
    }

    /**
     * 按条件类型添加查询条件
     * @param wrapper
     * @param field
     * @param operator
     * @param valueNode
     */
    private static <T extends BaseEntity> void addCondition(QueryWrapper<T> wrapper, String field, String operator, JsonNode valueNode) {
        if(QueryOperator.NE.getIndex().equalsIgnoreCase(operator)) {
            wrapper.ne(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.GT.getIndex().equalsIgnoreCase(operator)) {
            wrapper.gt(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.GTE.getIndex().equalsIgnoreCase(operator)) {
            wrapper.ge(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.LT.getIndex().equalsIgnoreCase(operator)) {
            wrapper.lt(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.LTE.getIndex().equalsIgnoreCase(operator)) {
            wrapper.le(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.IN.getIndex().equalsIgnoreCase(operator)) {
            wrapper.in(field, JsonNodeUtils.getListValue(valueNode));
        } else if(QueryOperator.IN_SQL.getIndex().equalsIgnoreCase(operator)) {
            wrapper.inSql(field, (String) JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.NOT_IN_SQL.getIndex().equalsIgnoreCase(operator)) {
            wrapper.notInSql(field, (String) JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.LIKE.getIndex().equalsIgnoreCase(operator)) {
            wrapper.like(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.LIKE_LEFT.getIndex().equalsIgnoreCase(operator)) {
            wrapper.likeLeft(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.LIKE_RIGHT.getIndex().equalsIgnoreCase(operator)) {
            wrapper.likeRight(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.NOT_LIKE.getIndex().equalsIgnoreCase(operator)) {
            wrapper.notLike(field, JsonNodeUtils.getNodeValue(valueNode));
        } else if(QueryOperator.NULL.getIndex().equalsIgnoreCase(operator)) {
            boolean nullFlag = valueNode.booleanValue();
            if(nullFlag) {
                wrapper.isNull(field);
            } else {
                wrapper.isNotNull(field);
            }
        }
    }

    /**
     * 拼接排序条件
     * @param wrapper
     * @param orders
     * @param <T>
     */
    public static <T extends BaseEntity> void ensureOrders(QueryWrapper<T> wrapper, List<OrderItem> orders, Class<T> clazz) {
        if(CollUtil.isEmpty(orders)) {
            return;
        }
        for(OrderItem order:orders) {
            String column = order.getColumn();
            // 只有实体存在的属性和json扩展属性参与排序，其他属性忽略
            if(!(StrUtil.startWith(column, "#JSON#") ||
                    ReflectUtil.hasField(clazz, column))) {
                continue;
            }
            column = toUnderlineCase(order.getColumn());
            wrapper.orderBy(true, order.isAsc(), column);
        }
    }
}
