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

import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ExcelAttribute;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.ValidityConstants;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author fxj
 * @Date 2022/6/23
 * @Description
 * @Version 1.0
 */
@Data
@Slf4j
public class ExcelUtil <T> implements Serializable {
	private Class<T> clazz;
	/**
	 * 用于返回错误信息
	 */
	private List<ErrorMessage> errorInfo;

	private HashMap<Integer, ErrorMessage> errorMessageHashMap;

	public ExcelUtil(Class<T> clazz) {
		this.clazz = clazz;
	}


	public void checkEntity(T data , Integer rowNum) {
		//存储错误数据
		Class<?> fieldType;
		String error = "";
		String c = null;
		//临时存储单元格数据
		String tempStr = "";
		ErrorMessage errorTemp = null;
		// 参数校验
		Field[] fields = data.getClass().getDeclaredFields();
		ExcelAttribute attr = null;
		try{

			for (Field field : fields) {
				field.getAnnotation(ExcelAttribute.class);
				// 单元格中的内容.
				c = getStringValByObject(getFieldValueByName(attr.name(), data, DateUtil.ISO_EXPANDED_DATE_FORMAT));
				if (c != null) {
					c = c.trim();
				}
				//校验字段是否符合要求 返回错误信息
				error = validateUtil(c, attr, rowNum);
				if (null != error) {
					errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, error), errorTemp);
					continue;
				}
				if (field == null) {
					continue;
				}
				//单元格数据为空不需要处理了
				if (!StringUtils.isNotBlank(c)) {
					continue;
				}
				//如果是需要从字典表取值数据的话在这里处理即可
				if (attr.isDataId()) {
					if (Common.isNotNull(attr.dataType())) {
						//非区域字段处理 TODO
						Map<String,String> dicObj = (Map<String, String>) RedisUtil.redis.opsForValue().get(attr.dataType());
						for (Map.Entry<String,String> entry:dicObj.entrySet()){
							if (Common.isNotNull(entry.getValue()) && entry.getValue().equals(c.trim())){
								tempStr = entry.getKey();
								break;
							}
						}
					/*if (Common.isNotNull(attr.parentField())){
						tempStr = dicMap.get(attr.dataType() + "_" + c.trim() + "_" + getFieldValueByName(attr.parentField(), entity, DateUtil.ISO_EXPANDED_DATE_FORMAT));
					}else {
						tempStr = dicMap.get(attr.dataType() + "_" + c.trim());
					}*/

					} else {
						if (attr.isArea()) {
							//区域字段处理 TODO
						/*if (!Common.isNotNull(attr.parentField())) {
							tempStr = dicMap.get(c.trim() + "_0");
						} else {
							tempStr = dicMap.get(c.trim() + "_" + getFieldValueByName(attr.parentField(), entity, DateUtil.ISO_EXPANDED_DATE_FORMAT));
						}*/
						} else {
							//直接按值去找数据 TODO
							//tempStr = dicMap.get(c.trim());
						}
					}
					if (!StringUtils.isNotBlank(tempStr)) {
						if (attr.isOrgan()) {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的单位或结算主体数据，请确认存在结算主体权限"), errorTemp);
						}
						if (attr.isArea()) {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的区域数据"), errorTemp);
						} else {
							if (Common.isNotNull(attr.errorInfoImport())) {
								errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "数据'" + c + "':" + attr.errorInfoImport()), errorTemp);
							} else {
								errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, "未找到:" + c + "的字典数据"), errorTemp);
							}
						}
						continue;
					} else {
						c = tempStr;
					}
				}
				// 取得类型,并根据对象类型设置值.
				fieldType = field.getType();
				if (fieldType == null) {
					continue;
				}
				if (String.class == fieldType) {
					field.set(data, c);
				} else if (BigDecimal.class == fieldType) {
					c = c.indexOf('%') != -1 ? c.replace("%", "") : c;
					field.set(data, BigDecimal.valueOf(Double.valueOf(c)));
				} else if (Date.class == fieldType && Common.isNotNull(c.trim())) {
					field.set(data, DateUtil.stringToDate(c.trim(), Common.isEmpty(attr.dateFormat()) ? DateUtil.ISO_EXPANDED_DATE_FORMAT : attr.dateFormat()));
				} else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) {
					field.set(data, Integer.parseInt(c));
				} else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) {
					field.set(data, Long.valueOf(c));
				} else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) {
					field.set(data, Float.valueOf(c));
				} else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) {
					field.set(data, Short.valueOf(c));
				} else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) {
					field.set(data, Double.valueOf(c));
				} else if (Character.TYPE == fieldType) {
					if ((c != null) && (c.length() > 0)) {
						field.set(data, Character.valueOf(c.charAt(0)));
					}
				} else if (LocalDateTime.class == fieldType && Common.isNotNull(c.trim())) {
					String dc = c.trim().replace(CommonConstants.CENTER_SPLIT_LINE_STRING, "")
							.replace(CommonConstants.SLASH_SPLIT_LINE_STRING, "");
					try {
						if (dc.length() > CommonConstants.EIGHT_INT) {
							field.set(data, LocalDateTimeUtils.convertDateToLDT(DateUtil.stringToDate(dc, DateUtil.DATETIME_PATTERN_CONTAINS)));
						}else {
							field.set(data, LocalDateTimeUtils.convertDateToLDT(DateUtil.stringToDate(dc, DateUtil.ISO_DATE_FORMAT)));
						}
					} catch (Exception e) {
						if (dc.length() > CommonConstants.EIGHT_INT) {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap,
									new ErrorMessage(rowNum, attr.name() + "：" +
											c.trim() + "应满足时间格式：" + DateUtil.DATETIME_PATTERN_SECOND), errorTemp);
							continue;
						} else {
							errorMessageHashMap = initErrorMessage(errorMessageHashMap,
									new ErrorMessage(rowNum, attr.name() + "：" +
											c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT), errorTemp);
							continue;
						}
					}
				} else if (LocalDate.class == fieldType && Common.isNotNull(c.trim())) {
					try {
						field.set(data, LocalDate.parse(c.trim().replace(CommonConstants.CENTER_SPLIT_LINE_STRING, ""), DateTimeFormatter.ofPattern(DateUtil.ISO_DATE_FORMAT)));

					} catch (Exception e) {
						errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, attr.name() + "：" + c.trim() + "应满足时间格式：" + DateUtil.ISO_DATE_FORMAT), errorTemp);
						continue;
					}
				}
			}
		}catch (Exception e){
			errorMessageHashMap = initErrorMessage(errorMessageHashMap, new ErrorMessage(rowNum, attr.name() + "：" + c.trim() + "校验异常，请联系管理人员"), errorTemp);
		}
		this.setErrorMessageHashMap(errorMessageHashMap);
	}

	/**
	 * @param fieldName 字段名
	 * @param o         对象
	 * @return 字段值
	 * @MethodName : getFieldValueByName
	 * @Description : 根据字段名获取字段值
	 */
	public static Object getFieldValueByName(String fieldName, Object o, String dateFormat) {

		Object value = null;
		Field field = null;
		if (o == null) {
			return "";
		}
		field = getFieldByName(fieldName, o.getClass());
		String type = getFieldType(fieldName, o.getClass());
		if (field != null) {
			field.setAccessible(true);
			try {
				if (null != type && type.equals("Date")) {
					Date date = (Date) field.get(o);
					return DateUtil.dateToString(date, dateFormat == null ? "yyyy-MM-dd" : dateFormat);
				} else {
					value = field.get(o);
				}
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		} else {
			log.info(o.getClass().getSimpleName() + "类不存在字段名 " + fieldName);
		}

		return value;
	}

	/**
	 * @param fieldName 字段名
	 * @param clazz     包含该字段的类
	 * @return 字段
	 * @MethodName : getFieldByName
	 * @Description : 根据字段名获取字段
	 */
	private static Field getFieldByName(String fieldName, Class<?> clazz) {
		// 拿到本类的所有字段
		Field[] selfFields = clazz.getDeclaredFields();

		// 如果本类中存在该字段，则返回
		for (Field field : selfFields) {
			if (field.getName().equals(fieldName)) {
				return field;
			}
		}
		// 否则，查看父类中是否存在此字段，如果有则返回
		Class<?> superClazz = clazz.getSuperclass();
		if (superClazz != null && superClazz != Object.class) {
			return getFieldByName(fieldName, superClazz);
		}

		// 如果本类和父类都没有，则返回空
		return null;
	}
	/**
	 * @param fieldName 字段名
	 * @param clazz     包含该字段的类
	 * @return 字段
	 * @MethodName : getFieldType
	 * @Description : 根据字段名获取字段类型
	 */
	private static String getFieldType(String fieldName, Class<?> clazz) {
		// 拿到本类的所有字段
		Field[] selfFields = clazz.getDeclaredFields();

		// 如果本类中存在该字段，则返回
		for (Field field : selfFields) {
			if (field.getName().equals(fieldName)) {
				//如果type是类类型，则前面包含"class "，后面跟类名
				String type = field.getGenericType().toString();
				if (type.equals("class java.lang.String")) {
					return "String";
				} else if (type.equals("class java.lang.Integer")) {
					return "Integer";
				} else if (type.equals("class java.lang.Short")) {
					return "Short";
				} else if (type.equals("class java.lang.Double")) {
					return "Double";
				} else if (type.equals("class java.lang.Boolean")) {
					return "Boolean";
				} else if (type.equals("class java.util.Date")) {
					return "Date";
				} else {
					return null;
				}
			}
		}
		// 否则，查看父类中是否存在此字段，如果有则返回
		Class<?> superClazz = clazz.getSuperclass();
		if (superClazz != null && superClazz != Object.class) {
			return getFieldType(fieldName, superClazz);
		}
		// 如果本类和父类都没有，则返回空
		return null;
	}
	/**
	 * 输出错误数据
	 *
	 * @param attr
	 * @param msg
	 * @param i
	 * @return
	 */
	private String errorInfo(ExcelAttribute attr, String msg, Integer i) {
		return (Common.isEmpty(msg) ? (Common.isEmpty(attr.errorInfo()) ? "" : attr.errorInfo()) : (attr.name() + msg));
	}
	/**
	 * 正则匹配返回
	 *
	 * @param c
	 * @param attr
	 * @param pattern
	 * @return
	 * @Author fxj
	 * @Date 2019-08-06
	 **/
	private boolean getMatchRes(String c, ExcelAttribute attr, String pattern) {
		return !c.matches(Common.isEmpty(attr.pattern()) ? pattern : attr.pattern());
	}
	/**
	 * 实现各种校验方式的错误返回新
	 *
	 * @param c
	 * @param attr
	 * @param i
	 * @return
	 */
	private String validateUtil(String c, ExcelAttribute attr, int i) {
		//非空校验
		if (attr.isNotEmpty() && !Common.isNotNull(c)) {
			return errorInfo(attr, "_字段不可为空", i);
		}
		if (Common.isNotNull(c)) {
			//日期格式校验
			if (attr.isDate()) {
				DateUtil.stringToDate(c.trim(), attr.dateFormat());
			}
			//手机号码校验
			if (attr.isPhone() && getMatchRes(c.trim(), attr, ValidityConstants.MOBILE_PATTERN)) {
				return errorInfo(attr, "_手机号码有误", i);
			}
			//身份证校验
			if (attr.isIdCard() && getMatchRes(c.trim(), attr, ValidityConstants.IDCARD_PATTERN)) {
				return errorInfo(attr, "_身份证格式有误", i);
			}
			//邮箱验证
			if (attr.isEmail() && getMatchRes(c.trim(), attr, ValidityConstants.EMAIL_PATTERN)) {
				return errorInfo(attr, "_邮箱格式有误", i);
			}
			//integer 验证
			if (attr.isInteger() && getMatchRes(c.trim(), attr, ValidityConstants.INTEGER_PATTERN)) {
				return errorInfo(attr, "_整数格式有误", i);
			}
			//float、double 验证
			if (attr.isFloat() && getMatchRes(c.trim(), attr, ValidityConstants.FLOAT_PATTERN)) {
				return errorInfo(attr, "_数字格式有误", i);
			}
			if (attr.isDouble() && getMatchRes(c.trim(), attr, ValidityConstants.FLOAT_PATTERN)) {
				return errorInfo(attr, "_数字格式有误", i);
			}
			//最大长度校验
			if (attr.maxLength() > 0 && c.length() > attr.maxLength()) {
				return errorInfo(attr, "_超出最大长度", i);
			}
			//最大值校验
			if (attr.max() > 0) {
				if (Common.isNumber(c)) {
					if (attr.isDouble()){
						if (Double.doubleToLongBits(Double.valueOf(c).doubleValue()) > Double.doubleToLongBits(attr.max())) {
							return errorInfo(attr, "_超出最大值", i);
						}
					}else{
						if (Float.valueOf(c).intValue() > attr.max()) {
							return errorInfo(attr, "_超出最大值", i);
						}
					}
				} else {
					return errorInfo(attr, "_必须为数字且最多两位小数", i);
				}
			}
			//最小值校验
			if (attr.min() > 0) {
				if (Common.isNumber(c)) {
					if (attr.isFloat()){
						if (Float.valueOf(c).compareTo(attr.max()) > CommonConstants.ZERO_INT) {
							return errorInfo(attr, "_超出最大值", i);
						}
					}else{
						if (Float.valueOf(c).intValue() < attr.min()) {
							return errorInfo(attr, "_小于最小值", i);
						}
					}
				} else {
					return errorInfo(attr, "_必须为数字且最多两位小数", i);
				}
			}
		}
		return null;
	}

	/**
	 * 根据属性名获取属性值
	 *
	 * @param fieldName
	 * @param hashMap
	 * @return
	 */
	private static Object getFieldValueByName(String fieldName, HashMap hashMap) {
		try {
			return hashMap.get(fieldName);
		} catch (Exception e) {
			return null;
		}
	}
	/**
	 * 按类型统一返回String内容
	 *
	 * @param param
	 * @return
	 */
	private 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.dateToString((Date) param);
		} else if (param instanceof LocalDateTime) {
			return LocalDateTimeUtils.formatTime((LocalDateTime) param, DateUtil.DATETIME_PATTERN_SECOND);
		} else {
			return param.toString();
		}
	}

	private HashMap<Integer, ErrorMessage> initErrorMessage(HashMap<Integer, ErrorMessage> errorMessageHashMap, ErrorMessage errorMessage, ErrorMessage temp) {
		if (null != errorMessageHashMap && null != errorMessage) {
			temp = errorMessageHashMap.get(errorMessage.getLine());
			if (null != temp) {
				temp.setMessage(temp.getMessage() + CommonConstants.DOWN_LINE_STRING + errorMessage.getMessage());
				errorMessageHashMap.put(temp.getLine(), temp);
			} else {
				errorMessageHashMap.put(errorMessage.getLine(), errorMessage);
			}
		}
		return errorMessageHashMap;
	}
}
