package com.kcim.common.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

@Slf4j
public final class BeanUtil {

    /**
     * 将对象转为为指定的对象
     *
     * @param source
     * @param <T>
     * @return
     */
    public static <T> T convertObj(Object source, Class<T> clazz) {
        Object model = null;
        if (source == null || clazz == null) {
            return null;
        }

        try {
            model = clazz.newInstance();
        } catch (Exception e) {
            log.error("将对象转为为指定的对象异常", e);
        }
        BeanUtils.copyProperties(source, model);
        return (T) model;
    }

    public static <T> T convertObj(Object source, T result) {
        BeanUtils.copyProperties(source, result);
        return result;
    }

    public static <F, T> List<T> convertList(List<F> fromList, Class<T> tClass) {
        List<T> tList = new ArrayList<>();
        if (CollectionUtils.isEmpty(fromList)) {
            return tList;
        }
        fromList.forEach(f -> tList.add(convertObj(f, tClass)));
        return tList;
    }

    public static <F, T> List<T> convertListIgnoreCase(List<F> fromList, Class<T> clazz) {
        List<T> tList = new ArrayList<>();
        if (CollectionUtils.isEmpty(fromList)) {
            return tList;
        }
        fromList.forEach(f -> {
            try {
                tList.add(copyIgnoreCase(f, clazz.newInstance()));
            } catch (Exception e) {
                log.error("将对象转为为指定的对象异常", e);
            }
        });
        return tList;
    }

    /**
     * 模仿Spring中 BeanUtils.copyProperties(source,target)
     * 类型不同不可以转换
     * 但是
     * 大小写可以忽略
     * 下划线 _ 被忽略
     *
     * @param source
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T copyIgnoreCase(Object source, Class<T> clazz) {
        try {
            return copyIgnoreCase(source, clazz.newInstance());
        } catch (Exception e) {
            log.error("将对象转为为指定的对象异常", e);
        }
        return null;
    }

    /**
     * 模仿Spring中 BeanUtils.copyProperties(source,target)
     * 类型不同不可以转换
     * 但是
     * 大小写可以忽略
     * 下划线 _ 被忽略
     *
     * @param source
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T copyIgnoreCase(Object source, T target) {
        Map<String, Field> sourceMap = CacheFieldMap.getFieldMap(source.getClass());
        CacheFieldMap.getFieldMap(target.getClass()).forEach((k, it) -> {
            Field field = sourceMap.get(k);
            if (field != null && field.getType().equals(it.getType())) {
                it.setAccessible(true);
                field.setAccessible(true);
                try {
                    it.set(target, field.get(source));
                } catch (Exception e) {
                    log.error("对象复制错误", e);
                }
            }
        });
        return target;
    }

    /**
     * 将对象中所有BigDecimal类型的字段设置为0
     *
     * @param target 目标对象
     * @param <T>    对象类型
     * @return 设置后的对象
     */
    public static <T> T initBigDecimalFieldsToZero(T target) {
        if (target == null) {
            return null;
        }

        Class<?> clazz = target.getClass();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (field.getType().equals(BigDecimal.class)) {
                    field.setAccessible(true);
                    try {
                        field.set(target, BigDecimal.ZERO);
                    } catch (IllegalAccessException e) {
                        log.error("设置BigDecimal字段默认值异常", e);
                    }
                }
            }
        }
        return target;
    }

    private static class CacheFieldMap {
        private static Map<String, Map<String, Field>> cacheMap = new HashMap<>();

        private static final String SER_STR = "serialVersionUID";

        private static Map<String, Field> getFieldMap(Class clazz) {
            final String name = clazz.getName();
            Map<String, Field> result = cacheMap.get(name);
            if (result != null) {
                return result;
            }
            synchronized (name) {
                if (result != null) {
                    return result;
                }
                Map<String, Field> fieldMap = new HashMap<>();
                for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
                    Arrays.stream(clazz.getDeclaredFields()).forEach(field -> {
                                //忽略序列号字段
                                if (SER_STR.equals(field.getName())) {
                                    return;
                                }
                                fieldMap.put(field.getName().toLowerCase().replace("_", ""), field);
                            }
                    );
                }
                cacheMap.put(name, fieldMap);
                return fieldMap;
            }
        }
    }

    public static <T> T copyProperties(Object source, T result) {
        BeanUtils.copyProperties(source, result);
        return result;
    }
}