package com.artfess.base.valid;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.xml.bind.ValidationException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Component
@Slf4j
public class FieldRepeatUtils {

    /**
     * 实体类中id字段
     */
    private String idColumnName;

    /**
     * 实体类中id的值
     */
    private Object idColumnValue;

//    private String DEL = "";

    /**
     * @param fields  验证的字段数组
     * @param message 如果不满足返回的消息
     * @param o       实体类
     * @return
     */
    public boolean fieldRepeat(String[] fields, String message, Object o) throws ValidationException, IllegalAccessException {
        try {
            // 没有校验的值返回true
            if (fields != null && fields.length == 0) {
                return true;
            }
            checkUpdateOrSave(o);
            checkRepeat(fields, o, message);
            return true;
        } catch (ValidationException ed) {
            throw new ValidationException(message);
        } catch (IllegalAccessException e) {
            throw new IllegalAccessException(e.getMessage());
        }
    }

    /**
     * 通过传入的实体类中 @TableId 注解的值是否为空，来判断是更新还是保存
     * 将值id值和id列名赋值
     * id的值不为空 是更新 否则是插入
     *
     * @param o 被注解修饰过的实体类
     * @return
     */
    public void checkUpdateOrSave(Object o) throws IllegalAccessException {
        Field[] fields = getAllFields(o.getClass());
        for (Field f : fields) {
            // 设置私有属性可读
            f.setAccessible(true);
            if (f.isAnnotationPresent(TableId.class)) {
                TableId tableId = f.getAnnotation(TableId.class);
                idColumnName = tableId.value();
                idColumnValue = f.get(o);
            }
//            if (f.getName().equals("isDele")) {
//                DEL = f.getName();
//            }
        }
    }

    /**
     * 获取本类及其父类的属性的方法
     *
     * @param clazz 当前类对象
     * @return 字段数组
     */
    private static Field[] getAllFields(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        return fieldList.toArray(fields);
    }


    /**
     * 通过传入的字段值获取数据是否重复
     *
     * @param fields
     * @param o
     * @param message
     * @return
     */
    public void checkRepeat(String[] fields, Object o, String message) throws ValidationException, IllegalAccessException {
        Model model = (Model) o;
        //Mybatis-plus 3.0以下用EntityWrapper
        QueryWrapper<Object> qw = new QueryWrapper<>();

        Map<String, Object> queryMap = getColumns(fields, o);

        if (CollectionUtils.isEmpty(queryMap)) {
            log.info("未配置验证重复的字段");
            return;
        }

        qw.and((obj) -> {
            int fildNum = 0;
            for (Map.Entry<String, Object> entry : queryMap.entrySet()) {
                fildNum++;
                if (1 == fildNum) {
                    obj.eq(entry.getKey(), entry.getValue());
                } else {
                    obj.or().eq(entry.getKey(), entry.getValue());
                }

            }
        });

//        if (StringUtils.isNotBlank(DEL)) {
//            qw.eq("is_dele_", DelStatusEnum.N.getType());
//        }
        if (idColumnValue != null) {
            //更新的话，那条件就要排除自身
            qw.ne(idColumnName, idColumnValue);
        }
        List list = model.selectList(qw);
        if (list != null && list.size() > 0) {
            throw new ValidationException(message);
        }
    }


    /**
     * 多条件判断唯一性，将我们的属性和值组装在map中，方便后续拼接条件
     *
     * @param fields
     * @param o
     * @return
     */
    public Map<String, Object> getColumns(String[] fields, Object o) throws IllegalAccessException {
        Field[] fieldList = getAllFields(o.getClass());
        Map<String, Object> map = new ConcurrentHashMap<>();
        for (Field f : fieldList) {
            // ② 设置对象中成员 属性private为可读
            f.setAccessible(true);
            // 判断字段是否包含在数组中，如果存在，则将它对应的列字段放入map中
            if (ArrayUtils.contains(fields, f.getName())) {
                getMapData(map, f, o);
            }
        }
        return map;
    }

    /**
     * 得到查询条件
     *
     * @param map 列字段
     * @param f   字段
     * @param o   传入的对象
     */
    private void getMapData(Map<String, Object> map, Field f, Object o) throws IllegalAccessException {
        try {
            if (f.isAnnotationPresent(TableField.class)) {
                TableField tableField = f.getAnnotation(TableField.class);
                Object val = f.get(o);
                if(null != val) {
                    map.put(tableField.value(), val);
                }
            }
        } catch (IllegalAccessException i) {
            throw new IllegalAccessException("获取字段的值错误");
        }
    }
}
