package com.sequenceiq.provisioning.service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sequenceiq.ambari.client.AmbariClient;
import com.sequenceiq.provisioning.controller.BadRequestException;
import com.sequenceiq.provisioning.controller.InternalServerException;
import com.sequenceiq.provisioning.controller.NotFoundException;
import com.sequenceiq.provisioning.controller.json.BlueprintJson;
import com.sequenceiq.provisioning.controller.json.ClusterRequest;
import com.sequenceiq.provisioning.controller.json.ClusterResponse;
import com.sequenceiq.provisioning.controller.json.JsonHelper;
import com.sequenceiq.provisioning.domain.Blueprint;
import com.sequenceiq.provisioning.domain.Stack;
import com.sequenceiq.provisioning.domain.User;
import com.sequenceiq.provisioning.repository.BlueprintRepository;
import com.sequenceiq.provisioning.repository.StackRepository;

import groovyx.net.http.HttpResponseException;

@Service
public class AmbariClusterService {

    private static final String PORT = "8080";

    @Autowired
    private JsonHelper jsonHelper;

    @Autowired
    private BlueprintRepository blueprintRepository;

    @Autowired
    private StackRepository stackRepository;

    public void createCluster(User user, Long stackId, ClusterRequest clusterRequest) {
        try {
            Stack stack = stackRepository.findOne(stackId);
            Blueprint blueprint = blueprintRepository.findOne(clusterRequest.getBlueprintId());
            addBlueprint(user, stackId, blueprint, clusterRequest);
            AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
            ambariClient.createCluster(
                    clusterRequest.getClusterName(),
                    blueprint.getName(),
                    ambariClient.recommendAssignments(blueprint.getName())
            );

        } catch (HttpResponseException e) {
            throw new InternalServerException("Failed to create cluster", e);
        }
    }

    public ClusterResponse retrieveCluster(User user, Long stackId) {
        Stack stack = stackRepository.findOne(stackId);
        AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
        try {
            return createClusterJsonFromString(ambariClient.getClusterAsJson());
        } catch (HttpResponseException e) {
            if ("Not Found".equals(e.getMessage())) {
                throw new NotFoundException("Ambari blueprint not found.", e);
            } else {
                throw new InternalServerException("Something went wrong", e);
            }
        } catch (IOException e) {
            throw new InternalServerException("Failed to parse cluster json coming from Ambari.", e);
        }
    }

    private ClusterResponse createClusterJsonFromString(String cluster) throws IOException {
        ClusterResponse clusterResponse = new ClusterResponse();
        clusterResponse.setCluster(jsonHelper.createJsonFromString(cluster));
        return clusterResponse;
    }

    public void addBlueprint(User user, Long stackId, Blueprint blueprint, ClusterRequest clusterRequest) {
        Stack stack = stackRepository.findOne(stackId);
        AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
        try {
            ambariClient.addBlueprint(blueprint.getBlueprintText());
        } catch (HttpResponseException e) {
            if ("Conflict".equals(e.getMessage())) {
                throw new BadRequestException("Ambari blueprint already exists.", e);
            } else if ("Bad Request".equals(e.getMessage())) {
                throw new BadRequestException("Failed to validate Ambari blueprint.", e);
            } else {
                throw new InternalServerException("Something went wrong", e);
            }
        }
    }

    public List<BlueprintJson> retrieveBlueprints(User user, Long stackId) {
        try {
            List<BlueprintJson> blueprints = new ArrayList<>();
            Stack stack = stackRepository.findOne(stackId);
            AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
            Set<String> blueprintNames = ambariClient.getBlueprintsMap().keySet();
            for (String blueprintName : blueprintNames) {
                blueprints.add(createBlueprintJsonFromString(ambariClient.getBlueprintAsJson(blueprintName)));
            }
            return blueprints;
        } catch (IOException e) {
            throw new InternalServerException("Jackson failed to parse blueprint JSON.", e);
        }
    }

    public BlueprintJson retrieveBlueprint(User user, Long stackId, String id) {
        Stack stack = stackRepository.findOne(stackId);
        AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
        try {
            return createBlueprintJsonFromString(ambariClient.getBlueprintAsJson(id));
        } catch (HttpResponseException e) {
            if ("Not Found".equals(e.getMessage())) {
                throw new NotFoundException("Ambari blueprint not found.", e);
            } else {
                throw new InternalServerException("Something went wrong", e);
            }
        } catch (IOException e) {
            throw new InternalServerException("Jackson failed to parse blueprint JSON.", e);
        }
    }

    private BlueprintJson createBlueprintJsonFromString(String blueprint) throws IOException {
        BlueprintJson blueprintJson = new BlueprintJson();
        blueprintJson.setAmbariBlueprint(jsonHelper.createJsonFromString(blueprint));
        return blueprintJson;
    }

    public String startAllService(User user, Long stackId) {
        Stack stack = stackRepository.findOne(stackId);
        AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
        //ambariClient.
        return "";
    }

    public String stopAllService(User user, Long stackId) {
        Stack stack = stackRepository.findOne(stackId);
        AmbariClient ambariClient = new AmbariClient(stack.getAmbariIp(), PORT);
        return "";
    }

}

@@ -35,24 +35,72 @@
 g.service;%0A%0A
+import groovyx.net.http.HttpResponseException;%0A%0A
 import java.
@@ -111,24 +111,24 @@
 OException;%0A
-
 import java.
@@ -1102,56 +1102,8 @@
 y;%0A%0A
-import groovyx.net.http.HttpResponseException;%0A%0A
 @Ser
@@ -1993,16 +1993,24 @@
 Name())%0A
+        
         
@@ -2016,16 +2016,16 @@
      );%0A
-
 %0A       
@@ -2393,74 +2393,387 @@
     
-return create
+String clusterJson = ambariClient.get
 Cluster
+As
 Json
-FromString(ambariClient.get
+();%0A            if (clusterJson == null) %7B%0A                throw new InternalServerException(String.format(%22Cluster response coming from Ambari server was null. %5BStack: '%25s', Ambari Server IP: '%25s'%5D%22,%0A                        stackId, stack.getAmbariIp()));%0A            %7D%0A            return create
 Cluster
-As
 Json
-()
+FromString(clusterJson
 );%0A 
@@ -6262,16 +6262,17 @@
       //
+ 
 ambariCl

throw internal exception when describe cluster reponse is null