package com.ruoyi.common.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;

/**
 * @author shiqian
 * @date 2021年03月26日 10:39
 **/
public class ObjectUtils {

    private static final String NULL = "null";
    private static final String UNDEFINED = "undefined";

    public static  <T> Collection<T> requireNonNull(Collection<T> input, String errorMsg){
        if (null == input || input.size() == 0) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    public static  <T> List<T> requireNonNull(List<T> input, String errorMsg){
        if (null == input || input.size() == 0) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    public static  <T> boolean isEmpty(Collection<T> input){
        return null == input || input.size() == 0;
    }

    public static  <T> boolean isNotEmpty(Collection<T> input){
        return !isEmpty(input);
    }

    public static long[] requireNonNull(long[] input, String errorMsg){
        if (ArrayUtils.isEmpty(input)) {
            throw new IllegalArgumentException(errorMsg);
        }

        return input;
    }


    public static Long[] requireNonNull(Long[] input, String errorMsg){
        if (ArrayUtils.isEmpty(input)) {
            throw new IllegalArgumentException(errorMsg);
        }

        return input;
    }

    public static Boolean requireNonNull(Boolean input, String errorMsg) {
        if (input == null) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    public static <T> T requireNonNull(T input, String errorMsg) {
        if (input == null) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    public static Integer requireNonNull(Integer input, String errorMsg) {
        if (input == null || input < 0) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    public static boolean isEmpty(Integer input) {
        return input == null || input < 0;
    }

    public static boolean isNotEmpty(Integer input) {
        return !isEmpty(input);
    }


    public static boolean isEmpty(Long input) {
        return input == null || input < 0;
    }

    public static boolean isNotEmpty(Long input) {
        return !isEmpty(input);
    }

    public static String requireNonNull(String input, String errorMsg) {
        if (input == null || input.isEmpty() || NULL.equalsIgnoreCase(input) || UNDEFINED.equalsIgnoreCase(input)) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    public static int requireNonNull(int input, String errorMsg) {
        if (input <= 0) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }


    public static JSONObject requireNonNull(JSONObject input, String errorMsg) {
        if (input == null || input.isEmpty()) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }


    public static JSONObject ifNullSetEmpty(JSONObject input) {
        if (input == null || input.isEmpty()) {
            input = new JSONObject();
        }
        return input;
    }


    public static List<JSONObject> ifNullSetEmpty(List<JSONObject> input) {
        if (input == null || input.isEmpty()) {
            input = Collections.emptyList();
        }
        return input;
    }

    public static JSONArray ifNullSetEmpty(JSONArray input) {
        if (input == null || input.isEmpty()) {
            input = new JSONArray();
        }
        return input;
    }


    public static boolean isNotEmpty(JSONObject input){
        return input != null && !input.isEmpty();
    }

    public static boolean isEmpty(JSONObject input){
        return !isNotEmpty(input);
    }

    public static boolean isNotEmpty(JSONArray input){
        return input != null && !input.isEmpty();
    }

    public static boolean isEmpty(JSONArray input){
        return !isNotEmpty(input);
    }

    /**
     * 功能描述: 暂且只做 string collection long 三种类型的校验
     *
     * @param input input
     * @return boolean
     */
    public static boolean isEmpty(Object input) {
        if (input instanceof String) {
            return StringUtils.isEmpty((String) input);
        } else if (input instanceof Collection) {
            return CollectionUtils.isEmpty(((Collection<?>) input));
        } else {
            return Objects.isNull(input);
        }
    }

    public static boolean isNotEmpty(Object input) {
        return !isEmpty(input);
    }

    public static boolean isEmpty(String input) {
        return input == null || input.isEmpty() || NULL.equalsIgnoreCase(input) || UNDEFINED.equalsIgnoreCase(input);
    }

    public static boolean isNotEmpty(String input) {
        return !isEmpty(input);
    }

    public static JSONArray requireNonNull(JSONArray input, String errorMsg) {
        if (input == null || input.isEmpty()) {
            throw new IllegalArgumentException(errorMsg);
        }
        return input;
    }

    /**
     * 功能描述: 需要判断数据库是什么类型，如果是VARCHAR则需要转，如果是数字则无需转
     *
     * @param input 输入
     * @return java.lang.String
     */
    public static String escapeStr(String input) {
        return "'" + input + "'";
    }


    /**
     * 功能描述: 是否小于0
     *
     * @param aLong aLong
     * @return boolean true小于0
     */
    public static boolean ltZero(Long aLong) {
        return null != aLong && aLong < 0;
    }


    /**
     * 功能描述: 根据规则过滤
     *
     * @param input     原数据
     * @param predicate FunctionalInterface
     * @return java.util.List<T>
     */
    public static <T> List<T> filter(List<T> input, Predicate<T> predicate) {
        return requireNonNull(input, "list is null")
                .stream().filter(predicate).collect(Collectors.toList());
    }

    public static <T> int count(List<T> input, ToIntFunction<T> toIntFunction) {
        return requireNonNull(input, "list is null").stream().mapToInt(toIntFunction).sum();
    }

    public static <T> boolean anyMatch(List<T> input, Predicate<T> predicate){
        return requireNonNull(input, "list is null").stream().anyMatch(predicate);
    }


    public static <T> boolean noneMatch(List<T> input, Predicate<T> predicate) {
        return requireNonNull(input, "list is null").stream().noneMatch(predicate);
    }

    /**
     * 功能描述: 根据规则过滤
     *
     * @param input     原数据
     * @param predicate FunctionalInterface
     * @return java.util.List<T>
     */
    public static <T> T filterOne(List<T> input, Predicate<T> predicate) {
        return requireNonNull(input, "list is null")
                .stream().filter(predicate).findFirst().orElse(null);
    }

    /**
     * 功能描述: 根据规则获取
     *
     * @param input    原数据
     * @param function FunctionalInterface
     * @return java.util.List<T>
     */
    public static <T, R> List<R> map(List<T> input, Function<T, R> function) {
        return requireNonNull(input, "list is null")
                .stream().map(function).distinct().collect(Collectors.toList());
    }

    /**
     * 功能描述: 根据规则获取
     *
     * @param input     原数据
     * @param predicate predicate
     * @param function  FunctionalInterface
     * @return java.util.List<R>
     */
    public static <T, R> List<R> mapFilter(List<T> input, Predicate<T> predicate, Function<T, R> function) {
        return requireNonNull(input, "list is null")
                .stream()
                .filter(predicate)
                .map(function)
                .distinct()
                .collect(Collectors.toList());
    }


    /**
     * 功能描述: 根据规则获取单个
     *
     * @param input    原数据
     * @param function FunctionalInterface
     * @return java.util.List<T>
     */
    public static <T, R> R mapFirst(List<T> input, Function<T, R> function) {
        requireNonNull(input, "list is null");
        List<R> rList = input.stream().map(function).collect(Collectors.toList());
        requireNonNull(rList, "rList is null");
        Optional<R> optionalR = rList.stream().findFirst();
        return optionalR.orElse(null);
    }

}
