package ru.yandex.qe.dispenser.ws.intercept;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxrs.model.ClassResourceInfo;
import org.apache.cxf.jaxrs.model.MethodInvocationInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfo;
import org.apache.cxf.jaxrs.model.OperationResourceInfoStack;
import org.apache.cxf.jaxrs.model.URITemplate;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.springframework.stereotype.Component;

@Component
public class EndpointMemoization extends InterceptorBase<Message> {

    protected EndpointMemoization() {
        super(Phase.POST_INVOKE);
    }

    @Override
    public void handleMessage(final Message message) throws Fault {
        final OperationResourceInfo resourceInfo = getResourceInfo(message);
        final String basePath = (String) message.getContextualProperty(Message.BASE_PATH);
        final String endpoint = getEndpoint(basePath, resourceInfo);
        if (endpoint == null) {
            return;
        }
        final Object httpRequest = message.getContextualProperty(AbstractHTTPDestination.HTTP_REQUEST);
        if (httpRequest instanceof HttpServletRequest) {
            ((HttpServletRequest) httpRequest).setAttribute(AccessLogFilter.ENDPOINT, endpoint);
        }
    }

    private OperationResourceInfo getResourceInfo(final Message message) {
        final OperationResourceInfoStack infoStack = message.get(OperationResourceInfoStack.class);
        if (infoStack == null || infoStack.isEmpty()) {
            return null;
        }
        final MethodInvocationInfo methodInvocationInfo = infoStack.peek();
        return methodInvocationInfo != null ? methodInvocationInfo.getMethodInfo() : null;
    }

    private String getClassPath(final OperationResourceInfo resourceInfo) {
        final ClassResourceInfo classResourceInfo = resourceInfo.getClassResourceInfo();
        if (classResourceInfo == null) {
            return null;
        }
        final URITemplate uriTemplate = classResourceInfo.getURITemplate();
        return uriTemplate != null ? uriTemplate.getValue() : null;
    }

    private String getEndpoint(final String basePath, final OperationResourceInfo resourceInfo) {
        if (resourceInfo == null) {
            return null;
        }
        final String method = StringUtils.defaultString(resourceInfo.getHttpMethod());
        final String classPath = StringUtils.defaultString(getClassPath(resourceInfo));
        final URITemplate uriTemplate = resourceInfo.getURITemplate();
        final String methodPath = StringUtils.defaultString(uriTemplate != null ? uriTemplate.getValue() : null);
        return method + " " + StringUtils.defaultString(basePath) + classPath + methodPath;
    }

}
