package cn.superdesk.uniorder.common.excel;


import cn.hutool.core.collection.CollUtil;
import cn.superdesk.uniorder.common.enums.common.CommonProcessResultEnum;
import cn.superdesk.uniorder.common.excel.model.ExcelRow;
import cn.superdesk.uniorder.common.excel.validate.HibernateValidator;
import cn.superdesk.uniorder.common.excel.validate.NotDuplicateValidator;
import cn.superdesk.uniorder.common.json.AnJsonUtils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintViolation;
import javax.validation.groups.Default;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Slf4j
public class ExcelImportBaseEventListener<T extends ExcelRow> extends AnalysisEventListener<T> {

	@Getter
	private List<T>  excelRows;
	private Field[]  fields;
	private Class<T> headClazz;
	@Setter
	private int      headRowNumber;

	private NotDuplicateValidator notDuplicateValidator;

	public ExcelImportBaseEventListener(Class<T> headClazz) {
		fields = headClazz.getDeclaredFields();
		excelRows = new ArrayList<>();
		this.headClazz = headClazz;
		notDuplicateValidator = new NotDuplicateValidator();
	}

	@Override
	public void invoke(T r, AnalysisContext analysisContext) {

		recoverEmptyRow(analysisContext.getCurrentRowNum()-1, excelRows.size());

		validate(r);

		r.setRowNum(analysisContext.getCurrentRowNum());

		excelRows.add(r);
	}

	@Override
	public void doAfterAllAnalysed(AnalysisContext analysisContext) {
		recoverEmptyRow(analysisContext.getCurrentRowNum()-1, excelRows.size());
	}

	private void validate(T r) {
		if (customValidate(r)) {
			hibernateValidate(r);
		}
	}

	/**
	 * 目前的问题点就是,把全部字段都要用字符串来判定
	 *
	 * @param t
	 * @return
	 */
	private boolean customValidate(T t) {

		for (Field field : fields) {

//			log.info("custom validate field {}", JsonUtils.toJson(field));

			String name  = field.getName();
			String value = null;

//			try {
//				field.setAccessible(true);
//				value = (String) field.get(t);
//				field.setAccessible(false);
//			} catch (IllegalAccessException e) {
//				e.printStackTrace();
//			}
//
//			if (value != null && !"".equals(value) && !notDuplicateValidator.validate(field, name, value, t)) {
//				return false;
//			}
		}

		return true;
	}

	private void hibernateValidate(T instance) {

//		Set<ConstraintViolation<T>> validateSet = HibernateValidator
//				.getValidatorModeFailFastFalse()
//				.validate(instance, HibernateValidator.class);
//
//		if (validateSet != null && !validateSet.isEmpty()) {
//			ConstraintViolation<T> constraint = validateSet.stream().findAny().orElse(null);
//			instance.setValidateCode(CommonProcessResultEnum.异常_数据本身问题.getKey());
//			instance.setValidateMessage(constraint.getMessage());
//		} else {
//			instance.setValidateCode(CommonProcessResultEnum.正常.getKey());
//			instance.setValidateMessage("正常");
//		}

		List<String> validateSet001 = null;
		Set<ConstraintViolation<T>> validateSet = HibernateValidator
				.getValidatorModeFailFastFalse()
				.validate(instance, Default.class);
		if (validateSet != null && !validateSet.isEmpty()) {
			validateSet001 = validateSet.stream()
					.map(c -> c.getPropertyPath() + "#" + c.getMessage())
					.collect(Collectors.toList());
		}

		if (CollUtil.isNotEmpty(validateSet001)) {
			instance.setValidateCode(CommonProcessResultEnum.异常_数据本身缺失.getDesc());
			instance.setValidateMessage(AnJsonUtils.toJson(validateSet001));
		} else {
			instance.setValidateCode(CommonProcessResultEnum.正常.getDesc());
			instance.setValidateMessage("正常");
		}
	}

	private void recoverEmptyRow(int target, int real) {

		if (target == real) {
			return;
		}

		List<T> emptyRows = IntStream
				.rangeClosed(real + headRowNumber, target)
				.mapToObj(i -> {
					try {
						T t = headClazz.newInstance();
						t.setRowNum(i);
						hibernateValidate(t);
						return t;
					} catch (InstantiationException | IllegalAccessException e) {
						throw new RuntimeException(e);
					}
				})
				.collect(Collectors.toList());
		excelRows.addAll(emptyRows);
	}
}
