package com.tzy.framework.util;

import com.tzy.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

@Slf4j
public class SpELUtils {

    public static final String PREFIX = "#{";
    public static final String SUBFIX = "}";


    public static void main(String[] args) {
        String contextEl = "用户名:" + "#{user.name} + 用户年龄: + #{user.age}";
        JoinPoint joinPoint = null;
        //String key = generateKeyBySpEL(contextEl, joinPoint);
        String key = generateKeyBySpEL("1", joinPoint);
        System.out.println(key);
    }


    /**
     * @param contextEl 带表达式的内容
     *                  举例: "用户名:"+#{user.name}+用户年龄:+#{user.age}
     *                  文字+#{map.name} ,不支持对象中嵌套map 如:{user.map.name}
     *                  最多支持三个变量 #{user.data.phone}
     * @param joinPoint 环绕切面 pjp
     * @return
     */
    public static String generateKeyBySpEL(String contextEl, JoinPoint joinPoint) {
        try {
            StringBuilder context = new StringBuilder();
            if (contextEl.contains(PREFIX) && contextEl.contains(SUBFIX) && contextEl.contains("+")) {
                List<String> strings = Arrays.asList((contextEl.split("\\+")));
                for (String s : strings) {
                    if (s.contains(PREFIX) && s.contains(SUBFIX)) {
                        String spel = s.substring(s.indexOf(PREFIX) + PREFIX.length(), s.lastIndexOf(SUBFIX));
                        context.append((resolverExpression(spel, joinPoint)));
                    } else {
                        context.append(s);
                    }
                }
            }else {
                context.append(contextEl);
            }
            return context.toString();
        } catch (Exception e) {
            return null;
        }
    }

    private static String resolverExpression(String expression, JoinPoint joinPoint) throws Exception {
        String first = null;
        String second = null;
        String third = null;
        if (expression.contains(".")) {
            List<String> list = Arrays.asList((expression.split("\\.")));
            if (list.size() > 3) {
                throw new ServiceException(500, "不支持三个变量以上表达式" + expression);
            }
            for (int i = 0; i < list.size(); i++) {
                if (i == 0) {
                    first = list.get(0);
                }
                if (i == 1) {
                    second = list.get(1);
                }
                if (i == 2) {
                    third = list.get(2);
                }
            }
        } else {
            first = expression;
        }

        Object[] args = joinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        Class<?>[] parameterTypes = method.getParameterTypes();
        DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        for (int i = 0; i < paramNames.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            String paramName = paramNames[i];
            Object paramValue = args[i];
            if (first.equals(paramName)) {
                if (second == null) {
                    return paramValue.toString();
                }
                if (second != null) {
                    if (paramValue instanceof Map<?, ?>) {
                        return (String) (((Map<?, ?>) paramValue).get(second));
                    } else {
                        return String.valueOf(getFieldValue(paramValue, second + (third != null ? "." + third : "")));
                    }
                }
            }
        }
        return null;
    }

    private static Object getFieldValue(Object target, String fieldName) throws Exception {
        Class<?> clazz = target.getClass();
        String[] fs = fieldName.split("\\.");
        try {
            for (int i = 0; i < fs.length - 1; i++) {
                Field f = getFieldFromClassHierarchy(clazz, fs[i]);
                f.setAccessible(true);
                target = f.get(target);
                if (target == null) {
                    return null;
                }
                clazz = target.getClass();
            }
            Field f = getFieldFromClassHierarchy(clazz, fs[fs.length - 1]);
            f.setAccessible(true);
            return f.get(target);
        } catch (Exception e) {
            throw e;
        }
    }

    private static Field getFieldFromClassHierarchy(Class<?> clazz, String fieldName) throws NoSuchFieldException {
        while (clazz != null) {
            try {
                return clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass(); // Move to the parent class
            }
        }
        throw new NoSuchFieldException("Field '" + fieldName + "' not found in class hierarchy.");
    }
}
