package com.hys.app.framework.database.mybatisplus.wrapper;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.util.PageConvert;
import com.hys.app.framework.database.BaseQueryParam;
import com.hys.app.framework.util.ArrayUtils;
import org.springframework.util.StringUtils;

import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;

import static com.hys.app.framework.database.BaseQueryParam.PAGE_NONE;

/**
 * 拓展 MyBatis Plus LambdaQueryChainWrapper 类，主要增加如下功能：
 * <p>
 * 1. 拼接条件的方法，增加 xxxIfPresent 方法，用于判断值不存在的时候，不要拼接到条件中。
 *
 * @param <T> 数据类型
 *
 * @author 张崧
 * @since 2023-11-28
 */
public class LambdaQueryChainWrapperX<T> extends LambdaQueryChainWrapper<T> {

    public LambdaQueryChainWrapperX(BaseMapper<T> baseMapper) {
        super(baseMapper);
    }

    public LambdaQueryChainWrapperX<T> likeIfPresent(SFunction<T, ?> column, String val) {
        if (StringUtils.hasText(val)) {
            return (LambdaQueryChainWrapperX<T>) super.like(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> inIfPresent(SFunction<T, ?> column, Collection<?> values) {
        if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
            return (LambdaQueryChainWrapperX<T>) super.in(column, values);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> inIfPresent(SFunction<T, ?> column, Object... values) {
        if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
            return (LambdaQueryChainWrapperX<T>) super.in(column, values);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> eqIfPresent(SFunction<T, ?> column, Object val) {
        if (ObjectUtil.isNotEmpty(val)) {
            return (LambdaQueryChainWrapperX<T>) super.eq(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> neIfPresent(SFunction<T, ?> column, Object val) {
        if (ObjectUtil.isNotEmpty(val)) {
            return (LambdaQueryChainWrapperX<T>) super.ne(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> gtIfPresent(SFunction<T, ?> column, Object val) {
        if (val != null) {
            return (LambdaQueryChainWrapperX<T>) super.gt(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> geIfPresent(SFunction<T, ?> column, Object val) {
        if (val != null) {
            return (LambdaQueryChainWrapperX<T>) super.ge(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> ltIfPresent(SFunction<T, ?> column, Object val) {
        if (val != null) {
            return (LambdaQueryChainWrapperX<T>) super.lt(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> leIfPresent(SFunction<T, ?> column, Object val) {
        if (val != null) {
            return (LambdaQueryChainWrapperX<T>) super.le(column, val);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object val1, Object val2) {
        if (val1 != null && val2 != null) {
            return (LambdaQueryChainWrapperX<T>) super.between(column, val1, val2);
        }
        if (val1 != null) {
            return (LambdaQueryChainWrapperX<T>) ge(column, val1);
        }
        if (val2 != null) {
            return (LambdaQueryChainWrapperX<T>) le(column, val2);
        }
        return this;
    }

    public LambdaQueryChainWrapperX<T> betweenIfPresent(SFunction<T, ?> column, Object[] values) {
        Object val1 = ArrayUtils.get(values, 0);
        Object val2 = ArrayUtils.get(values, 1);
        return betweenIfPresent(column, val1, val2);
    }

    public LambdaQueryChainWrapperX<T> andX(boolean condition, Consumer<LambdaQueryWrapper<T>> consumer) {
        this.getWrapper().and(condition, consumer);
        return this;
    }

    // ========== 重写父类方法，方便链式调用 ==========

    @Override
    public LambdaQueryChainWrapperX<T> eq(boolean condition, SFunction<T, ?> column, Object val) {
        super.eq(condition, column, val);
        return this;
    }

    @Override
    public LambdaQueryChainWrapperX<T> eq(SFunction<T, ?> column, Object val) {
        super.eq(column, val);
        return this;
    }

    @Override
    public LambdaQueryChainWrapperX<T> orderByDesc(SFunction<T, ?> column) {
        super.orderByDesc(true, column);
        return this;
    }

    @Override
    public LambdaQueryChainWrapperX<T> orderByAsc(SFunction<T, ?> column) {
        super.orderByAsc(true, column);
        return this;
    }

    @Override
    public LambdaQueryChainWrapperX<T> last(String lastSql) {
        super.last(lastSql);
        return this;
    }

    @Override
    public LambdaQueryChainWrapperX<T> in(SFunction<T, ?> column, Collection<?> coll) {
        super.in(column, coll);
        return this;
    }

    /**
     * 分页查询
     * @param pageParam 分页查询参数
     * @return 分页数据
     */
    public WebPage<T> page(BaseQueryParam pageParam) {
        // 如果不分页，直接查列表
        if(pageParam.getPageSize() == PAGE_NONE){
            List<T> list = list();
            return new WebPage<>(pageParam.getPageNo(), (long) list.size(), pageParam.getPageSize(), list);
        }

        IPage<T> mpPage = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());
        super.page(mpPage);
        return PageConvert.convert(mpPage);
    }
}
