package com.ssyf.orm.mysql.helper;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.ssyf.common.core.domain.query.SortQuery;
import com.ssyf.common.core.util.EntityUtil;
import com.ssyf.common.core.util.LambdaEnhanceUtil;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

import java.beans.PropertyDescriptor;
import java.lang.invoke.*;
import java.util.*;

/**
 * mybaits plus 帮助类
 *
 * @author huwei
 * @date 2023/1/27 9:06
 */
@Slf4j
public class MybatisPlusHelper {

    /**
     * 排序
     *
     * @param cls
     * @param queryWrapper
     * @param queryList
     * @param <T>
     */
    public static <T> void order(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, List<SortQuery> queryList) throws Exception {
        if(queryList == null || queryList.isEmpty()){
            return;
        }
        Map<String, PropertyDescriptor> nameToPropertyMap = EntityUtil.getPropertyAndChangeNameToMap(cls);
        for (SortQuery sortQuery : queryList) {
            PropertyDescriptor propertyDescriptor = nameToPropertyMap.get(sortQuery.getName());
            if (propertyDescriptor == null) {
                throw new Exception(cls.getName() + "没有属性：" + sortQuery.getName());
            }
            String methodName = wrapGetterMethodName(propertyDescriptor.getName(), propertyDescriptor.getPropertyType());
            SFunction<T, ?> sFunction = null;
            try {
                sFunction = createLambdaFunction(cls, methodName, propertyDescriptor.getPropertyType());
            } catch (Throwable t) {
                throw new Exception(cls.getName() + "没有属性" + sortQuery.getName() + "的getter方法：" + methodName);
            }
            if (sortQuery.isDesc()) {
                queryWrapper.orderByDesc(sFunction);
            } else {
                queryWrapper.orderByAsc(sFunction);
            }
        }
    }

    /**
     * 排序
     *
     * @param cls
     * @param queryWrapper
     * @param queryList
     * @param <T>
     */
    public static <T> void orderAndIgnoreError(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, List<SortQuery> queryList) {
        if(queryList == null || queryList.isEmpty()){
            return;
        }
        Map<String, PropertyDescriptor> nameToPropertyMap = EntityUtil.getPropertyAndChangeNameToMap(cls);
        for (SortQuery sortQuery : queryList) {
            PropertyDescriptor propertyDescriptor = nameToPropertyMap.get(sortQuery.getName());
            if (propertyDescriptor == null) {
                continue;
            }
            String methodName = wrapGetterMethodName(propertyDescriptor.getName(), propertyDescriptor.getPropertyType());
            SFunction<T, ?> sFunction = null;
            try {
               sFunction = createLambdaFunction(cls, methodName, propertyDescriptor.getPropertyType());
            } catch (Throwable t) {
                log.warn("创建字段Lambda引用实例失败", t);
                //ignore
            }
            if(sFunction == null){
                continue;
            }
            if (sortQuery.isDesc()) {
                queryWrapper.orderByDesc(sFunction);
            } else {
                queryWrapper.orderByAsc(sFunction);
            }
        }
    }

    /**
     * 创建LambdaQueryWrapper实例并通过关联关系匹配数据
     * 未设置关联关系的查询参数使用默认的匹配关系：automaticMatching
     * @param cls
     * @param query
     * @param relations
     * @param <T>
     * @return
     */
    public static <T> LambdaQueryWrapper<T> createAndAutomaticRelationOrDefault(Class<T> cls, Object query, WrapperRelation<T,?> ...relations) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
        automaticRelationOrDefault(cls, queryWrapper, query, relations);
        return queryWrapper;
    }

    /**
     * 创建LambdaQueryWrapper实例并通过关联关系匹配数据
     * 未设置关联关系的查询参数使用默认的匹配关系：automaticMatching
     * @param cls
     * @param query
     * @param relations
     * @param <T>
     * @return
     */
    public static <T> LambdaQueryWrapper<T> createAndAutomaticRelationOrDefault(Class<T> cls, Object query, WrapperRelation<T,?>[] relations ,SFunction<T, ?> ...ignores) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
        automaticRelationOrDefault(cls, queryWrapper, query, relations ,ignores);
        return queryWrapper;
    }

    /**
     * 创建LambdaQueryWrapper实例并通过关联关系匹配数据
     * 未设置关联关系的查询参数使用默认的匹配关系：automaticMatching
     * @param cls
     * @param queryWrapper
     * @param query
     * @param relations
     * @param <T>
     */
    public static <T> void automaticRelationOrDefault(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, WrapperRelation<T,?> ...relations) {
        automaticRelationOrDefault(cls, queryWrapper, query, relations, new SFunction[]{});
    }

    /**
     * 创建LambdaQueryWrapper实例并通过关联关系匹配数据
     * 未设置关联关系的查询参数使用默认的匹配关系：automaticMatching
     * @param cls
     * @param queryWrapper
     * @param query
     * @param relations
     * @param ignoreProperties
     * @param <T>
     */
    public static <T> void automaticRelationOrDefault(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, WrapperRelation<T,?>[] relations ,SFunction<T, ?> ...ignoreProperties) {
        Map<String, PropertyDescriptor> instancePropertyNameToPropertyMap = EntityUtil.getPropertyAndChangeNameToMap(cls);
        PropertyDescriptor[] propertyDescriptors = BeanUtil.getPropertyDescriptors(query.getClass());
        Map<String,WrapperRelation<T,?>> propertyNameToRelationMap = new HashMap<>();
        for(WrapperRelation<T,?> relation : relations){
            propertyNameToRelationMap.put(relation.getQueryPropertyName() ,relation);
        }
        List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
        for(PropertyDescriptor propertyDescriptor : propertyDescriptors){
            String propertyName = propertyDescriptor.getName();
            WrapperRelation<T,?> relation = propertyNameToRelationMap.get(propertyName);
            if(relation == null){
                PropertyDescriptor instanceProperty = instancePropertyNameToPropertyMap.get(propertyName);
                if (instanceProperty == null || !instanceProperty.getPropertyType().isAssignableFrom(propertyDescriptor.getPropertyType())) {
                    //没有关联关系，也没有实例查询对象的关系或则字段类型不匹配
                    continue;
                }
                String methodName = wrapGetterMethodName(propertyName ,propertyDescriptor.getPropertyType());
                try{
                    SFunction<T ,?> sFunction = createLambdaFunction(cls ,methodName,propertyDescriptor.getPropertyType());
                    relation = new WrapperRelation(sFunction);
                }catch (Throwable t){
                    log.warn("创建字段Lambda引用实例失败", t);
                    //ignore
                    continue;
                }
            }
            if (!instancePropertyNameToPropertyMap.containsKey(relation.getInstancePropertyName())) {
                continue;
            }
            //忽略
            if (ignorePropertyList.contains(relation.getInstancePropertyName())){
                continue;
            }

            Object fieldValue = BeanUtil.getFieldValue(query, relation.getQueryPropertyName());
            if (fieldValue == null || (String.class.isAssignableFrom(fieldValue.getClass()) && StrUtil.isBlank(fieldValue.toString()))) {
                continue;
            }
            switch (relation.getMatcher()) {
                case eq:
                    queryWrapper.eq(relation.getInstanceProperty(), fieldValue);
                    break;
                case ne:
                    queryWrapper.ne(relation.getInstanceProperty(), fieldValue);
                    break;
                case le:
                    queryWrapper.le(relation.getInstanceProperty(), fieldValue);
                    break;
                case ge:
                    queryWrapper.ge(relation.getInstanceProperty(), fieldValue);
                    break;
                case in:
                    queryWrapper.in(relation.getInstanceProperty(), fieldValue);
                    break;
                case notIn:
                    queryWrapper.notIn(relation.getInstanceProperty(), fieldValue);
                    break;
                case like:
                    queryWrapper.like(relation.getInstanceProperty(), fieldValue);
                    break;
                case likeRight:
                    queryWrapper.like(relation.getInstanceProperty(), fieldValue);
                    break;
                case likeLeft:
                    queryWrapper.likeLeft(relation.getInstanceProperty(), fieldValue);
                    break;
                default:
                    break;
            }
        }
    }

    /**
     * 创建LambdaQueryWrapper实例并自动适配比对查询参数
     *
     * @param cls
     * @param query
     * @param <T>
     * @return
     */
    public static <T> LambdaQueryWrapper<T> createAndAutomaticMatching(Class<T> cls, Object query) {
        return createAndAutomaticMatchingIncloude(cls, query);
    }

    /**
     * 创建LambdaQueryWrapper实例并自动适配比对查询参数
     * 处理指定字段，若未指定则处理query参数的所有字段
     *
     * @param cls
     * @param query
     * @param incloudeProperties
     * @param <T>
     * @return
     */
    public static <T> LambdaQueryWrapper<T> createAndAutomaticMatchingIncloude(Class<T> cls, Object query, SFunction<T, ?> ...incloudeProperties) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
        automaticMatchingIncloude(cls, queryWrapper, query, incloudeProperties);
        return queryWrapper;
    }

    /**
     * 创建LambdaQueryWrapper实例并自动适配比对查询参数
     * 排除指定字段，若未指定则处理query参数的所有字段
     *
     * @param cls
     * @param query
     * @param ignoreProperties
     * @param <T>
     * @return
     */
    public static <T> LambdaQueryWrapper<T> createAndAutomaticMatchingIgnore(Class<T> cls, Object query, SFunction<T, ?> ...ignoreProperties) {
        LambdaQueryWrapper<T> queryWrapper = new LambdaQueryWrapper<>();
        automaticMatchingIgnore(cls, queryWrapper, query, ignoreProperties);
        return queryWrapper;
    }

    /**
     * 自动匹配条件规则，当前只提供2种方式，in 和 eq
     *
     * @param queryWrapper
     * @param methodSFunction
     * @param methodValue
     * @param methodReturnTypeClass
     * @param <T>
     */
    public static <T> void automaticMatching(LambdaQueryWrapper<T> queryWrapper, SFunction<T, ?> methodSFunction, Object methodValue, Class<?> methodReturnTypeClass) {
        if (Collection.class.isAssignableFrom(methodReturnTypeClass) || methodReturnTypeClass.isArray()) {
            queryWrapper.in(methodSFunction, methodValue);
        } else {
            queryWrapper.eq(methodSFunction, methodValue);
        }
    }

    public static <T> void automaticMatching(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        automaticMatchingIncloude(cls, queryWrapper, query);
    }

    public static <T> void automaticMatchingIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            automaticMatching(queryWrapperBo.getQueryWrapper(), queryWrapperBo.getPropertySFunction()
                    , queryWrapperBo.getPropertyValue(), queryWrapperBo.getPropertyTypeClass());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void automaticMatchingIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            automaticMatchingIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                automaticMatching(queryWrapperBo.getQueryWrapper(), queryWrapperBo.getPropertySFunction()
                        , queryWrapperBo.getPropertyValue(), queryWrapperBo.getPropertyTypeClass());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void eq(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        eqIncloude(cls, queryWrapper, query);
    }

    public static <T> void eqIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.eq(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void eqIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            eqIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.eq(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void ne(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        neIncloude(cls, queryWrapper, query);
    }

    public static <T> void neIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.ne(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void neIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            neIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.ne(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void le(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        leIncloude(cls, queryWrapper, query);
    }

    public static <T> void leIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.le(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void leIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            leIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.le(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void ge(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        geIncloude(cls, queryWrapper, query);
    }

    public static <T> void geIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.ge(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void geIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            geIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.ge(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void in(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        inIncloude(cls, queryWrapper, query);
    }

    public static <T> void inIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.in(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void inIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            inIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.in(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void notIn(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        notInIncloude(cls, queryWrapper, query);
    }

    public static <T> void notInIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.notIn(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void notInIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            notInIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.notIn(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void like(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        likeIncloude(cls, queryWrapper, query);
    }

    public static <T> void likeIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.like(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void likeIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            likeIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.like(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void likeRight(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        likeRightIncloude(cls, queryWrapper, query);
    }

    public static <T> void likeRightIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.like(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void likeRightIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            likeRightIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.like(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    public static <T> void likeLeft(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query) {
        likeLeftIncloude(cls, queryWrapper, query);
    }

    public static <T> void likeLeftIncloude(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...incloudeProperties) {
        List<String> includePropertyList = LambdaEnhanceUtil.getFieldNameList(incloudeProperties);
        queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
            queryWrapper.likeLeft(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
            return true;
        }, (propertyName) -> {
            return !includePropertyList.isEmpty() && !includePropertyList.contains(propertyName);
        });
    }

    public static <T> void likeLeftIgnore(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query, SFunction<T, ?> ...ignoreProperties) {
        if (ignoreProperties.length == 0) {
            likeLeftIncloude(cls, queryWrapper, query);
        } else {
            List<String> ignorePropertyList = LambdaEnhanceUtil.getFieldNameList(ignoreProperties);
            queryWrapper(cls, queryWrapper, query, (queryWrapperBo) -> {
                queryWrapper.likeLeft(queryWrapperBo.getPropertySFunction(), queryWrapperBo.getPropertyValue());
                return true;
            }, (propertyName) -> {
                return ignorePropertyList.contains(propertyName);
            });

        }
    }

    /**
     * 动态创建对象方法的Lambda引用实例
     *
     * @param tClass                           对象类
     * @param targetMethodName                 方法名
     * @param targetMethodReturnTypeClass      方法返回类型，可为空，则默认为void.class类
     * @param targetMethodParameterTypeClasses 方法参数类型
     * @param <T>
     * @return
     * @throws Throwable
     */
    public static <T> SFunction<T, ?> createLambdaFunction(Class<T> tClass, String targetMethodName
            , Class<?> targetMethodReturnTypeClass, Class<?>... targetMethodParameterTypeClasses) throws Throwable {
        final Class<?> sFunctionClass = SFunction.class;
        final MethodType sFunctionType = MethodType.methodType(sFunctionClass);
        //初始
        Class<?> methodReturnTypeClass = targetMethodReturnTypeClass == null ? void.class : targetMethodReturnTypeClass;
        MethodType methodReturnType, methodRelationInstanceType;
        if (targetMethodParameterTypeClasses.length == 0) {
            methodReturnType = MethodType.methodType(methodReturnTypeClass);
            methodRelationInstanceType = MethodType.methodType(methodReturnTypeClass, tClass);
        } else {
            methodReturnType = MethodType.methodType(methodReturnTypeClass, targetMethodParameterTypeClasses);
            methodRelationInstanceType = MethodType.methodType(methodReturnTypeClass, tClass, targetMethodParameterTypeClasses);
        }
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        MethodHandle targetMethodHandle = lookup.findVirtual(tClass, targetMethodName, methodReturnType);
        CallSite callSite = LambdaMetafactory
                .altMetafactory(lookup, "apply", sFunctionType
                        , targetMethodHandle.type().generic()
                        , targetMethodHandle
                        , methodRelationInstanceType
                        , LambdaMetafactory.FLAG_SERIALIZABLE);

        return (SFunction<T, ?>) callSite.dynamicInvoker().invoke();
    }

    /**
     * @param cls
     * @param queryWrapper
     * @param query
     * @param queryWrapperCall
     * @param propertyFilter   字段过滤，true 不操作该字段，false 操作该字段
     * @param <T>
     */
    private static <T> void queryWrapper(Class<T> cls, LambdaQueryWrapper<T> queryWrapper, Object query
            , Callback<Boolean, QueryWrapperBo<T>> queryWrapperCall, Callback<Boolean, String> propertyFilter) {
        Map<String, PropertyDescriptor> nameToPropertyMap = EntityUtil.getPropertyAndChangeNameToMap(cls);
        PropertyDescriptor[] propertyDescriptors = BeanUtil.getPropertyDescriptors(query.getClass());
        try {
            for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
                //回调：自定义过滤
                if (propertyFilter != null && propertyFilter.call(propertyDescriptor.getName())) {
                    continue;
                }
                PropertyDescriptor instancePropertyDescriptor = nameToPropertyMap.get(propertyDescriptor.getName());
                if (instancePropertyDescriptor == null || !propertyDescriptor.getPropertyType().isAssignableFrom(instancePropertyDescriptor.getPropertyType())) {
                    //目标查询类没有当前属性
                    continue;
                }
                Object fieldValue = BeanUtil.getFieldValue(query, propertyDescriptor.getName());
                //空或空串
                if (fieldValue == null || (String.class.isAssignableFrom(fieldValue.getClass()) && StrUtil.isBlank(fieldValue.toString()))) {
                    //值为空，跳过
                    continue;
                }
                String methodName = wrapGetterMethodName(propertyDescriptor.getName(), propertyDescriptor.getPropertyType());
                SFunction<T, ?> sFunction = createLambdaFunction(cls, methodName, propertyDescriptor.getPropertyType());

                //回调：条件封装
                queryWrapperCall.call(new QueryWrapperBo<T>().setQueryWrapper(queryWrapper)
                        .setPropertySFunction(sFunction).setPropertyValue(fieldValue)
                        .setPropertyTypeClass(propertyDescriptor.getPropertyType()));
            }
        } catch (Throwable t) {
            log.warn("创建字段Lambda引用实例失败", t);
            //ignore
        }
    }

    private static String wrapGetterMethodName(String propertyName, Class<?> propertyClass) {
        String t = propertyName.replaceFirst(propertyName.charAt(0) + "", (propertyName.charAt(0) + "").toUpperCase());
        if (Boolean.class.isAssignableFrom(propertyClass) || boolean.class.isAssignableFrom(propertyClass)) {
            return "is" + t;
        }
        return "get" + t;
    }
    

    /**
     * 回调
     *
     * @author huwei
     * @date 2023/1/27 13:40
     */
    interface Callback<R, P> {
        R call(P p);
    }

    @Data
    @Accessors(chain = true)
    static class QueryWrapperBo<T> {
        LambdaQueryWrapper<T> queryWrapper;
        SFunction<T, ?> propertySFunction;
        Object propertyValue;
        Class<?> propertyTypeClass;
    }

    /**
     * 匹配关系枚举
     */
    public enum MatcherEnum {
        eq, ne, le, ge, in, notIn, like, likeRight, likeLeft;
    }

    @Data
    @Accessors(chain = true)
    public static class WrapperRelation<T,Q> {
        /**
         * 实例参数字段名lambda引用实例
         */
        private SFunction<T, ?> instanceProperty;

        private String instancePropertyName;

        private String queryPropertyName;
        /**
         * 匹配关系
         */
        private MatcherEnum matcher;

        public WrapperRelation(SFunction<T, ?> instanceProperty) {
            this(instanceProperty , MatcherEnum.eq);
        }

        public WrapperRelation(SFunction<T, ?> instanceProperty, MatcherEnum matcher) {
            this.instanceProperty = instanceProperty;
            this.matcher = matcher;
            this.instancePropertyName = LambdaEnhanceUtil.getFieldName(instanceProperty);
            this.queryPropertyName = this.instancePropertyName;
        }

        public WrapperRelation(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this(instanceProperty, queryProperty, MatcherEnum.eq);
        }

        public WrapperRelation(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty, MatcherEnum matcher) {
            this.instanceProperty = instanceProperty;
            this.matcher = matcher;
            this.instancePropertyName = LambdaEnhanceUtil.getFieldName(instanceProperty);
            this.queryPropertyName = LambdaEnhanceUtil.getFieldName(queryProperty);
        }
    }

    /**
     * 关系构建类
     *
     * @param <T>
     */
    public static class WrapperRelationBuilder<T ,Q> {
        List<WrapperRelation<T,Q>> relationList = new ArrayList<>();

        public static <T,Q> WrapperRelationBuilder<T,Q> create() {
            return new WrapperRelationBuilder();
        }

        public static <T,Q> WrapperRelationBuilder<T,Q> create(Class<T> cls ,Class<Q> queryClass) {
            return new WrapperRelationBuilder();
        }

        public WrapperRelation<T,Q>[] buildArray() {
            WrapperRelation<T,Q>[] result = new WrapperRelation[this.relationList.size()];
            this.relationList.toArray(result);
            return result;
        }

        public WrapperRelationBuilder<T,Q> eq(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty));
            return this;
        }

        public WrapperRelationBuilder<T,Q> eq(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty));
            return this;
        }

        public WrapperRelationBuilder<T,Q> ne(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.ne));
            return this;
        }

        public WrapperRelationBuilder<T,Q> ne(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.ne));
            return this;
        }

        public WrapperRelationBuilder<T,Q> le(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.le));
            return this;
        }

        public WrapperRelationBuilder<T,Q> le(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.le));
            return this;
        }

        public WrapperRelationBuilder<T,Q> ge(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.ge));
            return this;
        }

        public WrapperRelationBuilder<T,Q> ge(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.ge));
            return this;
        }

        public WrapperRelationBuilder<T,Q> in(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.in));
            return this;
        }

        public WrapperRelationBuilder<T,Q> in(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.in));
            return this;
        }

        public WrapperRelationBuilder<T,Q> notIn(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.notIn));
            return this;
        }

        public WrapperRelationBuilder<T,Q> notIn(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.notIn));
            return this;
        }

        public WrapperRelationBuilder<T,Q> like(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.like));
            return this;
        }

        public WrapperRelationBuilder<T,Q> like(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.like));
            return this;
        }

        public WrapperRelationBuilder<T,Q> likeRight(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.likeRight));
            return this;
        }

        public WrapperRelationBuilder<T,Q> likeRight(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.likeRight));
            return this;
        }

        public WrapperRelationBuilder<T,Q> likeLeft(SFunction<T, ?> instanceProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, MatcherEnum.likeLeft));
            return this;
        }

        public WrapperRelationBuilder<T,Q> likeLeft(SFunction<T, ?> instanceProperty, SFunction<Q, ?> queryProperty) {
            this.relationList.add(new WrapperRelation<T,Q>(instanceProperty, queryProperty, MatcherEnum.likeLeft));
            return this;
        }
    }
}
