package ru.yandex.qe.bus.servlet;

import java.util.Map;

import javax.annotation.Nullable;
import javax.servlet.ServletConfig;
import javax.servlet.annotation.WebServlet;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import ru.yandex.qe.bus.factories.BusEndpointBuilder;
import ru.yandex.qe.bus.factories.BusServerBuilderBean;
import ru.yandex.qe.spring.PropertyResolverBean;

import static org.springframework.web.context.support.WebApplicationContextUtils.getWebApplicationContext;

@WebServlet(
        urlPatterns = "/api/*",
        name = "bus-cxf-servlet",
        loadOnStartup = 1
)
public class SpringBusServlet extends CXFNonSpringServlet {

    private static final Logger LOG = LoggerFactory.getLogger(SpringBusServlet.class);

    protected void loadBus(ServletConfig servletConfig) {
        final ApplicationContext ctx = getWebApplicationContext(servletConfig.getServletContext());
        Map<String, BusServerBuilderBean> endpoints = ctx.getBeansOfType(BusServerBuilderBean.class);
        if (endpoints.isEmpty()) {
            endpoints = ctx.getParent().getBeansOfType(BusServerBuilderBean.class);
        }
        String endpointName = null;
        PropertyResolverBean propertyResolverBean = ctx.getBean(PropertyResolverBean.class);
        String name = getAppBusServerName(propertyResolverBean.getPropertyValue("qe.app.name"));
        if (endpoints.size() == 0) {
            throw new IllegalStateException("Not found an endpoint");
        } else if (endpoints.size() >= 1) {
            if (endpoints.containsKey(name)) {
                endpointName = name;
            } else if (endpoints.containsKey("&busServer")) {
                endpointName = "&busServer";
            }
        }
        if (endpointName == null) {
            throw new IllegalStateException("Not found an endpoint, expected '" + name.substring(1) + "' or 'busServer' bean");
        }
        BusEndpointBuilder endpoint = endpoints.get(endpointName);
        if (endpoint == null) {
            throw new IllegalStateException(String.format("Invalid endpoint - %s!", endpointName));
        }
        LOG.info("Using endpoint - {}.", endpointName);
        setBus(endpoint.getBus());
    }

    private String getAppBusServerName(String appName) {
        String springName = StringUtils.isBlank(appName) ? "" : Joiner.on("").join(Iterables.transform(Splitter.on("-").split(appName), new Function<String, String>() {

            boolean first = true;

            @Nullable
            @Override
            public String apply(String part) {
                if (first) {
                    first = false;
                    return part;
                } else {
                    return StringUtils.capitalize(part);
                }
            }
        }));
        return "&" + springName + "BusServer";
    }
}
