package com.kingdee.eas.custom.integration.apimgt.sync;

import com.kingdee.eas.custom.integration.base.annotation.ApiDoc;
import com.kingdee.eas.custom.integration.base.annotation.SkipAuth;
import com.kingdee.eas.custom.integration.base.annotation.SkipCallLog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
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.LinkedHashMap;
import java.util.Map;
import java.util.Set;

/**
 * Spring MVC 接口扫描器，从 RequestMappingHandlerMapping 中提取已注册的 Controller 接口。
 * 同时读取 @SkipAuth、@SkipCallLog、@ApiDoc 注解状态，用于同步到 ApiRegistryBill。
 */
public class ApiScanner {

    private static final Logger logger = LoggerFactory.getLogger(ApiScanner.class);

    private static final String SCAN_PACKAGE = "com.kingdee.eas.custom.integration";

    /**
     * 扫描指定包下的所有 API 接口端点。
     *
     * @param handlerMapping Spring MVC 映射注册表
     * @return Map，key 为 "path#METHOD"
     */
    public Map<String, ApiEndpoint> scan(RequestMappingHandlerMapping handlerMapping) {
        Map<String, ApiEndpoint> result = new LinkedHashMap<>();

        if (handlerMapping == null) {
            logger.warn("RequestMappingHandlerMapping 不可用，跳过 API 扫描");
            return result;
        }

        Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
        logger.info("开始扫描 Spring MVC 接口，共 {} 个 handler", handlerMethods.size());

        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            HandlerMethod handlerMethod = entry.getValue();
            Class<?> beanType = handlerMethod.getBeanType();

            if (!beanType.getName().startsWith(SCAN_PACKAGE)) {
                continue;
            }

            RequestMappingInfo mappingInfo = entry.getKey();
            Set<String> patterns = mappingInfo.getPatternsCondition().getPatterns();
            Set<org.springframework.web.bind.annotation.RequestMethod> methods =
                    mappingInfo.getMethodsCondition().getMethods();

            Method method = handlerMethod.getMethod();
            boolean skipAuth = isSkipAuth(method, beanType);
            boolean isSkipCallLog = isSkipCallLog(method, beanType);
            String apiName = buildApiName(method, beanType);
            String apiDesc = buildApiDesc(method, beanType);

            for (String pattern : patterns) {
                String fullPath = "/qy" + normalizePath(pattern);
                ApiEndpoint endpoint = new ApiEndpoint(
                        fullPath, "GET", apiName, apiDesc, !skipAuth, isSkipCallLog);
                if (methods.isEmpty()) {
                    result.put(fullPath + "#GET", endpoint);
                } else {
                    for (org.springframework.web.bind.annotation.RequestMethod rm : methods) {
                        endpoint = new ApiEndpoint(
                                fullPath, rm.name(), apiName, apiDesc, !skipAuth, isSkipCallLog);
                        result.put(fullPath + "#" + rm.name(), endpoint);
                    }
                }
            }
        }

        logger.info("API 扫描完成，共找到 {} 个接口端点", result.size());
        return result;
    }

    /**
     * 从 @ApiDoc 注解读取接口名称，无注解则回退为 ClassName.methodName。
     */
    private String buildApiName(Method method, Class<?> beanType) {
        ApiDoc apiDoc = method.getAnnotation(ApiDoc.class);
        if (apiDoc != null && !apiDoc.name().isEmpty()) {
            return apiDoc.name();
        }
        return beanType.getSimpleName() + "." + method.getName();
    }

    /**
     * 从 @ApiDoc 注解读取接口描述，无注解则回退为 ClassName.methodName。
     */
    private String buildApiDesc(Method method, Class<?> beanType) {
        ApiDoc apiDoc = method.getAnnotation(ApiDoc.class);
        if (apiDoc != null && !apiDoc.desc().isEmpty()) {
            return apiDoc.desc();
        }
        return beanType.getSimpleName() + "." + method.getName();
    }

    /**
     * 判断是否跳过认证（方法或类上有 @SkipAuth 注解）。
     */
    private boolean isSkipAuth(Method method, Class<?> beanType) {
        if (method.isAnnotationPresent(SkipAuth.class)) {
            return true;
        }
        if (beanType.isAnnotationPresent(SkipAuth.class)) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否跳过调用日志（方法或类上有 @SkipCallLog 注解）。
     */
    private boolean isSkipCallLog(Method method, Class<?> beanType) {
        if (method.isAnnotationPresent(SkipCallLog.class)) {
            return true;
        }
        if (beanType.isAnnotationPresent(SkipCallLog.class)) {
            return true;
        }
        return false;
    }

    private String normalizePath(String path) {
        if (path == null || path.isEmpty()) {
            return "/";
        }
        path = path.replaceAll("/{2,}", "/");
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        return path;
    }
}
