package cn.fateverse.query.portal.service;

import cn.fateverse.common.core.exception.CustomException;
import cn.fateverse.common.core.utils.SpringContextHolder;
import cn.fateverse.query.dubbo.DubboDispatchServletPublish;
import cn.fateverse.query.portal.PortalDispatchServlet;
import cn.fateverse.query.portal.config.DubboServiceBean;
import cn.fateverse.query.portal.event.DispatchSyncEvent;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.cloud.nacos.registry.NacosRegistration;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.rpc.RpcContext;
import org.apache.dubbo.rpc.RpcContextAttachment;
import org.apache.dubbo.rpc.cluster.specifyaddress.Address;
import org.apache.dubbo.rpc.cluster.specifyaddress.UserSpecifiedAddressUtil;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author Clay
 * @date 2024/4/12 16:56
 */
@Slf4j
@Component
public class HandlerMethodService implements ApplicationContextAware {

    public static final String CUSTOM_INTERFACE = "customInterface:";

    private RequestMappingHandlerMapping mapping;

    private Method mappingMethod;


    public HandlerMethodService() {
        //固定PortalDispatchServlet为入口类,其中doDispatch为入口方法
        Class<PortalDispatchServlet> portalDispatchServletClass = PortalDispatchServlet.class;
        Method[] declaredMethods = portalDispatchServletClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            if ("doDispatch".equals(declaredMethod.getName())) {
                mappingMethod = declaredMethod;
            }
        }
        if (mappingMethod == null) {
            log.error("mappingMethod is null");
        }
        //设置权限
        mappingMethod.setAccessible(Boolean.TRUE);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        //获取到web mvc的接口存储mapping
        mapping = (RequestMappingHandlerMapping) applicationContext.getBean("requestMappingHandlerMapping");
    }

    /**
     * 注册映射接口
     *
     * @param path          接口路径
     * @param requestMethod 请求方法
     */
    public void registerMapping(String path, RequestMethod requestMethod, Boolean sync) {
        String[] empty = {};
        RequestMappingInfo.Builder builder = RequestMappingInfo
                .paths(path)
                .methods(requestMethod)
                .params(empty)
                .headers(empty)
                .consumes(empty)
                .produces(empty)
                .mappingName(CUSTOM_INTERFACE + path);
        RequestMappingInfo requestMappingInfo = builder.options(mapping.getBuilderConfiguration()).build();
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
        if (handlerMethods.containsKey(requestMappingInfo)) {
            throw new CustomException("path is exist");
        }
        mapping.registerMapping(requestMappingInfo, "portalDispatchServlet", mappingMethod);
        // 判断是否需要发起同步
        if (sync) {
            //使用事件监听机制,避免循环注入
            SpringContextHolder.publishEvent(new DispatchSyncEvent(path, requestMethod.name(), Boolean.TRUE));
        }
    }

    /**
     * 卸载映射接口
     *
     * @param path          接口路径
     * @param requestMethod 请求类型
     */
    public void unregisterMapping(String path, RequestMethod requestMethod, Boolean sync) {
        Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
        for (RequestMappingInfo mappingInfo : handlerMethods.keySet()) {
            if (!ObjectUtils.isEmpty(mappingInfo.getName())
                    && (CUSTOM_INTERFACE + path).equals(mappingInfo.getName())
                    && mappingInfo.getMethodsCondition().getMethods().contains(requestMethod)) {
                mapping.unregisterMapping(mappingInfo);
                if (sync) {
                    SpringContextHolder.publishEvent(new DispatchSyncEvent(path, requestMethod.name(), Boolean.FALSE));
                }
            }
        }
    }


}
