package nl.jpoint.vertx.mod.cluster.handler;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import io.netty.handler.codec.http.HttpResponseStatus;
import nl.jpoint.vertx.mod.cluster.Constants;
import nl.jpoint.vertx.mod.cluster.request.DeployArtifactRequest;
import nl.jpoint.vertx.mod.cluster.request.DeployModuleRequest;
import nl.jpoint.vertx.mod.cluster.request.DeployRequest;
import nl.jpoint.vertx.mod.cluster.service.AwsService;
import nl.jpoint.vertx.mod.cluster.service.DeployModuleService;
import nl.jpoint.vertx.mod.cluster.service.DeployService;
import nl.jpoint.vertx.mod.cluster.util.LogConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.vertx.java.core.Handler;
import org.vertx.java.core.buffer.Buffer;
import org.vertx.java.core.http.HttpServerRequest;

import java.io.IOException;

public class RestDeployHandler implements Handler<HttpServerRequest> {

    private final ObjectReader reader = new ObjectMapper().reader(DeployRequest.class);
    private final DeployService moduleDeployService;
    private final DeployService artifactDeployService;
    private final AwsService awsService;

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

    public RestDeployHandler(final DeployService moduleDeployService, final DeployService artifactDeployService, AwsService awsService) {
        MDC.put("service", Constants.SERVICE_ID);
        this.moduleDeployService = moduleDeployService;
        this.artifactDeployService = artifactDeployService;
        this.awsService = awsService;
    }
    @Override
    public void handle(final HttpServerRequest request) {
        request.bodyHandler(new Handler<Buffer>() {
            @Override
            public void handle(Buffer event) {

                DeployRequest deployRequest;

                if (event.getBytes() == null || event.getBytes().length == 0) {
                    LOG.error("{}: No postdata in request.", LogConstants.DEPLOY_REQUEST);
                    respondFailed(request);
                    return;
                }
                try {
                    deployRequest = reader.readValue(event.getBytes());
                } catch (IOException e) {
                    LOG.error("{}: Error while reading postdata -> {}.", LogConstants.DEPLOY_REQUEST, e.getMessage());
                    respondFailed(request);
                    return;
                }

                LOG.info("[{} - {}]: Received deploy request with {} module(s) and {} artifact(s) ", LogConstants.DEPLOY_REQUEST, deployRequest.getId().toString(), deployRequest.getModules().size(), deployRequest.getArtifacts().size());

                boolean deployOk = false;


                if (deployRequest.withAws()) {
                    if (awsService.registerRequest(deployRequest)) {
                        respondContinue(request, deployRequest.getId().toString());
                        awsService.deRegisterInstance(deployRequest.getId().toString());
                    }   else {
                        respondFailed(request);
                    }
                    return;
                }

                if (deployRequest.withRestart()) {
                    ((DeployModuleService) moduleDeployService).stopContainer(deployRequest.getId().toString());
                }

                for (DeployModuleRequest moduleRequest : deployRequest.getModules()) {
                    deployOk = moduleDeployService.deploy(moduleRequest);

                    if (!deployOk) {
                        respondFailed(request);
                        return;
                    }
                }


                if (deployOk || deployRequest.getModules().size() == 0) {
                    for (DeployArtifactRequest artifactRequest : deployRequest.getArtifacts()) {
                        deployOk = artifactDeployService.deploy(artifactRequest);

                        if (!deployOk) {
                            respondFailed(request);
                            return;
                        }
                    }
                }

                respondOk(request);
            }
        });
    }

    private void respondOk(HttpServerRequest request) {
        request.response().setStatusCode(HttpResponseStatus.OK.code());
        request.response().end();
    }

    private void respondContinue(HttpServerRequest request, String id) {
        request.response().setStatusCode(HttpResponseStatus.OK.code());
        request.response().setStatusMessage(id);
        request.response().end(id);
    }

    private void respondFailed(HttpServerRequest request) {
        request.response().setStatusCode(HttpResponseStatus.INTERNAL_SERVER_ERROR.code());
        request.response().end();
    }
}

@@ -3427,28 +3427,32 @@
 ploy
-ModuleRequest module
+ArtifactRequest artifact
 Requ
@@ -3474,22 +3474,24 @@
 uest.get
-Module
+Artifact
 s()) %7B%0A 
@@ -3520,22 +3520,24 @@
 loyOk = 
-module
+artifact
 DeploySe
@@ -3549,22 +3549,24 @@
 .deploy(
-module
+artifact
 Request)
@@ -3726,17 +3726,16 @@
      %7D%0A%0A
-%0A
         
@@ -3767,38 +3767,40 @@
 eployRequest.get
-Module
+Artifact
 s().size() == 0)
@@ -3837,32 +3837,28 @@
 ploy
-ArtifactRequest artifact
+ModuleRequest module
 Requ
@@ -3876,32 +3876,30 @@
 yRequest.get
-Artifact
+Module
 s()) %7B%0A     
@@ -3924,32 +3924,30 @@
  deployOk = 
-artifact
+module
 DeployServic
@@ -3951,32 +3951,30 @@
 vice.deploy(
-artifact
+module
 Request);%0A%0A 

Deploy artifacts first, then modules. This way, modules can depend on contents of artifacts.