package com.ytpm.utils;

import com.ytpm.config.GlobalFeignInterceptor;
import com.ytpm.handle.DynamicFeignClientFactory;
import com.ytpm.question.base.BaseFeign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
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<>();
    @Resource
    private DynamicFeignClientFactory feignClientFactory;

    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);
        }
        Object feignClient = null;
        try {
            // 默认查询声明实例
            // 动态查找标注@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);
                    feignClient = bean;
                }
            }
            // 构建动态FeignClient
            if (feignClient == null) {
                Class<?> clazz = com.ytpm.question.base.BaseFeign.class;
                if (serviceName.contains("ios")) {
                    clazz = com.ytpm.lemonios.feign.base.BaseFeign.class;
                }
                feignClient = feignClientFactory.getClient(serviceName, clazz);
            }
            feignClientCache.put(serviceName, feignClient);
        } catch (Exception e) {
            throw new IllegalArgumentException("未找到服务: " + serviceName);
        }
        if (feignClient == null) {
            throw new IllegalArgumentException("未找到服务: " + serviceName);
        }
        return feignClient;
    }


    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;
    }
}