package com.yifu.cloud.plus.v1.yifu.common.core.util;

import cn.hutool.core.collection.CollUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static java.util.regex.Pattern.compile;


/**
 * @author: FANG
 * @createDate: 2017年7月24日 下午4:50:23
 * @Description 常用工具类
 */
@Slf4j
public class Common {
	/**
	 * 字符串不为空且不是空串不是字符"null"
	 *
	 * @param str
	 * @return
	 * @author: fxj
	 */
	public static boolean isEmpty(String str) {
		return null == str || "".equals(str.trim()) || "null".equals(str.trim()) || "undefinded".equals(str.trim());
	}
	/**
	 * 截取startStr和endStr中间的字符串（开区间）
	 *
	 * @param startStr 开始的标志
	 * @param endStr   结束标志
	 * @param src      源串
	 * @return 返回符合要求的字符串或者返回null
	 * @author: fxj
	 */
	public static String subByStr(String startStr, String endStr, String src) {
		if (StringUtils.isNotBlank(src) && StringUtils.isNotBlank(startStr) && StringUtils.isNotBlank(endStr)) {
			int start = src.indexOf(startStr);
			int end = src.indexOf(endStr);
			if (end > start && start > -1) {
				return src.substring(start + 1, end);
			}
		}
		return null;
	}
	/**
	 * 对象null
	 *
	 * @param obj
	 * @return
	 * @author: fxj
	 */
	public static boolean isEmpty(Object obj) {
		return null == obj || "".equals(obj) || "null".equals(obj);
	}

	public static boolean isEmpty(Map obj) {
		return (null == obj || obj.size() == 0);
	}

	public static boolean isEmpty(List obj) {
		return (null == obj || obj.size() == 0);
	}

	public static boolean isNotNull(Object obj) {
		return null != obj && !"".equals(obj) && !"null".equals(obj);
	}

	public static boolean isNotEmpty(List obj) {
		return (null != obj && obj.size() > 0);
	}

	public static boolean isNotNull(String obj) {
		if (null != obj && !"".equals(obj) && !"undefined".equals(obj) && !"null".equals(obj)) {
			return true;
		}
		return false;
	}

	/**
	 * 集合不为空
	 *
	 * @param collection
	 * @return
	 */
	public static boolean isNotKong(Collection collection) {
		return null != collection && collection.size() > 0;
	}

	/**
	 * obj不是null
	 *
	 * @param obj
	 * @return
	 * @author: fxj
	 */
	public static boolean isNotKong(Object obj) {
		return null != obj;
	}

	/**
	 * 集合为空
	 *
	 * @param collection
	 * @return
	 */
	public static boolean isEmpty(Collection collection) {
		return null == collection || collection.size() == 0;
	}

	// 金额验证
	public static boolean isNumber(String str) {
		// 判断小数点后2位的数字的正则表达式
		Pattern pattern = compile("^((-?[1-9]{1}\\d*)|(-?[0]{1}))(\\.(\\d){0,2})?$");
		Matcher match = pattern.matcher(str);
		return match.matches() != false;
	}

	/**
	 * 允许上传的文件类型
	 *
	 * @Author pwang
	 * @Date 2020-01-07 15:52
	 * @param null
	 * @return
	 **/
	private static final String suffixList = "gif|jpg|jpeg|png|bmp|xls|xlsx|csv|pdf|docx|doc|m4a|mp3|zip|rar|txt";

	/**
	 * 判断是否为允许的上传文件类型,true表示允许
	 */
	public static boolean checkFile(String fileName) {
		// 获取文件后缀
		String suffix = getSuffix(fileName);
		if (null != suffix) {
			if (suffixList.contains(suffix.trim().toLowerCase())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断是否为允许的上传文件类型,true表示允许
	 */
	public static String getSuffix(String fileName) {

		if (isEmpty(fileName) || fileName.lastIndexOf(CommonConstants.SPOT_CHAR) < 0) {
			return null;
		}
		// 获取文件后缀
		return fileName.substring(fileName.lastIndexOf(CommonConstants.SPOT_CHAR)
				+ 1, fileName.length());

	}

	/**
	 * 将字符串根据分割附转换为字符集合
	 *
	 * @param str
	 * @param regex
	 * @return
	 * @author: pwang
	 */
	public static List<String> initStrToList(String str, String regex) {
		List<String> result = new ArrayList<String>();
		try {
			if (isNotNull(str) && isNotNull(regex)) {
				String[] strTemp = str.split(regex);
				if (isNotNull(strTemp)) {
					for (String temp : strTemp) {
						if (isNotNull(temp)) {
							result.add(temp);
						}
					}
				}
			}
		} catch (Exception e) {
			log.error("字符串转LIST错误");
			return null;
		}
		return result;
	}

	/**
	 * 将集合拼成串
	 *
	 * @param <T>
	 * @param str
	 * @param regex 分隔符默认，
	 * @return
	 */
	public static <T> String ListToStr(Collection<T> str, String regex) {
		String result = "";
		try {
			if (isNotNull(str)) {
				// 默认用，分割
				if (!isNotNull(regex)) {
					regex = ",";
				}
				for (Object strtemp : str) {
					if ("".equals(result)) {
						result = String.valueOf(strtemp);
					} else {
						result = result + regex + strtemp;
					}
				}
			}
		} catch (Exception e) {
			// 数据异常
		}
		return result;
	}

	public static <T> boolean isNotNull(Collection<T> obj) {
		return null != obj && obj.size() > 0;
	}

	public static List<String> getList(String ids) {
		List<String> idList = null;
		if (Common.isNotNull(ids)) {
			idList = Common.initStrToList(ids, CommonConstants.COMMA_STRING);
		}
		return idList;
	}

	/**
	 * 对象转string
	 *
	 * @param param
	 * @return
	 */
	public static String getStringValByObject(Object param) {
		if (null == param) {
			return null;
		} else if (param instanceof Integer) {
			return Integer.toString(((Integer) param).intValue());
		} else if (param instanceof String) {
			return (String) param;
		} else if (param instanceof Double) {
			return Double.toString(((Double) param).doubleValue());
		} else if (param instanceof Float) {
			return Float.toString(((Float) param).floatValue());
		} else if (param instanceof Long) {
			return Long.toString(((Long) param).longValue());
		} else if (param instanceof Boolean) {
			return Boolean.toString(((Boolean) param).booleanValue());
		} else if (param instanceof Date) {
			return DateUtil.formatDate((Date) param);
		} else {
			return param.toString();
		}
	}

	/**
	 * 根据属性名获取属性值
	 *
	 * @param fieldName
	 * @param o
	 * @return
	 */
	public static Object getFieldValueByName(String fieldName, Object o) {
		try {
			String firstLetter = fieldName.substring(0, 1).toUpperCase();
			String getter = "get" + firstLetter + fieldName.substring(1);
			Method method = o.getClass().getMethod(getter);
			Object value = method.invoke(o);
			return value;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	public static <T> HashMap<String, T> listToHashMapByKey(List<T> list, String filedKey) {
		HashMap<String, T> hashMap = new HashMap<String,T>();
		Object key = null;
		String[] split = null;
		if (null != list) {
			if (filedKey.indexOf(CommonConstants.DOWN_LINE_CHAR) > CommonConstants.dingleDigitIntArray[0]) {
				split = filedKey.split(CommonConstants.DOWN_LINE_STRING);
				for (T t : list) {
					key= null;
					key = getFieldsValue(t, split, key);
					hashMap.put(getStringValByObject(key), t);
				}
			} else {
				for (T t : list) {
					key= null;
					key = getFieldValueByName(filedKey, t);
					hashMap.put(getStringValByObject(key), t);
				}
			}
		}
		return hashMap;
	}
	public static <T> HashMap<String, T> listToHashMapByKey(List<T> list, String keyPreStr, String filedKey) {
		HashMap<String, T> hashMap = new HashMap<String,T>();
		Object key = null;
		String[] split = null;
		if (null != list) {
			if (filedKey.indexOf(CommonConstants.DOWN_LINE_CHAR) > CommonConstants.dingleDigitIntArray[0]) {
				split = filedKey.split(CommonConstants.DOWN_LINE_STRING);
				for (T t : list) {
					key= null;
					key = getFieldsValue(t, split, key);
					hashMap.put(keyPreStr +CommonConstants.DOWN_LINE_STRING+ getStringValByObject(key), t);
				}
			} else {
				for (T t : list) {
					key= null;
					key = getFieldValueByName(filedKey, t);
					hashMap.put(keyPreStr +CommonConstants.DOWN_LINE_STRING+ getStringValByObject(key), t);
				}
			}
		}
		return hashMap;
	}

	/**
	 * 从实体中获取多个字段的值并已下划线分割
	 *
	 * @param t
	 * @param split
	 * @return
	 * @Author fxj
	 * @Date 2019-09-24
	 **/
	private static <T> Object getFieldsValue(T t, String[] split, Object key) {
		int i = 0;
		while (i < split.length) {
			if (null == key || CommonConstants.EMPTY_STRING.equals(key)) {
				key = getFieldValueByName(split[i], t);
			} else {
				key = key + CommonConstants.DOWN_LINE_STRING + getFieldValueByName(split[i], t);
			}
			i++;
		}
		return key;
	}

	/**
	 * 如果为空或零 返回true  否则 返回false
	 * @Author fxj
	 * @Date 2020-12-29
	 * @param data
	 * @return
	 **/
	public static boolean isNullOrZero(BigDecimal data) {
		if (null == data ||
				BigDecimal.ZERO.compareTo(data) == CommonConstants.ZERO_INT){
			return true;
		}
		return false;
	}

	public static String isNotNullToStr(Integer value) {
		if (Common.isNotNull(value)){
			return Integer.toString(value);
		}
		return null;
	}
	public static String isNotNullToStr(Long value) {
		if (Common.isNotNull(value)){
			return Long.toString(value);
		}
		return null;
	}

	public static Integer isNotNullToInt(String value) {
		if (Common.isNotNull(value)){
			try {
				return  Integer.valueOf(value);
			}catch (Exception e){
				return null;
			}
		}
		return null;
	}

	/**
	 * 默认"null"
	 * @param obj
	 * @return
	 */
	public static String isBlankToNullString(String obj) {
		if(obj == null || "".equals(obj)) {
			return CommonConstants.NULL;
		}
		if(obj.trim().length() == 0) {
			return CommonConstants.NULL;
		}
		if(obj.trim().equals("null")) {
			return CommonConstants.NULL;
		}
		return obj;
	}
	public static String isNullToString(StringBuilder obj) {
		if(obj == null) {
			return CommonConstants.EMPTY_STRING;
		}
		return obj.toString();
	}
	public static String isNullToString(String obj) {
		if(obj == null || "".equals(obj)) {
			return CommonConstants.EMPTY_STRING;
		}
		if(obj.trim().length() == 0) {
			return CommonConstants.EMPTY_STRING;
		}
		if(obj.trim().equals("null")) {
			return CommonConstants.EMPTY_STRING;
		}
		return obj;
	}

	/**
	 * 两个日期中间年份
	 * @Author fxj
	 * @Date 2021-07-22
	 * @param start  yyyy-MM-dd
	 * @param end  yyyy-MM-dd
	 * @return
	 **/
	public static int getYearOfTime(String start, String end) {
		int year = 0;
		if (Common.isEmpty(start) || Common.isEmpty(end) || start.length() < 10 || end.length() < 10){
			return year;
		}
		String startYear = start.substring(0,4);
		String endYear = end.substring(0,4);
		if (!Common.isNumber(startYear) || !Common.isNumber(endYear)){
			return year;
		}
		year = Integer.valueOf(endYear).intValue() - Integer.valueOf(startYear).intValue() ;
		return year < 0?0:year;
	}

	public static int getYearOfTime(Date start, Date end) {
		int year = 0;
		if (Common.isEmpty(start) || Common.isEmpty(end)){
			return year;
		}
		String startYear = DateUtil.getYear(start).substring(0,4);
		String endYear = DateUtil.getYear(end).substring(0,4);
		if (!Common.isNumber(startYear) || !Common.isNumber(endYear)){
			return year;
		}
		year = Integer.valueOf(endYear).intValue() - Integer.valueOf(startYear).intValue() ;
		return year < 0?0:year;
	}


	/**
	 * 公积金单边小数点格式化
	 *
	 * @param money
	 * @param type
	 * @return
	 * @Author fxj
	 * @Date 2019-09-26
	 **/
	public static BigDecimal formatMoneyForFund(BigDecimal money, int type) {
		DecimalFormat formater = new DecimalFormat("#0.#");
		if (type == 1) {//四舍五入取整
			return BigDecimal.valueOf(money.doubleValue()).setScale(0, RoundingMode.HALF_UP);
		}
		if (type == 2) {//元一下全部舍去，取整
			return BigDecimal.valueOf(Math.floor(money.doubleValue())).setScale(0, BigDecimal.ROUND_UP);
		}
		if (type == 3) {//见角进元
			return BigDecimal.valueOf(Math.ceil(BigDecimal.valueOf(money.doubleValue()).setScale(1, RoundingMode.HALF_DOWN).doubleValue())).setScale(0, BigDecimal.ROUND_UP);
		}
		if (type == 4) {//保留两位小数
			return BigDecimal.valueOf(money.doubleValue()).setScale(2, RoundingMode.HALF_UP);
		}
		if (type == 5) {//保留一位小数
			return BigDecimal.valueOf(money.doubleValue()).setScale(1, RoundingMode.HALF_UP);
		}
		return money;
	}

	public static void clear(Collection map){
		if (Common.isNotNull(map)){
			map.clear();
		}
	}
	public static void clear(Map map){
		if (Common.isNotNull(map)){
			map.clear();
		}
	}

	/**
	 * 按字段返回字符串
	 *
	 * @param list
	 * @param filedName
	 * @param <T>
	 * @return
	 */
	public static <T> List<String> listObjectToStrList(List<T> list, String filedName) {
		List<String> idsStr = new ArrayList<String>();
		Object temp = null;
		if (null != list && list.size() > 0) {
			for (T t : list) {
				temp = getFieldValueByName(filedName, t);
				if (null != temp) {
					idsStr.add(temp.toString());
				}
			}
		}
		return idsStr;
	}

	/**
	 * 默认空 置为零
	 * @param obj
	 * @return
	 */
	public static BigDecimal isBlankToBigDecimalZero(BigDecimal obj) {
		if(obj == null) {
			return BigDecimal.ZERO;
		}
		if(String.valueOf(obj).trim().length() == 0) {
			return BigDecimal.ZERO;
		}
		if(String.valueOf(obj).trim().equals("null")) {
			return BigDecimal.ZERO;
		}
		return obj;
	}

	/**
	 * 商险附件允许上传的文件类型
	 *
	 * @Author pwang
	 * @Date 2020-01-07 15:52
	 * @param null
	 * @return
	 **/
	private static final String insuranceSuffixList = "pdf|png|jpg|doc|docx|xls|xlsx|rar|zip|txt|jpeg";

	/**
	 * 判断是否为允许的上传文件类型,true表示允许
	 */
	public static boolean checkInsuranceFile(String fileName) {
		// 获取文件后缀
		String suffix = getSuffix(fileName);
		if (null != suffix) {
			if (insuranceSuffixList.contains(suffix.trim().toLowerCase())) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @description: 通过spring校验注解list中的数据格式, 后续补充剩余注解
	 * @param list 需要校验的list
	 * @return: java.util.List<com.yifu.cloud.v1.common.core.util.bean.ErrorMessage>
	 * @author: wangweiguo
	 * @date: 2021/8/24
	 */
	public static List<ErrorMessage> commonImportErrorMessage(List<?> list) {
		List<ErrorMessage> errorMessageList = new ArrayList<>();
		if (!CollUtil.isEmpty(list)) {
			int size = list.size();
			for (int i = 0; i < size; i++) {
				Object o = list.get(i);
				Field[] fields = o.getClass().getDeclaredFields();
				for (Field field : fields) {
					Annotation[] declaredAnnotations = field.getDeclaredAnnotations();
					if (declaredAnnotations.length == 0) {
						continue;
					}
					try {
						for (Annotation declaredAnnotation : declaredAnnotations) {
							field.setAccessible(true);
							Object val = field.get(o);
							if (declaredAnnotation instanceof NotBlank) {
								// @NotBlank
								String s = (String) val;
								if (StringUtils.isBlank(s)) {
									errorMessageList.add(new ErrorMessage(i + 2, ((NotBlank) declaredAnnotation).message(), CommonConstants.RED));
									break;
								}
							} else if (declaredAnnotation instanceof Length) {
								// @Length
								if (val instanceof String) {
									String s = (String) val;
									if (s.length() > ((Length) declaredAnnotation).max()) {
										errorMessageList.add(new ErrorMessage(i + 2, ((Length) declaredAnnotation).message(), CommonConstants.RED));
										break;
									}
									if (s.length() < ((Length) declaredAnnotation).min()) {
										errorMessageList.add(new ErrorMessage(i + 2, ((Length) declaredAnnotation).message(), CommonConstants.RED));
										break;
									}
								}
							} else if (declaredAnnotation instanceof NotNull) {
								// @NotNull
								if (null == val) {
									errorMessageList.add(new ErrorMessage(i + 2, ((NotNull) declaredAnnotation).message(), CommonConstants.RED));
									break;
								}
							} else if(declaredAnnotation instanceof Size) {
								// @Size
								int curSize = 0;
								if (val instanceof String) {
									curSize = ((String) val).length();
								}
								if (val instanceof Collection) {
									curSize = ((Collection<?>) val).size();
								}
								if (val instanceof Map) {
									curSize = ((Map<?, ?>) val).size();
								}
								int min = ((Size) declaredAnnotation).min();
								int max = ((Size) declaredAnnotation).max();
								if (curSize > max) {
									errorMessageList.add(new ErrorMessage(i + 2, ((Size) declaredAnnotation).message(), CommonConstants.RED));
									break;
								}
								if (curSize < min) {
									errorMessageList.add(new ErrorMessage(i + 2, ((Size) declaredAnnotation).message(), CommonConstants.RED));
									break;
								}
							} else if (declaredAnnotation instanceof javax.validation.constraints.Pattern) {
								// @Pattern
								if (val instanceof String) {
									if (!((String) val).matches(((javax.validation.constraints.Pattern) declaredAnnotation).regexp())) {
										errorMessageList.add(new ErrorMessage(i + 2, ((javax.validation.constraints.Pattern) declaredAnnotation).message(), CommonConstants.RED));
										break;
									}
								}
							} else if (declaredAnnotation instanceof Digits) {
								int maxIntegerLength = ((Digits) declaredAnnotation).integer();
								int maxFractionLength = ((Digits) declaredAnnotation).fraction();
								if (val instanceof BigDecimal) {
									int integerPartLength = ((BigDecimal) val).precision() - ((BigDecimal) val).scale();
									int fractionPartLength = Math.max(((BigDecimal) val).scale(), 0);
									if (!( maxIntegerLength >= integerPartLength && maxFractionLength >= fractionPartLength )) {
										errorMessageList.add(new ErrorMessage(i + 2, ((Digits) declaredAnnotation).message(), CommonConstants.RED));
										break;
									}
								}
							} else if (declaredAnnotation instanceof DecimalMin) {
								BigDecimal minValue = BigDecimal.valueOf(Double.parseDouble(((DecimalMin) declaredAnnotation).value()));
								if (val instanceof BigDecimal) {
									if (minValue.compareTo((BigDecimal) val) >= 0) {
										errorMessageList.add(new ErrorMessage(i + 2, ((DecimalMin) declaredAnnotation).message(), CommonConstants.RED));
										break;
									}
								}
							} else if (declaredAnnotation instanceof DecimalMax) {
								BigDecimal maxValue = BigDecimal.valueOf(Double.parseDouble(((DecimalMax) declaredAnnotation).value()));
								if (val instanceof BigDecimal) {
									if (maxValue.compareTo((BigDecimal) val) <= 0) {
										errorMessageList.add(new ErrorMessage(i + 2, ((DecimalMax) declaredAnnotation).message(), CommonConstants.RED));
										break;
									}
								}
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}
		}
		return errorMessageList;
	}

	public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
		Set<Object> seen = ConcurrentHashMap.newKeySet();
		return t -> seen.add(keyExtractor.apply(t));
	}
}
