package com.ytpm.util;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * FeignClient公共调用类
 * @author Marx
 * @date 2025/8/19 17:22
 */
@Component
public class FeignClientInvoker {

    private final ApplicationContext applicationContext;
    private final Map<String, Object> feignClientCache = new HashMap<>();
    private final Map<String, Method> methodCache = new HashMap<>();

    public FeignClientInvoker(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    /**
     * 动态调用FeignClient方法
     * @param serviceName FeignClient的name属性值
     * @param methodName 要调用的方法名
     * @param args 方法参数
     * @return 调用结果
     */
    public Object invoke(String serviceName, String methodName, Object... args) {
        try {
            // 1. 获取FeignClient实例
            Object feignClient = getFeignClient(serviceName);
            
            // 2. 获取目标方法
            Method method = getTargetMethod(feignClient, methodName, args);
            
            // 3. 执行方法调用
            return method.invoke(feignClient, args);
        } catch (Exception e) {
            throw new RuntimeException("调用FeignClient失败: " + serviceName, e);
        }
    }

    private Object getFeignClient(String serviceName) {
        // 优先从缓存获取
        if (feignClientCache.containsKey(serviceName)) {
            return feignClientCache.get(serviceName);
        }
        
        // 动态查找标注@FeignClient的Bean
        Map<String, Object> feignClients = applicationContext.getBeansWithAnnotation(FeignClient.class);
        for (Object bean : feignClients.values()) {
            FeignClient annotation = bean.getClass().getInterfaces()[0].getAnnotation(FeignClient.class);
            if (annotation != null && serviceName.equals(annotation.name())) {
                feignClientCache.put(serviceName, bean);
                return bean;
            }
        }
        throw new IllegalArgumentException("未找到服务: " + serviceName);
    }

    private Method getTargetMethod(Object feignClient, String methodName, Object[] args) 
        throws NoSuchMethodException {
        
        String cacheKey = feignClient.getClass().getName() + "#" + methodName;
        
        // 缓存命中直接返回
        if (methodCache.containsKey(cacheKey)) {
            return methodCache.get(cacheKey);
        }
        
        // 获取参数类型
        Class<?>[] argTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
            argTypes[i] = args[i].getClass();
        }
        
        // 反射获取方法
        Method method = feignClient.getClass().getMethod(methodName, argTypes);
        methodCache.put(cacheKey, method);
        
        return method;
    }
}