package org.wildfly.test.suspendresumeendpoint;

import java.util.concurrent.atomic.AtomicInteger;
import org.jboss.as.network.SocketBindingManager;
import org.wildfly.extension.requestcontroller.ControlPoint;
import org.wildfly.extension.requestcontroller.RequestController;
import org.wildfly.extension.requestcontroller.RunResult;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;

import io.undertow.Undertow;
import io.undertow.server.ExchangeCompletionListener;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;

/**
 * @author Stuart Douglas
 */
public class TestUndertowService implements Service<TestUndertowService> {


    private static final AtomicInteger COUNT = new AtomicInteger();


    public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("test-undertow-server");
    public static final String SKIP_GRACEFUL = "skip-graceful";

    private volatile Undertow undertow;
    private final InjectedValue<RequestController> requestControllerInjectedValue = new InjectedValue<>();
    private final InjectedValue<SocketBindingManager> socketBindingManagerInjectedValue = new InjectedValue<>();

    @Override
    public void start(StartContext context) throws StartException {        //add graceful shutdown support
        final SuspendResumeHandler suspendResumeHandler = new SuspendResumeHandler();
        final ControlPoint controlPoint = requestControllerInjectedValue.getValue().getControlPoint("test", "test");

        final ExchangeCompletionListener exchangeCompletionListener = new ExchangeCompletionListener() {
            @Override
            public void exchangeEvent(HttpServerExchange exchange, NextListener nextListener) {
                controlPoint.requestComplete();
                nextListener.proceed();
            }
        };

        HttpHandler shutdown = new HttpHandler() {
            @Override
            public void handleRequest(final HttpServerExchange exchange) throws Exception {
                if(exchange.isInIoThread()) {
                    exchange.dispatch(this);
                    return;
                }
                final int count = COUNT.incrementAndGet();
                if(exchange.getQueryParameters().containsKey(SKIP_GRACEFUL)) {
                    //bit of a hack, allows to send in some requests even when the server is paused
                    //very useful for testing
                    System.out.println("Skipping request " + count + " " + exchange);
                    suspendResumeHandler.handleRequest(exchange);
                    return;
                }
                System.out.println("Attempting " + count + " " + exchange);
                RunResult result = controlPoint.beginRequest();
                if (result == RunResult.REJECTED) {
                    exchange.dispatch(new Runnable() {
                        @Override
                        public void run() {
                            controlPoint.queueTask(new Runnable() {
                                @Override
                                public void run() {
                                    exchange.addExchangeCompleteListener(exchangeCompletionListener);
                                    exchange.dispatch(suspendResumeHandler);
                                }
                            }, exchange.getIoThread(), 1000, new Runnable() {
                                @Override
                                public void run() {
                                    System.out.println("Rejected " + count + " " + exchange);
                                    exchange.setStatusCode(503);
                                    exchange.endExchange();
                                }
                            }, true);
                        }
                    });

                    return;
                }
                exchange.addExchangeCompleteListener(exchangeCompletionListener);
                suspendResumeHandler.handleRequest(exchange);
            }
        };
        undertow = Undertow.builder().addHttpListener(8080 + socketBindingManagerInjectedValue.getValue().getPortOffset(), "0.0.0.0").setHandler(shutdown).build();
        undertow.start();
    }

    @Override
    public void stop(StopContext context) {
        undertow.stop();
        undertow = null;
    }

    @Override
    public TestUndertowService getValue() throws IllegalStateException, IllegalArgumentException {
        return this;
    }

    public InjectedValue<RequestController> getRequestControllerInjectedValue() {
        return requestControllerInjectedValue;
    }

    public InjectedValue<SocketBindingManager> getSocketBindingManagerInjectedValue() {
        return socketBindingManagerInjectedValue;
    }
}
