package cc.smtweb.framework.core.mvc.controller.scan;

import cc.smtweb.framework.core.annotation.SwAction;
import cc.smtweb.framework.core.mvc.controller.ApiConfigBean;
import cc.smtweb.framework.core.mvc.controller.access.MethodAccess;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Method;

/**
 * URL构造器，用于API的访问路径构造
 *
 * @author xkliu
 */
@Slf4j
class UrlMaker {
    private static final String SERVICE_SUFFIX = "Service";

    private final ApiConfigBean apiConfig;
    @Getter
    private final String module;
    private String serviceUrl;

    UrlMaker(ApiConfigBean apiConfig, String module) {
        this.apiConfig = apiConfig;
        this.module = module;
    }

    private String getServiceName(Class clazz) {
        String simpleName = clazz.getSimpleName();
        if (simpleName.endsWith(SERVICE_SUFFIX)) {
            simpleName = simpleName.substring(0, simpleName.length() - SERVICE_SUFFIX.length());
        }

        return simpleName;
    }

    /**
     * 添加API映射到BeanManager，API的url先取SwApi配置的值，然后取SwService配置的值+“/”+方法名，最后使用默认规则: “服务名” / "方法名"
     * url都以模块名开头，避免应用模块服务名称重复
     *
     * @param clazz        服务类
     * @param method       执行方法，用于映射API
     * @param methodAccess 方法实际执行
     * @param controllers  控制器管理容器
     */
    void addApi(Class<?> clazz, Method method, MethodAccess methodAccess, BeanManager controllers) {
        String serviceName = getServiceName(clazz);
        String methodName = method.getName();
        String urlPrefix = module + "/";
        SwAction swAction = method.getAnnotation(SwAction.class);

        if (swAction != null && StringUtils.isNotBlank(swAction.value())) {
            // SwApi设置了URL
            mappingApi(methodAccess, controllers, urlPrefix + swAction.value());
        } else if (this.serviceUrl != null) {
            // SwService设置了URL
            mappingApi(methodAccess, controllers, urlPrefix + this.serviceUrl + "/" + methodName);
        } else {
            // 小驼峰路径
            String littleCamelCaseUrl = urlPrefix + toLittleCamelName(serviceName) + "/" + methodName;

            if (mappingApi(methodAccess, controllers, littleCamelCaseUrl)) {
                // 大驼峰路径，类原名
                if (apiConfig.isBigCameCaseUrl()) {
                    mappingApi(methodAccess, controllers, urlPrefix + serviceName + "/" + methodName);
                }

                // 小写服务名路径
                if (apiConfig.isLowerCaseUrl()) {
                    mappingApi(methodAccess, controllers, urlPrefix + serviceName.toLowerCase() + "/" + methodName);
                }
            }
        }
    }

    private String toLittleCamelName(String serviceName) {
        return Character.toLowerCase(serviceName.charAt(0))
                + serviceName.substring(1);
    }

    private boolean mappingApi(MethodAccess methodAccess, BeanManager controllers, String url) {
        if (controllers.putIfAbsent(url, methodAccess) != null) {
            log.error("url is repeat: " + url + ", " + methodAccess.controllerFullName());
            return false;
        }

        log.debug("[smt]init: " + url + ", " + methodAccess.controllerFullName());
        return true;
    }

    void setServiceUrl(String value) {
        this.serviceUrl = StringUtils.trimToNull(value);
    }
}
