package com.fs.common.utils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fs.common.core.domain.BaseEntityTow;
import com.fs.common.exception.base.BaseException;
import com.fs.common.utils.date.DateUtil;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.util.stream.Collectors.*;

public class PubFun {

    /**
     * @Description 把实体转换为map
     * @author 吴树波
     * @date 2020/4/16 14:07
     * @param t 实体
     * @return java.lang.String
     */
    public static <T> Map<String, Object> objectToMap(T t, String attr){
        List<String> attrList = Arrays.asList(attr.split(","));
        // 获取所有属性并组装为map
        return objectToMap(t, e -> attrList.contains(e.getName().trim()), false, false);
    }
    public static <T> List<Map<String, Object>> objectToMap(List<T> t, String attr){
        List<String> attrList = Arrays.asList(attr.split(","));
        // 获取所有属性并组装为map
        return t.stream().map(c -> objectToMap(c, e -> attrList.contains(e.getName().trim()), false, false)).collect(Collectors.toList());
    }
    /**
     * @Description 把实体转换为map
     * @author 吴树波
     * @date 2020/4/16 14:07
     * @param t 实体
     * @return java.lang.String
     */
    public static <T> Map<String, Object> objectToMap(T t){
        // 获取所有属性并组装为map
        return objectToMap(t, e -> true, false, false);
    }
    public static <T> List<Map<String, Object>> objectToMap(List<T> t){
        // 获取所有属性并组装为map
        return t.stream().map(e -> objectToMap(e, c -> true, false, false)).collect(Collectors.toList());
    }
    /**
     * 对金额进行三位数的拆分
     * @author 吴树波
     * @date 2020/12/15 15:46
     * @param s 字符串
     * @return java.lang.String
     */
    public static String splitMoney(String s){
        return splitMoney(s, 3, ",");
    }
    /**
     * 对字符串进行翻转
     * @author 吴树波
     * @date 2020/12/15 15:32
     * @param s 字符串
     * @return java.lang.String
     */
    public static String reverse(String s){
        return new StringBuffer(s).reverse().toString();
    }
    /**
     * 对字符串进行 num个为单位进行拆分然后以joinStr进行拼接
     * @author 吴树波
     * @date 2020/12/15 15:42
     * @param s       字符串
     * @param num     以几个为单位
     * @param joinStr 连接字符串
     * @return java.lang.String
     */
    public static String splitMoney(String s, int num, String joinStr){
        boolean isFu = "-".equals(s.substring(0, 1));
        if(isFu){
            s = s.substring(1);
        }
        // 对点进行拆分
        String[] split = s.split("\\.");
        String numStr = IntStream.range(0, num).mapToObj(e -> ".").collect(joining());
        // 每三个为单位进行拆分
        String[] array = reverse(split[0]).split("(?<=\\G" + numStr + ")");
        String collect = String.join(joinStr, array);
        return (isFu ? "-" : "") + reverse(collect) + "." + split[1];
    }
    /**
     * 对金额进行三位数的拆分并格式化
     * @author 吴树波
     * @date 2020/12/15 15:47
     * @param b 金额
     * @return java.lang.String
     */
    public static String splitMoneyRound(BigDecimal b){
        return splitMoney(BigDecimalUtil.roundTwoToString(b));
    }
    public static String splitMoneyRound(double b){
        return splitMoneyRound(BigDecimal.valueOf(b));
    }
    private static <T> Map<String, Object> objectToMap(T t, Predicate<Field> p, boolean dealWithBigDecimal, boolean splitMoney){
        // 获取class对象
        Class<?> clazz = t.getClass();
        Map<String, Object> collect = Arrays.stream(clazz.getDeclaredFields()).filter(p).filter(e -> !"serialVersionUID".equals(e.getName())).collect(toMap(Field::getName, e -> {
            // 打开私有访问
            e.setAccessible(true);
            try {
                Object o = e.get(t);
                if (o != null) {
                    if (e.isAnnotationPresent(JsonFormat.class)) {
                        JsonFormat annotation = e.getAnnotation(JsonFormat.class);
                        Class<?> type = e.getType();
                        if (type.isAssignableFrom(LocalDate.class)) {
                            return DateUtil.formatLocalDate((LocalDate) o, annotation.pattern());
                        } else if (type.isAssignableFrom(LocalDateTime.class)) {
                            return DateUtil.formatLocalDateTime((LocalDateTime) o, annotation.pattern());
                        } else if (type.isAssignableFrom(Date.class)) {
                            return DateUtil.formatLocalDateTime(DateUtil.dateToLocalDateTime((Date) o), annotation.pattern());
                        }
                    }
                    if (e.getType().isAssignableFrom(BigDecimal.class)) {
                        if (dealWithBigDecimal) {
                            return BigDecimalUtil.roundTwoToString(BigDecimal.valueOf(objectToDouble(o)));
                        }
                        if (splitMoney) {
                            return splitMoneyRound(objectToDouble(o));
                        }
                    }
                }
                return objectDefault(o);
            } catch (IllegalAccessException ex) {
                throw new BaseException("访问异常：" + e.getName());
            }
        }));
        // 获取所有属性并组装为map
        return collect.entrySet().stream().filter(e -> Objects.nonNull(e.getValue()) && StringUtils.isNotEmpty(e.getValue().toString())).collect(toMap(Map.Entry::getKey,Map.Entry::getValue));
    }
    public static Object objectDefault(Object param) {
        return Objects.isNull(param) ? "" : param;
    }
    public static double objectToDouble(Object param) {
        isNull(param, "数据为空");
        return Double.parseDouble(objectToString(param));
    }
    public static String objectToString(Object param) {
        isNull(param,  "数据为空");
        return param.toString();
    }
    public static void isNull(Object object, String msg) {
        if(Objects.isNull(object)) {
            throw new BaseException(msg);
        }
    }
    /**
     * 分组 数据返回list
     * @author 吴树波
     * @date 2019/12/4 17:30
     * @param list 数据源
     * @param deal map key
     * @return java.util.Map<K,java.util.List<T>>
     */
    public static <T,K> Map<K,List<T>> listToMapByGroupList(List<T> list,Function<T,K> deal){
        return list.stream().filter(Objects::nonNull).collect(groupingBy(deal));
    }

    /**
     * 分组 数据返回list
     * @author 吴树波
     * @date 2019/12/4 17:30
     * @param list 数据源
     * @param deal map key
     * @return java.util.Map<K,java.util.List<T>>
     * @return
     */
    public static <T, K, A, D> Map<K, D> listToMapByGroupCustomize(List<T> list, Function<T,K> deal, Collector<? super T, A, D> downstream){
        return list.stream().filter(Objects::nonNull).collect(groupingBy(deal, downstream));
    }

    /**
     * 分组 数据返回Object
     * @author 吴树波
     * @date 2019/12/4 17:28
     * @param list 数据源
     * @param deal map key
     * @return java.util.Map<K,T>
     */
    public static <T,K> Map<K,T> listToMapByGroupObject(List<T> list,Function<T,K> deal){
        return list.stream().collect(toMap(deal, e -> e, (first, last) -> first));
    }
    public static <T,K> Map<K, Map<String, Object>> listToMapByGroupMap(List<T> list,Function<T,K> deal){
        return list.stream().collect(toMap(deal, PubFun::objectToMap, (first, last) -> first));
    }

    /**
     * 分组 数据个数 并行
     * @author 吴树波
     * @date 2019/12/4 17:28
     * @param list 数据源
     * @param deal map   key
     * @return java.util.Map<K,java.lang.Long>
     */
    public static <T,K> Map<K,Long> listToMapByGroupCount(List<T> list,Function<T,K> deal){
        return listToMapByGroupCount(list, deal, true);
    }
    /**
     * 分组 数据个数
     * @author 吴树波
     * @date 2019/12/4 17:27
     * @param list 数据源
     * @param deal map   key
     * @param parallel 是否并行
     * @return java.util.Map<K,java.lang.Long>
     */
    public static <T,K> Map<K,Long> listToMapByGroupCount(List<T> list,Function<T,K> deal, boolean parallel){
        return list.stream().filter(Objects::nonNull).collect(groupingBy(deal,counting()));
    }


    public static <T, A> List<A> listToNewList(List<T> list, Function<T, A> function){
        return list.stream().filter(Objects::nonNull).map(function).distinct().collect(Collectors.toList());
    }
    public static <T extends BaseEntityTow> List<Long> listGetIds(List<T> list){
        return list.stream().filter(Objects::nonNull).map(BaseEntityTow::getId).distinct().collect(Collectors.toList());
    }

    public static <T, T1,M extends BaseMapper<T1>, S extends ServiceImpl<M, T1>> void setListObject(List<T> list, S s, Function<T, Long> genId, Function<T1, Long> genKey, BiConsumer<T, T1> action){
        if(list.isEmpty()) return;
        List<T1> ts = new ArrayList<>(s.listByIds(listToNewList(list, genId)));
        Map<Long, T1> map = listToMapByGroupObject(ts, genKey);
        list.stream().filter( e -> map.containsKey(genId.apply(e))).forEach(e -> action.accept(e, map.get(genId.apply(e))));
    }
    public static <T, T1,M extends BaseMapper<T1>, S extends ServiceImpl<M, T1>> void setListObject(List<T> list, M s, Function<T, Long> genId, Function<T1, Long> genKey, BiConsumer<T, T1> action){
        if(list.isEmpty()) return;
        List<T1> ts = s.selectList(new QueryWrapper<T1>().in("id", listToNewList(list, genId)));
        Map<Long, T1> map = listToMapByGroupObject(ts, genKey);
        list.stream().filter( e -> map.containsKey(genId.apply(e))).forEach(e -> action.accept(e, map.get(genId.apply(e))));
    }

    public static <T, T1,M extends BaseMapper<T1>, S extends ServiceImpl<M, T1>> void setListList(List<T> list, S s, Function<T, Long> genId, Function<T1, Long> genKey, BiConsumer<T, List<T1>> action){
        if(list.isEmpty()) return;
        List<T1> ts = new ArrayList<>(s.listByIds(listToNewList(list, genId)));
        Map<Long, List<T1>> map = listToMapByGroupList(ts, genKey);
        list.stream().filter( e -> map.containsKey(genId.apply(e))).forEach(e -> action.accept(e, map.get(genId.apply(e))));
    }

    public static <T, T1,M extends BaseMapper<T1>, S extends ServiceImpl<M, T1>> List<T1> getListByIds(List<T> list, S s, Function<T, Long> genId){
        return new ArrayList<>(s.listByIds(listToNewList(list, genId)));
    }
    public static <T> void batchProcessing(int batchSize, List<T> list, Consumer<List<T>> consumer){
        // 总长度
        int totalSize = list.size();
        // 每 100 个为一批次进行处理
        for (int i = 0; i < totalSize; i += batchSize) {
            // 计算当前批次的结束索引
            int end = Math.min(i + batchSize, totalSize);
            consumer.accept(list.subList(i, end));
        }
    }
}
