package cn.iocoder.yudao.framework.common.base;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.CodeException;
import cn.iocoder.yudao.framework.common.model.PageQuery;
import cn.iocoder.yudao.framework.common.util.page.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 功能描述: 基于通用MyBatis Mapper插件的Service接口的实现
 * <p>
 * 作者: July
 * 日期: 2020-09-16 18:58
 * @author Administrator
 */
@Component
@Transactional(rollbackFor = Exception.class)
public abstract class AbstractService<M extends BaseMapper<T>, T> implements IService<T> {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    @SuppressWarnings("all")
    protected M mapper;

    /**
     * 保存一个实体，null的属性也会保存，不会使用数据库默认值
     */
    @Override
    public int save(T entity) {
        return mapper.insert(entity);
    }

    /**
     * 批量插入，支持批量插入的数据库可以使用，例如MySQL,H2等，另外该接口限制实体包含`id`属性并且必须为自增列
     */
    @Override
    public int save(List<T> list) {
        return batchSave(list);
    }

    /**
     * 批量插入，支持批量插入的数据库可以使用，例如MySQL,H2等，另外该接口限制实体包含`id`属性并且必须为自增列
     */
    @Override
    public int batchSave(List<T> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        return mapper.insertList(list);
    }

    /**
     * 保存一个实体，null的属性不会保存，会使用数据库默认值
     */
    @Override
    public int saveNotNull(T entity) {
        // 修复多次更新数据后由于 Version 没有改变导致更新无效的问题
       if (entity instanceof BaseRowEntity) {
            ((BaseRowEntity) entity).setCreatedAt(new Date());
            ((BaseRowEntity) entity).setUpdatedAt(new Date());
        }
        return mapper.insertSelective(entity);
    }

    /**
     * 根据主键字段进行删除，方法参数必须包含完整的主键属性
     */
    @Override
    public int deleteByKey(Object key) {
        return mapper.deleteByPrimaryKey(key);
    }

    /**
     * 根据主键字符串进行删除，类中只有存在一个带有@Id注解的字段
     * @param ids 如 "1,2,3,4"
     */
    @Override
    public int deleteByIds(String ids) {
        return mapper.deleteByIds(ids);
    }

    @Override
    public int deleteByIds(Object[] ids) {
        if (ids == null || ids.length == 0) {
            return 0;
        }
        return mapper.deleteByIds(StrUtil.join(",", ids));
    }

    /**
     * 根据主键更新实体全部字段，null值会被更新
     */
    @Override
    public int update(T entity) {
        int result = mapper.updateByPrimaryKey(entity);
        if (result <= 0) { throw new CodeException("更新记录异常"); }
        else if (entity instanceof BaseFullEntity) {
            ((BaseFullEntity) entity).updateVersion();
        }
        return result;
    }

    @Override
    public Long clean(Integer month) {
        if(null == month || 0 >= month) {
            mapper.truncate(); return 0L;
        }
        return mapper.clean(month);
    }

    /**
     * 根据主键更新属性不为null的值
     */
    @Override
    public int updateNotNull(T entity) {
        // 修复多次更新数据后由于 Version 没有改变导致更新无效的问题
        if (entity instanceof BaseRowEntity) {
            ((BaseRowEntity) entity).setUpdatedAt(new Date());
        }
        int result = mapper.updateByPrimaryKeySelective(entity);
        if (result <= 0) { throw new CodeException("更新记录异常"); }
        // 修复多次更新数据后由于 Version 没有改变导致更新无效的问题
        if (entity instanceof BaseFullEntity) {
            ((BaseFullEntity) entity).updateVersion();
        }
        return result;
    }

    /**
     * 批量 根据主键更新属性不为null的值
     */
    @Override
    public int batchUpdate(List<T> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        int updateCount = 0;
        for (T item : list) {
            updateCount += updateNotNull(item);
        }
        return updateCount;
    }

    /**
     * 批量更新部分信息 Mapper 需要自己实现
     */
    @Override
    public int batch(List<T> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        int maxSize = list.size();
        int pageSize = 1000;
        int loopNum = maxSize / pageSize + ((maxSize % pageSize == 0) ? 0 : 1);
        int updateNum = 0;
        for (int i = 0; i < loopNum; i++) {
            int fromIndex = i * pageSize;
            int toIndex = (i + 1) * pageSize;
            if (toIndex > maxSize) {
                toIndex = maxSize;
            }
            updateNum += mapper.batch(list.subList(fromIndex, toIndex));
        }
        return updateNum;
    }

    /**
     * 根据主键字段进行查询，方法参数必须包含完整的主键属性，查询条件使用等号
     */
    @Override
    @Transactional(readOnly = true)
    public T selectByKey(Object key) {
        return mapper.selectByPrimaryKey(key);
    }

    /**
     * 查询所有
     */
    @Override
    @Transactional(readOnly = true)
    public List<T> selectAll() {
        return mapper.selectAll();
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> select(T entity) {return mapper.select(entity);}

    @Override
    @Transactional(readOnly = true)
    public T selectOne(T entity) {return mapper.selectOne(entity);}

    @Override
    @Transactional(readOnly = true)
    public T selectOneByExample(T entity) {return mapper.selectOneByExample(entity);}

    /**
     * 根据主键字符串进行查询，类中只有存在一个带有@Id注解的字段
     * @param ids 如 "1,2,3,4"
     */
    @Override
    @Transactional(readOnly = true)
    public List<T> selectByIds(String ids) {
        return mapper.selectByIds(ids);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> selectByIds(Object[] ids) {
        if (ids == null || ids.length == 0) {
            return Collections.emptyList();
        }
        return mapper.selectByIds(StrUtil.join(",", ids));
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> selectByIds(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyList();
        }
        int maxSize = ids.size();
        int pageSize = 1000;
        int loopNum = maxSize / pageSize + ((maxSize % pageSize == 0) ? 0 : 1);
        List<T> results = new ArrayList<>();
        List<Long> nowIds;
        for (int i = 0; i < loopNum; i++) {
            int fromIndex = i * pageSize;
            int toIndex = (i + 1) * pageSize;
            if (toIndex > maxSize) {
                toIndex = maxSize;
            }
            nowIds = ids.subList(fromIndex, toIndex);
            results.addAll(selectByIds(nowIds.toArray()));
        }
        return results;
    }

    /**
     * 根据Example条件进行查询
     */
    @Override
    @Transactional(readOnly = true)
    public List<T> selectByExample(Object example) {
        return mapper.selectByExample(example);
    }

    /**
     * 根据Example条件删除数据
     */
    @Override
    public int deleteByExample(Object example) {
        return mapper.deleteByExample(example);
    }

    @Override
    @Transactional(readOnly = true)
    public PageHelper<T> queryPageList(Map<String, Object> params) {
        return queryPageList(params, null);
    }

    @Override
    @Transactional(readOnly = true)
    public PageHelper<T> queryPageList(Map<String, Object> params, String alias) {
        return PageHelper.of(pager(params, alias, Boolean.TRUE));
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> queryPage(Map<String, Object> params) {
        return mapper.queryPage(params);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> pageList(Map<String, Object> params) {
        return pageList(params, null);
    }

    @Override
    @Transactional(readOnly = true)
    public List<T> pageList(Map<String, Object> params, String alias) {
        return pager(params, alias, Boolean.FALSE).getList();
    }

    /****
     * 分页
     * @param params
     * @param alias
     * @param counted
     * @return
     */
    private PageInfo<T> pager(Map<String, Object> params, String alias, boolean counted) {
        // 前置参数校检
        handlePageParam(params);

        // 参数封装
        PageQuery query = new PageQuery(params);

        // 排序字段
        StringBuilder sb = new StringBuilder();
        if (StrUtil.isNotBlank(alias)) {
            sb.append(alias);
            sb.append(".");
        }
        sb.append(StrUtil.isBlank(query.getBy()) ? "id DESC" : query.getBy());

        // 进行分页查询请求
        PageInfo<T> pager = com.github.pagehelper.PageHelper
                .startPage(query.getPage(), query.getRows(), counted)
                .setOrderBy(sb.toString().trim())
                .doSelectPageInfo(() -> queryPage(query));

        // 返回的数据列表
        List<T> list = pager.getList();

        // 处理列表返回的数据
        if (list != null && !list.isEmpty()) {
            handlePageData(list);
        }

        return pager;
    }

    /**
     * 处理分页查询参数
     */
    @Override
    public void handlePageParam(Map<String, Object> params) {}

    /**
     * 处理分页查询返回的数据
     */
    @Override
    public void handlePageData(List<T> list) {}
}
