package com.kym.common.utils;

import cn.hutool.core.util.ReflectUtil;
import com.kym.common.constant.ResponseEnum;
import com.kym.common.exception.BusinessException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;


/**
 * 通用工具类
 */
public class CommUtil {

    private static Logger logger = LoggerFactory.getLogger(CommUtil.class);

    private CommUtil() {
    }

    /**
     * 断言
     *
     * @param expected
     * @param error
     * @param code
     */
    public static void asserts(boolean expected, String error, int code) {
        if (!expected) {
            throw new BusinessException(code, error);
        }
    }

    /**
     * 断言
     *
     * @param obj
     * @param error
     * @param code
     */
    public static void assertsNonNull(Object obj, String error, int code) {
        if (isEmptyOrNull(obj)) {
            throw new BusinessException(code, error);
        }
    }


    public static void assertsNonNulls(List<Object> obj, String error) {
        if (isEmptyOrNull(obj)) {
            throw new BusinessException(ResponseEnum.FAILED.getCode(), error);
        }
        obj.forEach(k->{
            if (isEmptyOrNull(k)) {
                throw new BusinessException(ResponseEnum.FAILED.getCode(), error);
            }
        });
    }


    /**
     * 断言
     *
     * @param expected
     * @param error
     */
    public static void asserts(boolean expected, String error) {
        if (!expected) {
            throw new BusinessException(ResponseEnum.FAILED.getCode(), error);
        }
    }


    /**
     * 断言
     *
     * @param expected
     * @param msgEnum
     */
    public static void asserts(boolean expected, ResponseEnum msgEnum) {
        if (!expected) {
            throw new BusinessException(msgEnum);
        }
    }

    /**
     * 断言
     *
     * @param obj
     * @param msgEnum
     */
    public static void assertsNonNull(Object obj, ResponseEnum msgEnum) {
        if (isEmptyOrNull(obj)) {
            throw new BusinessException(msgEnum);
        }
    }

    /**
     * privatmitive
     * 判断一个对象是否是基础数据类型或String
     */
    public static boolean isBasicType(Object obj) {
        if (obj instanceof String) {
            return true;
        } else if (obj instanceof Integer) {
            return true;
        } else if (obj instanceof Short) {
            return true;
        } else if (obj instanceof Float) {
            return true;
        } else if (obj instanceof Double) {
            return true;
        } else if (obj instanceof Byte) {
            return true;
        } else if (obj instanceof Boolean) {
            return true;
        } else if (obj instanceof Long) {
            return true;
        } else {
            return obj instanceof Character;
        }
    }

    public static boolean isNotEmptyAndNull(Object value) {
        if (null == value) {
            return false;
        }
        if (isBasicType(value)) {
            return !isEmptyOrNull(value.toString());
        } else {
            if (value instanceof Array) {
                return Array.getLength(value) != 0;
            } else if (value instanceof Collection) {
                return !((Collection<?>) value).isEmpty();
            } else if (value instanceof Map) {
                return !((Map<?, ?>) value).isEmpty();
            } else {
                return !isEmptyOrNull(value.toString());
            }
        }
    }

    /**
     * 判断集合是否为空
     */
    public static boolean isEmptyOrNull(Collection<?> collection) {
        return null == collection || collection.isEmpty();
    }


    /**
     * 判断集合是否为空
     */
    public static boolean isEmptyOrNull(List<Object> args) {
        if (null == args || args.isEmpty()) {
            return true;
        }
        for (Object arg : args) {
            if (isEmptyOrNull(arg)) {
                return true;
            }
        }
        return false;
    }

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

    /**
     * 判断数组是否为空
     */
    public static boolean isEmptyOrNull(Object[] array) {
        return null == array || array.length == 0 || isEmptyOrNull(array[0]);
    }

    /**
     * 判断字符串是否为空
     */
    public static boolean isEmptyOrNull(String value) {
        return null == value || value.length() == 0 || value.trim().length() == 0;
    }

    /**
     * 判断对象是否为空
     */
    public static boolean isEmptyOrNull(Object value) {
        if (null == value) {
            return true;
        }
        if (isBasicType(value)) {
            return isEmptyOrNull(value.toString());
        } else {
            if (value.getClass().isArray()) {
                return Array.getLength(value) == 0;
            } else if (value instanceof Collection) {
                return ((Collection<?>) value).isEmpty();
            } else if (value instanceof Map) {
                return ((Map<?, ?>) value).isEmpty();
            } else {
                return isEmptyOrNull(value.toString());
            }
        }
    }


    public static <T> Set<T> null2Set(Collection<T> col, boolean checkNull) {
        Set<T> list = new HashSet<>();
        if (isEmptyOrNull(col)) {
            return list;
        }
        if (checkNull) {
            try {
                for (T t : col) {
                    if (null != t) {
                        list.add(t);
                    }
                }
            } catch (Exception e) {
                logger.error("null2Set error", e);
            }
        }
        return list;
    }


    /**
     * 集合过滤空转List
     *
     * @param iterable
     * @param <T>
     * @return
     */
    public static <T> List<T> null2List(Iterable<T> iterable) {
        List<T> list = new ArrayList<>();
        if (isEmptyOrNull(iterable)) {
            return list;
        }

        for (T next : iterable) {
            if (!isEmptyOrNull(next)) {
                list.add(next);
            }
        }

        return list;
    }

    /**
     * 判断是否为脚本类可执行文件
     *
     * @param suffix
     * @return
     */
    public static boolean isExecutable(String suffix) {
        if (isEmptyOrNull(suffix)) return false;
        List<String> forbidSuffixs = List.of("sh", "bat", "exe", "msi", "py");
        return forbidSuffixs.contains(suffix.toLowerCase());
    }


    /**
     * 对象转Long
     *
     * @param s
     * @return
     */
    public static Long null2Long(Object s) {
        long v = 0L;
        if (null != s) {
            try {
                v = Long.parseLong(s.toString());
            } catch (Exception e) {
                logger.error("null2Long error :{}", s);
            }
        }
        return v;
    }

    public static String null2String(Object val) {
        if (isEmptyOrNull(val)) {
            return "";
        }
        return val.toString().trim();
    }

    public static String toDbColumn(String name) {
        char[] chars = name.toCharArray();
        StringBuilder sbr = new StringBuilder();
        for (char ch : chars) {
            if (Character.isUpperCase(ch)) {
                sbr.append("_").append(Character.toLowerCase(ch));
            } else {
                sbr.append(ch);
            }
        }
        return sbr.toString();
    }

    /**
     * 根据指定字段去重
     *
     * @param keyExtractor
     * @param <T>
     * @return
     */
    public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }



    /**
     * 反射获取对象的属性值
     */
    public static Object getFieldAlternativeValue(Object bean, String... fieldName) {
        for (String s : fieldName) {
            try {
                Field field = ReflectUtil.getField(bean.getClass(), s);
                field.setAccessible(true);
                Object val = field.get(bean);
                if (null != val) {
                    return val;
                }
            } catch (Exception e) {
                logger.debug("CommUtil.getFieldAlternativeValue Miss " + e.getMessage());
            }
        }
        return null;
    }

}
