package com.wx.application.base;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.Map;

@SuppressWarnings({"rawtypes", "hiding"})
public class DynamicSpecifications<T extends BaseEntity<?>> {
    /**
     * 开始构造表达式
     *
     * @param filters
     * @param <T>
     * @return
     */
    @SuppressWarnings({"incomplete-switch"})
    public <T> QueryWrapper<T> bySearchFilter(final Collection<SearchFilter> filters) {

        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        if (CollectionUtil.isNotEmpty(filters)) {


            for (SearchFilter filter : filters) {
                filter.fieldName = StrUtil.toUnderlineCase(filter.fieldName);
                // nested path translate, 如Task的名为"user.name"的filedName, 转换为Task.user.name属性
                // fixme 暂不支持级联查询
                if (filter.logic != null) {
                    switch (filter.logic) {
                        case OR:
                            queryWrapper = queryWrapper.or();
                            break;
                    }
                }
                if (filter.operator == null) {
                    continue;
                }
                switch (filter.operator) {
                    case EQ:
                        queryWrapper = queryWrapper.eq(filter.fieldName, filter.value);
                        break;
                    case LIKE:
                        queryWrapper = queryWrapper.like(filter.fieldName, filter.value);
                        break;
                    case GT:
                        queryWrapper = queryWrapper.gt(filter.fieldName, filter.value);
                        break;
                    case LT:
                        queryWrapper = queryWrapper.lt(filter.fieldName, filter.value);
                        break;
                    case GTE:
                        queryWrapper = queryWrapper.ge(filter.fieldName, filter.value);
                        break;
                    case LTE:
                        queryWrapper = queryWrapper.le(filter.fieldName, filter.value);
                        break;
                    case IN:
                        queryWrapper = queryWrapper.in(filter.fieldName, StrUtil.split(filter.value.toString(), ',', -1));
                        break;
                    case NIN:
                        queryWrapper = queryWrapper.notIn(filter.fieldName, StrUtil.split(filter.value.toString(), ',', -1));
                        break;
                    case NEQ:
                        queryWrapper = queryWrapper.ne(filter.fieldName, filter.value);
                        break;
                    case FIELDEQ:
                        queryWrapper = queryWrapper.apply(StrUtil.format("{}={}", filter.fieldName, filter.value));
                        break;
                    case ISNOTNULL:
                        queryWrapper = queryWrapper.isNotNull(filter.fieldName);
                        break;
                    case ISNULL:
                        queryWrapper = queryWrapper.isNull(filter.fieldName);
                        break;
                    case ISEMPTY:
                        queryWrapper = queryWrapper.eq(filter.fieldName, "");
                        break;
                    case ISNOTEMPTY:
                        queryWrapper = queryWrapper.ne(filter.fieldName, "");
                        break;
                    case FIELDNEQ:
                        queryWrapper = queryWrapper.apply(StrUtil.format("{}!={}", filter.fieldName, filter.value));
                        break;
                    case DESC:
                        queryWrapper.orderByDesc(filter.fieldName);
                        break;
                    case DESCA:
                        queryWrapper.orderByDesc(filter.value.toString().split(","));
                        break;
                    case ASC:
                        queryWrapper.orderByAsc(filter.fieldName);
                        break;
                    case ASCA:
                        queryWrapper.orderByAsc(filter.value.toString().split(","));
                        break;
                }
            }
        }
        return queryWrapper;
    }


    /**
     * 直接解析map的方式
     *
     * @param map
     * @param <T>
     * @return
     */
    public <T> QueryWrapper<T> parseSearchParams(Map map) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        // 获取排序字段，支持多个
        String order = MapUtil.getStr(map, "order");
        // 获取排序类型
        String by = StrUtil.isBlank(MapUtil.getStr(map, "by")) ? "asc" : MapUtil.getStr(map, "by");
        // 设置查询条件
        String searchParam = MapUtil.getStr(map, "searchParam");
        queryWrapper = parseSearchParams(searchParam);
        // 如果需要排序
        if (!StrUtil.isBlank(order)) {
            // 多个字段一起排序
            if (order.contains("|")) {
                // 多个字段排序
                String[] orders = StringUtils.split(order, "|");
                for (int i = 0; i < orders.length; i++) {
                    // 设置order
                    if (by.toLowerCase().equals("desc")) {
                        queryWrapper.orderByDesc(StrUtil.toUnderlineCase(orders[i]));
                    } else {
                        queryWrapper.orderByAsc(StrUtil.toUnderlineCase(orders[i]));
                    }
                }
            }
            // 单个字段排序
            else {
                // 设置order
                if (by.toLowerCase().equals("desc")) {
                    queryWrapper.orderByDesc(StrUtil.toUnderlineCase(order));
                } else {
                    queryWrapper.orderByAsc(StrUtil.toUnderlineCase(order));
                }
            }
        }
        return queryWrapper;
    }

    /**
     * 解析json字符串为查询参数
     *
     * @param searchParam
     * @param <T>
     * @return
     */

    public <T> QueryWrapper<T> parseSearchParams(String searchParam) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        try {
            JSONArray searchData = JSONArray.parseArray(searchParam);
            queryWrapper = parseSearchParams(searchData, null);
        } catch (Exception e) {
        }
        return queryWrapper;
    }

    /**
     * 解析jsonarray为查询参数
     *
     * @param searchParam
     * @param <T>
     * @return
     */
    public <T> QueryWrapper<T> parseSearchParams(JSONArray searchParam, QueryWrapper<T> queryWrapper) {
        // 定义返回参数
        if (queryWrapper == null) {
            queryWrapper = new QueryWrapper<>();
        }
        for (int i = 0; i < searchParam.size(); i++) {
            JSONObject item = searchParam.getJSONObject(i);
            // 如果是组模式
            if (SearchFilter.Mod.group.toString().equals(item.getString("mod"))) {
                // 如果是or连接
                if (SearchFilter.Logic.OR.toString().toLowerCase().equals(item.getString("logic").toLowerCase())) {
                    // 如果存在子节点
                    if (item.getJSONArray("children") != null) {
                        queryWrapper.or((wrapper) -> {
                            parseSearchParams(item.getJSONArray("children"), wrapper);
                        });
                    }
                }
                // 如果是and连接
                else {
                    // 如果存在子节点
                    if (item.getJSONArray("children") != null) {
                        queryWrapper.and((wrapper) -> {
                            parseSearchParams(item.getJSONArray("children"), wrapper);
                        });
                    }
                }
            }
            // 如果是条件模式
            else {
                // 表达式
                String operator = item.getString("operator");
                // 查询字段，支持复合字段
                String fieldName = item.getString("field");
                // 后续转化根据类型
                String type = item.getString("type");
                // 查询值
                Object value = item.getString("value");
                // 连接符
                String logic = StrUtil.isBlank(item.getString("logic")) ? "and" : item.getString("logic");
                // 如果是多字段查询同一个值
                if (fieldName.contains("|")) {
                    String[] fields = StringUtils.split(fieldName, "|");
                    // 如果是and连接符
                    if (logic.toLowerCase().equals("and")) {
                        queryWrapper.and((wrapper) -> {
                            for (int j = 0; j < fields.length; j++) {
                                wrapper.or();
                                consumption(wrapper, operator, fields[j], value);
                            }
                        });
                    }
                    // 如果是or连接符
                    else {
                        queryWrapper.or((wrapper) -> {
                            for (int j = 0; j < fields.length; j++) {
                                wrapper.or();
                                consumption(wrapper, operator, fields[j], value);
                            }
                        });
                    }
                } else {
                    // 如果是or连接符
                    if (!StrUtil.isBlank(logic) && logic.toLowerCase().equals("and")) {
                        queryWrapper.or();
                    }
                    consumption(queryWrapper, operator, fieldName, value);
                }
            }
        }
        return queryWrapper;
    }

    public <T> QueryWrapper<T> consumption(QueryWrapper<T> queryWrapper, String operator, String fieldName, Object value) {
        // 转换字段名格式，把 驼峰转为数据库下划线形式
        fieldName = StrUtil.toUnderlineCase(fieldName);
        if (!StrUtil.isBlank(operator)) {
            switch (operator.toUpperCase()) {
                case "EQ":
                    queryWrapper = queryWrapper.eq(fieldName, value);
                    break;
                case "LIKE":
                    queryWrapper = queryWrapper.like(fieldName, value);
                    break;
                case "GT":
                    queryWrapper = queryWrapper.gt(fieldName, value);
                    break;
                case "LT":
                    queryWrapper = queryWrapper.lt(fieldName, value);
                    break;
                case "GTE":
                    queryWrapper = queryWrapper.ge(fieldName, value);
                    break;
                case "LTE":
                    queryWrapper = queryWrapper.le(fieldName, value);
                    break;
                case "IN":
                    queryWrapper = queryWrapper.in(fieldName, StrUtil.split(value.toString(), ',',-1));
                    break;
                case "NEQ":
                    queryWrapper = queryWrapper.ne(fieldName, value);
                    break;
                case "FIELDEQ":
                    queryWrapper = queryWrapper.apply(StrUtil.format("{}={}", fieldName, value));
                    break;
                case "ISNOTNULL":
                    queryWrapper = queryWrapper.isNotNull(fieldName);
                    break;
                case "ISNULL":
                    queryWrapper = queryWrapper.isNull(fieldName);
                    break;
                case "ISEMPTY":
                    queryWrapper = queryWrapper.eq(fieldName, "");
                    break;
                case "ISNOTEMPTY":
                    queryWrapper = queryWrapper.ne(fieldName, "");
                    break;
                case "FIELDNEQ":
                    queryWrapper = queryWrapper.apply(StrUtil.format("{}!={}", fieldName, value));
                    break;
                case "DESC":
                    queryWrapper.orderByDesc(fieldName);
                    break;
                case "ASC":
                    queryWrapper.orderByAsc(fieldName);
                    break;
            }
        }
        return queryWrapper;
    }
}
