package com.changhu.support.fastjson2.filter;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.DesensitizedUtil;
import com.alibaba.fastjson2.filter.ValueFilter;
import com.changhu.common.annotation.Desensitized;
import com.changhu.common.pojo.vo.DesensitizedVo;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * author: luozhun
 * desc: 数据加敏过滤器
 * createTime: 2023/9/13 16:44
 */
@Slf4j
public class DesensitizedFilter implements ValueFilter {

    public static final DesensitizedFilter instance = new DesensitizedFilter();

    private static final Map<FieldKey, Desensitized> cache = new ConcurrentHashMap<>();

    private DesensitizedFilter() {
    }

    static {
        preProcessAnnotations();
    }

    @Override
    public Object apply(Object object, String name, Object value) {
        if (value instanceof String strValue && !strValue.isEmpty()) {
            FieldKey fieldKey = new FieldKey(object.getClass(), name);
            Desensitized desensitized = cache.get(fieldKey);
            if (desensitized != null) {
                if (desensitized.keepOriginalField()) {
                    return DesensitizedVo.builder()
                            .originalValue(strValue)
                            .desensitizedValue(DesensitizedUtil.desensitized(strValue, desensitized.value()))
                            .build();
                }
                return DesensitizedUtil.desensitized(strValue, desensitized.value());
            }
        }
        return value;
    }

    /**
     * 脱敏字段预处理 初始化缓存信息
     */
    private static void preProcessAnnotations() {
        Set<Class<?>> classes = ClassUtil.scanPackage("com.changhu");
        for (Class<?> clazz : classes) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                Desensitized annotation = AnnotationUtil.getAnnotation(field, Desensitized.class);
                if (annotation != null) {
                    cache.put(new FieldKey(clazz, field.getName()), annotation);
                }
            }
        }
    }

    private record FieldKey(Class<?> clazz, String fieldName) {

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            FieldKey fieldKey = (FieldKey) o;
            return clazz.equals(fieldKey.clazz) && fieldName.equals(fieldKey.fieldName);
        }

        @Override
        public int hashCode() {
            return clazz.hashCode() ^ fieldName.hashCode();
        }
    }

}