/* (C) 2021 YiRing, Inc. */
package com.yiring.common.util;

import cn.hutool.core.collection.CollUtil;
import java.lang.reflect.Constructor;
import java.util.*;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

/**
 * 公共工具类
 *
 * @author ifzm
 * @version 0.1 2019/3/5 20:29
 */

@SuppressWarnings({ "unused" })
@Slf4j
@UtilityClass
public class Commons {

    /**
     * 随机生成一个UUID
     *
     * @return UUID 字符串
     */
    public String uuid() {
        return UUID.randomUUID().toString().replace("-", "");
    }

    /**
     * 判断集合是否为空
     *
     * @param collection 集合
     * @return 是否为空
     */
    public boolean isNotEmpty(Collection<?> collection) {
        return collection != null && !collection.isEmpty();
    }

    /**
     * 判断Map是否为空
     *
     * @param map Map
     * @return 是否为空
     */
    public boolean isNullOrEmpty(Map<?, ?> map) {
        return map == null || map.isEmpty();
    }

    /**
     * 对象 Copy
     *
     * @param source           源对象
     * @param type             目标类型
     * @param ignoreProperties 忽略属性
     * @param <T>              目标类型
     * @return 目标对象
     */
    public <T> T transform(Object source, Class<T> type, String... ignoreProperties) {
        try {
            if (Objects.isNull(source)) {
                return null;
            }

            Constructor<T> declaredConstructor = type.getDeclaredConstructor();
            // 实例化
            T target = declaredConstructor.newInstance();
            // 使用 BeanUtils 进行数据拷贝
            BeanUtils.copyProperties(source, target, ignoreProperties);
            return target;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将集合通过 BeanUtils 反射转换成指定类型集合
     *
     * @param list             原始数据集合
     * @param type             目标类型
     * @param ignoreProperties 忽略属性
     * @param <T>              目标类型集合
     * @param <S>              原类型集合
     * @return 目标集合
     */
    public <T, S> List<T> transform(List<S> list, Class<T> type, String... ignoreProperties) {
        return transform(list, type, null, ignoreProperties);
    }

    /**
     * 将集合通过 BeanUtils 反射转换成指定类型集合
     *
     * @param list             原始数据集合
     * @param type             目标类型
     * @param fn               自定义处理函数
     * @param ignoreProperties 忽略属性
     * @param <T>              目标类型集合
     * @param <S>              原类型集合
     * @return 目标集合
     */
    public <T, S> List<T> transform(
        List<S> list,
        Class<T> type,
        CallbackFunction<S, T> fn,
        String... ignoreProperties
    ) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }

        try {
            Constructor<T> declaredConstructor = type.getDeclaredConstructor();

            List<T> targets = new ArrayList<>();
            for (S source : list) {
                // 实例化
                T target = declaredConstructor.newInstance();

                // 使用 BeanUtils 进行数据拷贝
                BeanUtils.copyProperties(source, target, ignoreProperties);

                // 通过自定义实现补充转换
                if (fn != null) {
                    fn.apply(source, target);
                }

                targets.add(target);
            }

            return targets;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @FunctionalInterface
    public interface CallbackFunction<S, T> {
        /**
         * 执行方法
         *
         * @param s 源对象
         * @param t 目标对象
         */
        void apply(S s, T t);
    }
}
