package com.m2pool.lease.aspect;


import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.json.JSONUtil;
import com.m2pool.lease.annotation.EncryptedField;
import com.m2pool.lease.exception.RSAException;
import com.m2pool.lease.utils.RsaUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.Map;

@Aspect
@Component
public class DecryptAspect {

    // 定义切点，拦截所有带 @Decrypt 注解的方法
    @Pointcut("@annotation(com.m2pool.lease.annotation.Decrypt)")
    public void decryptPointcut() {}

    @Around("decryptPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        Parameter[] parameters = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameters();

        for (int i = 0; i < parameters.length; i++) {
            // 找到被 @RequestBody 标记的参数
            if (parameters[i].isAnnotationPresent(RequestBody.class)) {
                Object requestBody = args[i];
                // 递归解密对象中的加密字段
                decryptObjectFields(requestBody);
            }
        }
        // 继续执行原方法
        return joinPoint.proceed(args);
    }

    private void decryptObjectFields(Object obj) {
        if (obj == null) {
            return;
        }

        // 处理集合或数组类型
        if (obj instanceof Collection) {
            for (Object item : (Collection<?>) obj) {
                decryptObjectFields(item);
            }
            return;
        }

        // 处理Map类型
        if (obj instanceof Map) {
            for (Object value : ((Map<?, ?>) obj).values()) {
                decryptObjectFields(value);
            }
            return;
        }

        // 处理普通对象
        Field[] fields = obj.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(EncryptedField.class)) {
                handleEncryptedField(obj, field);
            } else {
                //这里可能是普通对象或者集合或其他非EncryptedField标记的普通属性字段
                handleNestedField(obj, field);
            }
        }
    }

    private void handleEncryptedField(Object obj, Field field) {
        field.setAccessible(true);
        try {
            Object value = field.get(obj);
            if (value != null) {
                String encryptedValue = value.toString();
                System.out.println("加密前地址:"+value +"类型"+(value instanceof String));
                String decryptedValue = RsaUtils.decrypt(encryptedValue);
                System.out.println("解密后地址:"+decryptedValue);
                field.set(obj, decryptedValue);
            }
        } catch (Exception e) {
            throw new RSAException("校验失败: " + e.getMessage());
        } finally {
            field.setAccessible(false);
        }
    }

    private void handleNestedField(Object obj, Field field) {
        field.setAccessible(true);
        try {
            Object fieldValue = field.get(obj);
            if (fieldValue != null && !isPrimitiveOrWrapper(fieldValue)) {
                decryptObjectFields(fieldValue);
            }
        } catch (IllegalAccessException e) {
            // 忽略访问异常
        } finally {
            field.setAccessible(false);
        }
    }

    private boolean isPrimitiveOrWrapper(Object obj) {
        Class<?> clazz = obj.getClass();
        return clazz.isPrimitive() ||
                clazz == String.class ||
                clazz == Integer.class ||
                clazz == Long.class ||
                clazz == Double.class ||
                clazz == Float.class ||
                clazz == Boolean.class ||
                clazz == Character.class ||
                clazz == Byte.class ||
                clazz == Short.class ||
                clazz == BigDecimal.class;
    }
}
