package com.ruoyi.framework.aspectj;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.annotation.DataMasking;
import com.ruoyi.common.annotation.DataMaskings;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author Duke_yzl
 * @date 20230618.01
 * @describe：
 */
@Aspect
@Component
@Slf4j
public class DataMaskingAspect {

    @Pointcut("@annotation(com.ruoyi.common.annotation.DataMasking) || @annotation(com.ruoyi.common.annotation.DataMaskings)")
    public void annotationPointcut(){
    }

    /**
     * 在切入点return内容之后切入内容（可以用来对处理返回值做一些加工处理）
     * @param joinPoint
     */
    @AfterReturning(value = "annotationPointcut()",returning = "res")
    public void doAfterReturning(JoinPoint joinPoint, Object res) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        DataMasking[] sensibles;
        // 获取注解Action
        DataMasking sensible = method.getAnnotation(DataMasking.class);
        if (null != sensible){
            sensibles = new DataMasking[]{sensible};
        }else {
            DataMaskings typeSensibles = method.getAnnotation(DataMaskings.class);
            sensibles = typeSensibles.value();
        }
        this.mask(res,sensibles, method.getName());
    }
    /**
     * 处理返回数据
     *
     * @param obj       对象
     * @param sensibles 字典类型
     */
    private void mask(Object obj, DataMasking[] sensibles, String methodName) {
        // 处理返回类型

        if (obj instanceof AjaxResult) {
            this.mask(((AjaxResult) obj).get(AjaxResult.DATA_TAG), sensibles, methodName);
            return;
        }
        if (obj instanceof TableDataInfo) {
            ((TableDataInfo) obj).getRows().forEach(e -> this.mask(e, sensibles, methodName));
            return;
        }
        if (obj instanceof Iterable) {
            ((Iterable) obj).forEach(e -> this.mask(e, sensibles, methodName));
            return;
        }
        Class<?> clazz = obj.getClass();
        for (DataMasking sensible : sensibles) {
            try {
                Field field = ReflectUtil.getField(clazz, sensible.name());
                if (field == null || !field.getType().getSimpleName().contains("String")) {
                    log.warn("--- 方法 {},字典 {} 进行忽略,不存在 || 非String类型 ------", methodName, sensible.name());
                    continue;
                }
                Object val = ReflectUtil.getFieldValue(obj, field);
                if (ObjectUtil.isEmpty(val)) {
                    continue;
                }
                String label = sensible.status()? StrUtil.desensitized((CharSequence) val, sensible.desensitizedType()):StrUtil.hide((CharSequence) val, sensible.startNum(), ((CharSequence) val).length()+sensible.endNum());
                ReflectUtil.setFieldValue(obj, field, label);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }


}