/*
 * Copyright (c) eHealth
 */
package be.fgov.ehealth.technicalconnector.tests.server;


import be.fgov.ehealth.technicalconnector.tests.server.asserter.HttpAsserter;
import be.fgov.ehealth.technicalconnector.tests.server.callback.AssertExpectationCallback;
import be.fgov.ehealth.technicalconnector.tests.server.callback.ContentExpectationCallback;
import be.fgov.ehealth.technicalconnector.tests.server.callback.EchoExpectationCallback;
import be.fgov.ehealth.technicalconnector.tests.server.callback.ErrorExpectationCallback;
import be.fgov.ehealth.technicalconnector.tests.server.callback.FullExpectationCallback;
import be.fgov.ehealth.technicalconnector.tests.server.callback.TimeOutExpectationCallback;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.mock.action.ExpectationCallback;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.apache.commons.lang3.StringUtils.startsWith;
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
import static org.mockserver.model.HttpClassCallback.callback;
import static org.mockserver.model.HttpRequest.request;

public class HttpServerStub {

    private Map<String, ExpectationCallback> callbackMap = new HashMap<String, ExpectationCallback>();

    private static ClientAndServer mockClient;
    private int port;

    public HttpServerStub(int port) throws Exception {
        mockClient = startClientAndServer(port);
        this.port = port;
    }

    public void shutdown() throws Exception {
        mockClient.stopAsync().get(30, TimeUnit.SECONDS);
        callbackMap.clear();
        FullExpectationCallback.reset();
        ContentExpectationCallback.reset();
        AssertExpectationCallback.reset();
    }

    public void reset() {
        mockClient.reset();
    }


    public void add(String path, String content) {
        if (callbackMap.containsKey(path)) {
            ExpectationCallback callback = callbackMap.get(path);
            if (callback instanceof ContentExpectationCallback) {
                ContentExpectationCallback.add(path, content);
            }
            if (callback instanceof FullExpectationCallback) {
                FullExpectationCallback.add(path, content);
            }
        } else {
            ExpectationCallback callback;
            if (startsWith(path, "/echo")) {
                callback = new EchoExpectationCallback();
            } else if (startsWith(path, "/error")) {
                callback = new ErrorExpectationCallback();
            } else if (startsWith(path, "/timeout")) {
                callback = new TimeOutExpectationCallback();
            } else if (startsWith(path, "/full")) {
                callback = new FullExpectationCallback();
                FullExpectationCallback.add(path, content);
            } else {
                callback = new ContentExpectationCallback();
                ContentExpectationCallback.add(path, content);
            }

            register(path, callback);
        }
    }

    private void register(String path, ExpectationCallback callback) {
        callbackMap.put(path, callback);


        mockClient.when(
                request().withPath(path).withMethod("POST")
        ).respond(
                callback().withCallbackClass(callback.getClass().getName())
        );
    }

    public void add(String path, HttpAsserter asserter) {
        if (startsWith(path, "/assert")) {
            register(path, new AssertExpectationCallback());
            AssertExpectationCallback.addAsserter(asserter);
            return;
        }
        throw new IllegalArgumentException("Unsupported url pattern [" + path + "]");

    }

    @Override
    public String toString() {
        return "HttpServerStub{" +
                "callbackMap=" + callbackMap.keySet() +
                ", port=" + port +
                '}';
    }
}
