package com.jy.framework.model.base;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jy.framework.mybatis.join.DefaultFunction;
import com.jy.framework.mybatis.join.Sql;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@SuppressWarnings({"unused", "unchecked", "UnusedReturnValue"})
public class BaseDao<M extends BaseMapper<T>, T extends BaseIdPo> extends ServiceImpl<M, T> implements DefaultFunction {

    public Sql<JSONObject> sql() {
        return Sql.create();
    }

    public <S> Sql<S> sql(Class<S> clazz) {
        return Sql.create(clazz);
    }

    public <K> List<K> fieldList(SFunction<T, K> mapper, Consumer<LambdaQueryWrapper<T>> consumer) {
        List<T> list = list(Wrappers.<T>lambdaQuery().select(mapper).func(ObjectUtil.isNotEmpty(consumer), consumer));
        return list.stream().map(mapper).filter(ObjectUtil::isNotEmpty).toList();
    }

    public <K> Set<K> fieldSet(SFunction<T, K> mapper, Consumer<LambdaQueryWrapper<T>> consumer) {
        List<T> list = list(Wrappers.<T>lambdaQuery().select(mapper).func(ObjectUtil.isNotEmpty(consumer), consumer));
        return list.stream().map(mapper).filter(ObjectUtil::isNotEmpty).collect(Collectors.toSet());
    }

    public boolean exists(Consumer<LambdaQueryWrapper<T>> consumer) {
        return exists(Wrappers.<T>lambdaQuery().func(ObjectUtil.isNotEmpty(consumer), consumer).last("limit 1"));
    }

    public long count(Consumer<LambdaQueryWrapper<T>> consumer) {
        return count(Wrappers.<T>lambdaQuery().func(ObjectUtil.isNotEmpty(consumer), consumer));
    }

    public T getOne(Consumer<LambdaQueryWrapper<T>> consumer) {
        return getOne(Wrappers.<T>lambdaQuery().func(ObjectUtil.isNotEmpty(consumer), consumer).last("limit 1"));
    }

    public List<T> list(Consumer<LambdaQueryWrapper<T>> consumer) {
        return list(Wrappers.<T>lambdaQuery().func(ObjectUtil.isNotEmpty(consumer), consumer));
    }

    public boolean update(Consumer<LambdaUpdateWrapper<T>> consumer) {
        return update(Wrappers.<T>lambdaUpdate().func(ObjectUtil.isNotEmpty(consumer), consumer));
    }

    public boolean update(T entity, Consumer<LambdaUpdateWrapper<T>> consumer) {
        return update(entity, Wrappers.<T>lambdaUpdate().func(ObjectUtil.isNotEmpty(consumer), consumer));
    }

    public boolean remove(Consumer<LambdaQueryWrapper<T>> consumer) {
        return remove(Wrappers.<T>lambdaQuery().func(ObjectUtil.isNotEmpty(consumer), consumer));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean saveBatchEx(Collection<? extends T> entityList) {
        return saveBatch((List<T>) entityList);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchByIdEx(Collection<? extends T> entityList) {
        return updateBatchById((List<T>) entityList);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateBatchEx(Collection<? extends T> entityList) {
        return saveOrUpdateBatch((List<T>) entityList);
    }

    /**
     * 编辑关联表
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateLinked(List<? extends T> list, SFunction<T, Long> getMasterIdFun, Long masterId) {
        List<Long> idList = list.stream().map(BaseIdPo::getId).filter(Objects::nonNull).toList();
        remove(q -> q.eq(getMasterIdFun, masterId).notIn(ObjectUtil.isNotEmpty(idList), BaseIdPo::getId, idList));
        saveOrUpdateBatchEx(list);
    }

}
