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

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.update.LambdaUpdateChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.UpdateChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.toolkit.ChainWrappers;
import com.github.yulichang.interfaces.MPJBaseJoin;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.database.mybatisplus.wrapper.LambdaQueryChainWrapperX;
import com.hys.app.framework.database.mybatisplus.wrapper.QueryChainWrapperX;
import com.hys.app.framework.util.PageConvert;
import com.hys.app.framework.database.BaseQueryParam;
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Param;

import java.util.Collection;
import java.util.List;

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

/**
 * 在 MyBatis Plus 的 BaseMapper 的基础上拓展，提供更多的能力
 *
 * 1. {@link BaseMapper} 为 MyBatis Plus 的基础接口，提供基础的 CRUD 能力
 * 2. {@link MPJBaseMapper} 为 MyBatis Plus Join 的基础接口，提供连表 Join 能力
 */
public interface BaseMapperX<T> extends MPJBaseMapper<T> {


    /**
     * 分页查询
     * @param pageParam 分页查询参数
     * @return 分页数据
     */
    default WebPage<T> selectPage(BaseQueryParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
        // 如果不分页，直接查列表
        if(pageParam.getPageSize() == PAGE_NONE){
            List<T> list = selectList(queryWrapper);
            return new WebPage<>(pageParam.getPageNo(), (long) list.size(), pageParam.getPageSize(), list);
        }
        IPage<T> mpPage = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());

        selectPage(mpPage, queryWrapper);

        return PageConvert.convert(mpPage);
    }

    default QueryChainWrapperX<T> query() {
        return new QueryChainWrapperX<>(this);
    }

    default LambdaQueryChainWrapperX<T> lambdaQuery() {
        return new LambdaQueryChainWrapperX<>(this);
    }

    default UpdateChainWrapper<T> update() {
        return ChainWrappers.updateChain(this);
    }

    default LambdaUpdateChainWrapper<T> lambdaUpdate() {
        return ChainWrappers.lambdaUpdateChain(this);
    }

    default T selectOne(String field, Object value) {
        return selectOne(new QueryWrapper<T>().eq(field, value));
    }

    default T selectOne(SFunction<T, ?> field, Object value) {
        return selectOne(new LambdaQueryWrapper<T>().eq(field, value));
    }

    default T selectOne(String field1, Object value1, String field2, Object value2) {
        return selectOne(new QueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }

    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2) {
        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2));
    }

    default T selectOne(SFunction<T, ?> field1, Object value1, SFunction<T, ?> field2, Object value2,
                        SFunction<T, ?> field3, Object value3) {
        return selectOne(new LambdaQueryWrapper<T>().eq(field1, value1).eq(field2, value2)
                .eq(field3, value3));
    }

    default Long selectCount() {
        return selectCount(new QueryWrapper<>());
    }

    default Long selectCount(String field, Object value) {
        return selectCount(new QueryWrapper<T>().eq(field, value));
    }

    default Long selectCount(SFunction<T, ?> field, Object value) {
        return selectCount(new LambdaQueryWrapper<T>().eq(field, value));
    }

    default List<T> selectList() {
        return selectList(new QueryWrapper<>());
    }

    default List<T> selectList(String field, Object value) {
        return selectList(new QueryWrapper<T>().eq(field, value));
    }

    default List<T> selectList(SFunction<T, ?> field, Object value) {
        return selectList(new LambdaQueryWrapper<T>().eq(field, value));
    }

    default List<T> selectList(String field, Collection<?> values) {
        if (CollUtil.isEmpty(values)) {
            return CollUtil.newArrayList();
        }
        return selectList(new QueryWrapper<T>().in(field, values));
    }

    default List<T> selectList(SFunction<T, ?> field, Collection<?> values) {
        if (CollUtil.isEmpty(values)) {
            return CollUtil.newArrayList();
        }
        return selectList(new LambdaQueryWrapper<T>().in(field, values));
    }

    default List<T> selectList(SFunction<T, ?> leField, SFunction<T, ?> geField, Object value) {
        return selectList(new LambdaQueryWrapper<T>().le(leField, value).ge(geField, value));
    }

    default <D> WebPage<D> selectJoinPage(BaseQueryParam pageParam, Class<D> clazz, MPJLambdaWrapper<T> lambdaWrapper) {
        // 特殊：不分页，直接查询全部
        if(pageParam.getPageSize() == PAGE_NONE){
            List<D> list = selectJoinList(clazz, lambdaWrapper);
            return new WebPage<>(pageParam.getPageNo(), (long) list.size(), pageParam.getPageSize(), list);
        }

        // MyBatis Plus Join 查询
        IPage<D> mpPage = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());
        mpPage = selectJoinPage(mpPage, clazz, lambdaWrapper);
        // 转换返回
        return PageConvert.convert(mpPage);
    }

    default <DTO> WebPage<DTO> selectJoinPage(BaseQueryParam pageParam, Class<DTO> resultTypeClass, MPJBaseJoin<T> joinQueryWrapper) {
        IPage<DTO> mpPage = new Page<>(pageParam.getPageNo(), pageParam.getPageSize());
        selectJoinPage(mpPage, resultTypeClass, joinQueryWrapper);
        // 转换返回
        return PageConvert.convert(mpPage);
    }

}
