package com.jeequan.jeepay.core.annotate.kits;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.ReflectUtil;
import com.jeequan.jeepay.core.annotate.Desensitized;
import com.jeequan.jeepay.core.model.applyment.IdcardInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @description: 数据脱敏工具类
 * @author: zx
 * @date: 2023/04/07 12:25
 */
@Slf4j
public class DesenKit {

    /**
     * 对象脱敏
     * */
    public static void desenObject(Object javaBean) {
        if (null != javaBean) {
            Class<?> beanClass = javaBean.getClass();
            BeanUtil.descForEach(beanClass, i -> {
                try {
                    setNewValueForField(javaBean, i.getField(), i.getValue(javaBean));
                } catch (IllegalAccessException e) {
                    log.error("脱敏异常：", e);
                }
            });
        }
    }

    private static void replace(Field[] fields, Object javaBean, Set<Integer> referenceCounter) throws IllegalArgumentException, IllegalAccessException {
        if (null != fields && fields.length > 0) {
            for (Field field : fields) {
                field.setAccessible(true);
                if (null != field && null != javaBean) {
                    Object value = field.get(javaBean);
                    if (null != value) {
                        Class<?> type = value.getClass();
                        //处理子属性，包括集合中的
                        if (type.isArray()) {//对数组类型的字段进行递归过滤
                            int len = Array.getLength(value);
                            for (int i = 0; i < len; i++) {
                                Object arrayObject = Array.get(value, i);
                                if (isNotGeneralType(arrayObject.getClass(), arrayObject, referenceCounter)) {
                                    replace(ReflectUtil.getFields(javaBean.getClass()), arrayObject, referenceCounter);
                                }
                            }
                        } else if (value instanceof Collection<?>) {//对集合类型的字段进行递归过滤
                            Collection<?> c = (Collection<?>) value;
                            Iterator<?> it = c.iterator();
                            while (it.hasNext()) {// TODO: 待优化
                                Object collectionObj = it.next();
                                if (isNotGeneralType(collectionObj.getClass(), collectionObj, referenceCounter)) {
                                    replace(ReflectUtil.getFields(javaBean.getClass()), collectionObj, referenceCounter);
                                }
                            }
                        } else if (value instanceof Map<?, ?>) {//对Map类型的字段进行递归过滤
                            Map<?, ?> m = (Map<?, ?>) value;
                            Set<?> set = m.entrySet();
                            for (Object o : set) {
                                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) o;
                                Object mapVal = entry.getValue();
                                if (isNotGeneralType(mapVal.getClass(), mapVal, referenceCounter)) {
                                    replace(ReflectUtil.getFields(javaBean.getClass()), mapVal, referenceCounter);
                                }
                            }
                        } else if (value instanceof Enum<?>) {
                            continue;
                        }

                        /*除基础类型、jdk类型的字段之外，对其他类型的字段进行递归过滤*/
                        else {
                            if (!type.isPrimitive()
                                    && type.getPackage() != null
                                    && !StringUtils.startsWith(type.getPackage().getName(), "javax.")
                                    && !StringUtils.startsWith(type.getPackage().getName(), "java.")
                                    && !StringUtils.startsWith(field.getType().getName(), "javax.")
                                    && !StringUtils.startsWith(field.getName(), "java.")
                                    && referenceCounter.add(value.hashCode())) {
                                replace(ReflectUtil.getFields(javaBean.getClass()), value, referenceCounter);
                            }
                        }
                    }

                    //脱敏操作
                    setNewValueForField(javaBean, field, value);

                }
            }
        }
    }

    private static boolean isNotGeneralType(Class<?> aClass, Object arrayObject, Set<Integer> referenceCounter) {
        return true;
    }


    public static void setNewValueForField(Object javaBean, Field field, Object value) throws IllegalAccessException {

        if (value instanceof Collection<?>) {
            Collection<?> c = (Collection<?>) value;
            Iterator<?> it = c.iterator();
            while (it.hasNext()) {
                Object collectionObj = it.next();
                if (collectionObj instanceof IdcardInfo) {
                    desenObject(collectionObj);
                }
            }
        }

        //处理自身的属性
        Desensitized annotation = field.getAnnotation(Desensitized.class);
        if (null == annotation) {
            return;
        }

        if ((field.getType().equals(String.class) || field.getType().equals(Long.class))) {
            String valueStr = (String) value;
            if (StringUtils.isNotBlank(valueStr)) {
                switch (annotation.type()) {
                    case CHINESE_NAME: {
                        field.set(javaBean, DesensitizedUtil.chineseName(valueStr));
                        break;
                    }
                    case ID_CARD: {
                        field.set(javaBean, DesensitizedUtil.idCardNum(valueStr, 3, 4));
                        break;
                    }
                    case FIXED_PHONE: {
                        field.set(javaBean, DesensitizedUtil.fixedPhone(valueStr));
                        break;
                    }
                    case MOBILE_PHONE: {
                        field.set(javaBean, DesensitizedUtil.mobilePhone(valueStr));
                        break;
                    }
                    case ADDRESS: {
                        field.set(javaBean, DesensitizedUtil.address(valueStr, 8));
                        break;
                    }
                    case EMAIL: {
                        field.set(javaBean, DesensitizedUtil.email(valueStr));
                        break;
                    }
                    case BANK_CARD: {
                        field.set(javaBean, DesensitizedUtil.bankCard(valueStr));
                        break;
                    }
                    case PASSWORD: {
                        field.set(javaBean, DesensitizedUtil.password(valueStr));
                        break;
                    }
                }
            }
        }
    }


}
