package com.chushang.common.mybatis.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chushang.common.core.util.StringUtils;
import com.chushang.common.mybatis.annotation.Condition;
import com.chushang.common.mybatis.base.BaseEntity;
import com.chushang.common.mybatis.exception.MybatisConditionException;
import com.chushang.common.mybatis.page.CommonParam;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class WrapperUtils {

    public static <T> LambdaQueryWrapper<T> builder(String... columns) {
        return builder(null, null, columns);
    }

    public static void buildSql(Object query)
    {
        // 获取注解
        Field[] fields = ReflectUtil.getFields(query.getClass(), field -> field.isAnnotationPresent(Condition.class));

        StringBuilder allSql = new StringBuilder();
        for (Field field : fields) {
            Class<?> fieldType = field.getType();
            Condition condition = field.getAnnotation(Condition.class);
            Object value = ReflectUtil.getFieldValue(query, field);
            if (ObjectUtil.isEmpty(value)) {
                continue;
            }
            // 检查 值是否包含关键字 不做关键字检查
//            SqlUtil.filterKeyword(String.valueOf(value));
            String name = condition.name();
            String tableName = condition.tableName();
            String[] split = name.split(",");
            Condition.ConditionType conditionType = condition.type();
            if (null != conditionType) {
                switch (conditionType) {
                    case ge -> {
                        if (StringUtils.isNotEmpty(tableName)) {
                            allSql.append(" AND ").append(tableName).append(".")
                                    .append(name).append(" $ge; ").append("'").append(value).append("'").append(" ");
                        }
                    }
                    case le -> {
                        if (StringUtils.isNotEmpty(tableName))
                            allSql.append(" AND ").append(tableName).append(".")
                                    .append(name).append(" $le; ").append("'").append(value).append("'").append(" ");
                    }
                    case gt -> {
                        if (StringUtils.isNotEmpty(tableName)) allSql.append(" AND ").append(tableName).append(".")
                                .append(name).append(" $gt; ").append("'").append(value).append("'").append(" ");
                    }
                    case lt -> {
                        if (StringUtils.isNotEmpty(tableName)) allSql.append(" AND ").append(tableName).append(".")
                                .append(name).append(" $lt; ").append("'").append(value).append("'").append(" ");
                    }
                    case isNull -> {
                        if (StringUtils.isNotEmpty(tableName)) allSql.append(" AND ").append(tableName).append(".")
                                .append(name).append(" is null ").append(" ");
                    }
                    case eq -> {
                        if (StringUtils.isNotEmpty(tableName)) {
                            if(fieldType.equals(String.class)) {
                                allSql.append(" AND ").append(tableName).append(".")
                                        .append(name).append(" = ").append("'").append(value).append("'").append(" ");
                            } else {
                                allSql.append(" AND ").append(tableName).append(".")
                                        .append(name).append(" = ").append(value).append(" ");
                            }
                        }
                    }
                    case like -> {
                        if (StringUtils.isNotEmpty(tableName)) allSql.append(" AND ").append(tableName).append(".")
                                .append(name).append(" like concat('%', ").append("'").append(value).append("'").append(", '%'").append(") ");
                    }
                    case in -> {
                        if (value instanceof Collection<?> values) {
                            if (StringUtils.isNotEmpty(tableName)) {
                                allSql.append(" AND ").append(tableName).append(".")
                                        .append(name).append(" in (");
                                for (Object o : values) {
                                    allSql.append(o).append(",");
                                }
                                if (allSql.toString().endsWith(",")) {
                                    allSql.delete(allSql.length() - 1, allSql.length());
                                }
                                allSql.append(" )").append(" ");
                            }

                        } else {
                            throw new MybatisConditionException("in 条件必须为集合");
                        }
                    }
                    case between -> {
                        if (value instanceof Collection<?>) {
                            List<?> list = Convert.toList(value);
                            if (CollUtil.size(list) == 2) {
                                if (StringUtils.isNotEmpty(tableName))
                                    allSql.append(" AND ").append(tableName).append(".")
                                            .append(name).append(" between ").append("'").append(list.get(0)).append("'").append(" AND ").append("'").append(list.get(1)).append("'").append(" ");
                            }
                        } else {
                            throw new MybatisConditionException("between 条件必须为集合");
                        }
                    }
                    case likeLeft -> {
                        if (StringUtils.isNotEmpty(tableName)) allSql.append(" AND ").append(tableName).append(".")
                                .append(name).append(" like concat('%', ").append("'").append(value).append("'").append(", '')").append(" ");
                    }
                    case dataScope -> {
                        // TODO 因为 dataScope 是在父类, 所以没有指定tableName, 此处无法获取对应的dataScopeIds
                        if (value instanceof HashMap sqlParam) {
                            // dataScope 的 拼接部门Ids
                            Object dataScope = sqlParam.get("dataScope");
                            if (ObjectUtil.isNotEmpty(dataScope) && dataScope instanceof String sql) {
                                allSql.append(sql).append(" ");
                            }
                        }
                    }
                    case or_eq -> {
                        if (StringUtils.isNotEmpty(tableName)) {
                            allSql.append(" OR ");
                            for (String key : split) {
                                allSql.append(tableName).append(".")
                                        .append(key).append(" = ").append(value).append(" AND ");
                            }
                            allSql.deleteCharAt(allSql.length() - 4);
                            if (allSql.toString().endsWith("AND ")) {
                                allSql.delete(allSql.length() - 4, allSql.length());
                            }
                            allSql.append(") ");
                        }
                    }
                    case or_like -> {
                        if (StringUtils.isNotEmpty(tableName)) {
                            allSql.append(" OR (");
                            for (String key : split) {
                                allSql.append(tableName).append(".")
                                        .append(key).append(" like concat('%', ").append(value).append(", '%'").append(" AND ");
                            }
                            if (allSql.toString().endsWith("AND ")) {
                                allSql.delete(allSql.length() - 4, allSql.length());
                            }
                            allSql.append(") ");
                        }
                    }
                    case or_likeLeft -> {
                        if (StringUtils.isNotEmpty(tableName)) {
                            allSql.append(" OR (");
                            for (String key : split) {
                                allSql.append(tableName).append(".")
                                        .append(key).append(" like concat('%', ").append(value).append(", '')").append(" AND ");
                            }
                            // 去掉末尾的 AND
                            if (allSql.toString().endsWith("AND ")) {
                                allSql.delete(allSql.length() - 4, allSql.length());
                            }
                            allSql.append(") ");
                        }
                    }
                }
            }
        }
        if (query instanceof CommonParam commonParam){
            commonParam.getSqlParam().put("sqlWhere", allSql.toString());
        }else if (query instanceof BaseEntity baseEntity){
            baseEntity.getSqlParam().put("sqlWhere", allSql.toString());
        }
    }

    public static <T> LambdaQueryWrapper<T> builder(Object query, CommonParam commonParam, String... columns)
    {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (null != columns) {
            queryWrapper = queryWrapper.select(columns);
        }
        if (null != commonParam) {
            // 构造Wrapper
            queryWrapper = queryWrapper
                    .orderBy(true, "asc".equals(commonParam.getIsAsc()), commonParam.getOrderBy());
            String groupStr = commonParam.getGroupStr();
            if (null != groupStr) {
                String[] split = groupStr.split(",");
                if (split.length > 0) {
                    queryWrapper.groupBy(Arrays.asList(split));
                }
            }
        }
        if (query == null) {
            return queryWrapper.lambda();
        }
        // 获取注解
        Field[] fields = ReflectUtil.getFields(query.getClass(), field -> field.isAnnotationPresent(Condition.class));

        if (ArrayUtil.isEmpty(fields)) {
            return queryWrapper.lambda();
        }

        for (Field field : fields) {
            Condition condition = field.getAnnotation(Condition.class);
            Object value = ReflectUtil.getFieldValue(query, field);

            if (ObjectUtil.isEmpty(value)) {
                continue;
            }
            String name = condition.name();
            String[] split = name.split(",");
            Condition.ConditionType conditionType = condition.type();
            if (null != conditionType) {
                switch (conditionType) {
                    case ge:
                        queryWrapper = queryWrapper.ge(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case le:
                        queryWrapper = queryWrapper.le(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case gt:
                        queryWrapper = queryWrapper.gt(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case lt:
                        queryWrapper = queryWrapper.lt(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case isNull:
                        queryWrapper = queryWrapper.isNull(name);
                        break;
                    case eq:
                        queryWrapper = queryWrapper.eq(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case like:
                        queryWrapper = queryWrapper.like(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case in:
                        if (value instanceof Collection<?>) {
                            queryWrapper = queryWrapper.in(ObjectUtil.isNotEmpty(value), name, (Collection) value);
                        } else {
                            throw new MybatisConditionException("in 条件必须为集合");
                        }
                        break;
                    case between:
                        if (value instanceof Collection<?>) {
                            List<?> list = Convert.toList(value);
                            if (CollUtil.size(list) == 2) {
                                queryWrapper = queryWrapper.between(name, list.get(0), list.get(1));
                            }
                        } else {
                            throw new MybatisConditionException("between 条件必须为集合");
                        }
                        break;
                    case likeLeft:
                        queryWrapper = queryWrapper.likeLeft(ObjectUtil.isNotEmpty(value), name, value);
                        break;
                    case dataScope:
                        if (value instanceof HashMap sqlParam) {
                            // dataScope 的 拼接部门Ids
                            Object dataScope = sqlParam.get("dataScopeIds");
                            if (ObjectUtil.isNotEmpty(dataScope) && dataScope instanceof Collection<?> deptIds) {
                                queryWrapper = queryWrapper.in(CollectionUtil.isNotEmpty(deptIds), name, deptIds);
                            }
                        }
                        break;
                    case or_eq:
                        queryWrapper.and(q -> {
                            for (String key : split) {
                                q.or().eq(ObjectUtil.isNotEmpty(value), key, value);
                            }
                        });
                        break;
                    case or_like:
                        queryWrapper.and(q -> {
                            for (String key : split) {
                                q.or().like(ObjectUtil.isNotEmpty(value), key, value);
                            }
                        });
                        break;
                    case or_likeLeft:
                        queryWrapper.and(q -> {
                            for (String key : split) {
                                q.or().likeLeft(ObjectUtil.isNotEmpty(value), key, value);
                            }
                        });
                        break;
                }
            }

        }
        return queryWrapper.lambda();
    }
}
