/*
* Licensed Materials - Property of IBM Corp.
* IBM UrbanCode Build
* (c) Copyright IBM Corporation 2015. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*/
import com.urbancode.air.CommandHelper

import groovy.json.JsonSlurper
import org.apache.http.HttpEntity
import org.apache.http.util.EntityUtils
import org.codehaus.jettison.json.JSONObject

import org.apache.http.HttpResponse
import org.apache.http.client.HttpClient
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.StringEntity
import org.apache.http.entity.ContentType

import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder
import com.urbancode.commons.util.IO
import com.urbancode.commons.web.util.PercentCodec;

class StatusHelper extends HelperBase {
    String authToken = System.getenv("AUTH_TOKEN")
    String webUrl = System.getenv("WEB_URL")

    public StatusHelper() {
        webUrl += webUrl.endsWith("/") ? "" : "/"
    }


    public StatusBase checkUCBStatus(def statusName) {
        StatusBase statusObject = null

        String urlStatusName = new PercentCodec().encode(statusName);

        String statusRestUrl = webUrl + "rest2/statuses/${urlStatusName}"

        println "Checking status '${statusName}' in the IBM UrbanCode Build server"

        HttpGet getMethod = new HttpGet(statusRestUrl)
        if (authToken) {
            getMethod.addHeader("Authorization-Token", authToken)
        }

        HttpClientBuilder builder = new HttpClientBuilder()
        builder.setTrustAllCerts(true)
        HttpClient client = builder.buildClient()
        HttpResponse response = client.execute(getMethod)

        def responseCode = response.statusLine.statusCode
        HttpEntity entity = response.getEntity()
        String content = EntityUtils.toString(entity, IO.utf8())

        if (!isGoodResponseCode(responseCode)) {
            println "Failed to get status '${statusName}' from IBM UrbanCode Build server: $content"
        }
        else {
            def jsonResult = new JSONObject(content)
            String name = jsonResult['name']
            String desc = jsonResult['description']
            if (jsonResult.isNull('description')) {
                desc = null
            }

            String color = jsonResult['color']
            statusObject = new StatusBase(name, desc, color)
            println "Get status '${statusName}' from IBM UrbanCode Build server"
        }

        getMethod.releaseConnection()

        return statusObject
    }

    public StatusBase checkUCDStatus(String jsonText, def statusName) {
        StatusBase statusObject = null

        def status = new JsonSlurper().parseText(jsonText).find { it.name == statusName }
        if (status != null) {
            def name = status['name']
            def desc = status['description']
            def color = status['color']
            statusObject = new StatusBase(name, desc, color)
        }

        return statusObject;
    }

    public boolean createStatusInBuild(StatusBase status) {
        def boolean isSuccessful = true

        def statusName = status.getName()
        String statusRestUrl = webUrl + "rest2/statuses"

        println "Creating status '${statusName}' in the IBM UrbanCode Build server"

        HttpPost postMethod = new HttpPost(statusRestUrl)
        def json = new JSONObject()
        json.put('name', statusName)
        json.put('description', status.getDescription())
        json.put('color', status.getColor())
        postMethod.setEntity(new StringEntity(json.toString(), ContentType.APPLICATION_JSON));
        if (authToken) {
            postMethod.addHeader("Authorization-Token", authToken)
        }

        HttpClientBuilder builder = new HttpClientBuilder()
        builder.setTrustAllCerts(true)
        HttpClient client = builder.buildClient()
        HttpResponse response = client.execute(postMethod)
        def responseCode = response.statusLine.statusCode
        InputStream responseStream = response.entity.content

        String changesXml = IO.readText(responseStream)

        if (!isGoodResponseCode(responseCode)) {
            println "Failed to create status '${statusName}' in the IBM UrbanCode Build server: $changesXml"
            isSuccessful = false
        }

        postMethod.releaseConnection()

        return isSuccessful;
    }

    public boolean createStatusInDeploy(StatusBase status) {
        boolean isSuccessful = true
        String statusName = status.getName()
        String statusDesc = status.getDescription()

        CommandHelper helper = getCommandHelper()
        def command = [javaFile.absolutePath, '-jar', udClientJarFile.absolutePath,
                       "--weburl", url,
                       "createStatus",
                       "--type", "version",
                       "--status", statusName,
                       "--color", status.getColor()
        ]
        // when a field is empty, uBuild rest shows "description":null,but uDeploy rest shows "description":"",
        // if you put the null to uDeply, uDeploy will show "description":"null", so if desc==null, we will skip it.
        if (statusDesc) {
            command << "--description" << statusDesc
        }

        addCredentials(command)

        def statusOutput = ""
        try {
            helper.ignoreExitValue(true)
            int exitCode = helper.runCommand("Creating version status '${statusName}' in the IBM UrbanCode Deploy server", command) { proc ->
                proc.out.close()
                Thread t = proc.consumeProcessErrorStream(System.out)
                statusOutput = proc.in.text.trim()
                t.join(10000L)
            }
            helper.ignoreExitValue(false)

            if (exitCode != 0) {
                isSuccessful = false
                println "Failed to create status '${statusName}' in the IBM UrbanCode Deploy server: $statusOutput"
            }
        }
        catch (Exception e) {
            println "Failed to create status '${statusName}' in the IBM UrbanCode Deploy server: $statusOutput"
            System.exit(1)
        }

        return isSuccessful;
    }

    protected def syncStatusBetweenBuildAndDeploy(StatusBase statusFoundInBuild, StatusBase statusFoundInDeploy, def statusName) {
        if (statusFoundInBuild == null && statusFoundInDeploy != null) {
            def isCreateSuccess = createStatusInBuild(statusFoundInDeploy)
            if (!isCreateSuccess) {
                println "WARN - Failed to sync status '${statusName}' to IBM UrbanCode Build server. Please ensure server's version is 6.1.2.2 or higher."
            }
        }
        else if (statusFoundInBuild != null && statusFoundInDeploy == null) {
             def isCreateSuccess = createStatusInDeploy(statusFoundInBuild)
             if (!isCreateSuccess) {
                 println "Failed to sync status '${statusName}' to IBM UrbanCode Deploy server."
                 System.exit(1)
             }
        }
        else if (statusFoundInBuild == null && statusFoundInDeploy == null) {
             println "Can't find status '${statusName}' in the IBM UrbanCode Deploy server or the IBM UrbanCode Build server."
             System.exit(1)
        }
    }

    protected boolean isGoodResponseCode(int responseCode) {
        return responseCode >= 200 && responseCode < 300;
    }
}
