/**
* Licensed Materials - Property of IBM* and/or HCL**
* IBM UrbanCode Deploy
* (c) Copyright IBM Corporation 2017. All Rights Reserved.
* (c) Copyright HCL Technologies Ltd. 2018. All Rights Reserved.
*
* U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
* GSA ADP Schedule Contract with IBM Corp.
*
* * Trademark of International Business Machines
* ** Trademark of HCL Technologies Limited
*/

package com.urbancode.air.plugin.webspherebpm

import com.urbancode.commons.httpcomponentsutil.CloseableHttpClientBuilder
import com.urbancode.commons.util.IO

import groovy.json.JsonSlurper
import java.io.IOException
import org.apache.commons.io.FilenameUtils
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.HttpStatus
import org.apache.http.client.methods.HttpGet
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.util.EntityUtils

public class WebSphereBPMRestAPIHelper {

    final String URL_PATH_SEPARATOR  = "/"
    final String REST_API_V1_PATH    = "/rest/bpm/wle/v1/"
    final String REST_API_REPO       = "/bpm/repo/projects/"

    String serverUrl
    String username
    String password
    boolean trustAllCerts
    CloseableHttpClient client

    private Map<String, File> tempDirs = new HashMap<String, File>()

    public WebSphereBPMRestAPIHelper(String serverUrl, String username, String password, boolean trustAllCerts) {
        while (serverUrl.endsWith(URL_PATH_SEPARATOR)) {
            serverUrl = serverUrl.substring(0, serverUrl.length() - 1)
        }

        this.serverUrl = serverUrl
        this.username  = username
        this.password  = password
        this.trustAllCerts = trustAllCerts
        initClient()
    }

    /**
     * result Creates the class's CloseableHttpClient. Only called during class creation.
     */
    private void initClient() {
        if (!client) {
            CloseableHttpClientBuilder builder = new CloseableHttpClientBuilder()
            if (username) {
                builder.setPreemptiveAuthentication(true)
                builder.setUsername(username)
                builder.setPassword(password)
            }
            builder.setTrustAllCerts(trustAllCerts)
            client = builder.buildClient()
        }
    }

    /**
     * result Closes client opened by initClient()
     */
    public void closeClient() {
        if (client) {
            client.close()
        }
    }

    /**
     * param processAppName The name of a Process Application
     * return JSON payload of the Process Application's identifying information and installed snapshots
     */
    public def getProcessApp(String processAppName) {
        def processApp
        println "[Action] Gathering information on Process Application `${processAppName}`"

        def processAppsList = getProcessAppsList()
        processAppsList.each{ it ->
            if (it.shortName == processAppName || it.name == processAppName) {
                processApp = it
            }
        }

        return processApp
    }

    /**
     * result Complete JSON payload of all Process Applications and their installed snapshots
     */
    private def getProcessAppsList() {
        def processAppsList

        // <https://ibmbpm:port>/rest/bpm/wle/v1/processApps
        String fullUrl = serverUrl + REST_API_V1_PATH + "processApps"
        URI procAppUri = new URI(fullUrl)

        HttpGet getRequest = new HttpGet(procAppUri.toString())
        getRequest.addHeader("Accept", "application/json")
        CloseableHttpResponse response = null
        def fullJson
        try {
            response = client.execute(getRequest)
            int status = response.getStatusLine().getStatusCode()
            if (status == 200) {
                String responseStr = EntityUtils.toString(response.getEntity())
                JsonSlurper slurper = new JsonSlurper()
                fullJson = slurper.parseText(responseStr)
            }
            else if (status == 401) {
                println "[Info] " + response.getStatusLine()
                throw new Exception("[Error] Invalid credentials.")
            }
            else {
                println "[Info] " + response.getStatusLine()
                throw new Exception("[Error] Unexpected error!")
            }

        } finally {
            if (response) {
                response.close()
            }
        }

        processAppsList = fullJson.data.processAppsList
        if (!processAppsList) {
            throw new Exception("[Error] Unable to find list of Process Applications: \n" + fullJson)
        }

        return processAppsList
    }

    /**
     * param projectId The Process Application's UUID from WebSphere BPM
     * param snapshotId The Snapshot's UUID to download
     * result The Snapshot's .twx file is downloaded and copied to <AGENT_HOME>/var/work/SourceConfig/UUID/export.twx
     * This REST API call is identical to the BPMExport command
     */
    public File downloadSnapshotTWX(String projectId, def snapshotId)
    throws IOException {
        // <https://serverUrl>/bpm/repo/projects/<projectId>/export?snapshot=<snapshotId>
        String fullUrl = serverUrl + REST_API_REPO + projectId + URL_PATH_SEPARATOR + "export?snapshot=" + snapshotId
        URI exportSnapshotUri = new URI(fullUrl)
        HttpGet getRequest = new HttpGet(exportSnapshotUri.toString())
        getRequest.addHeader("Accept", "application/zip")
        CloseableHttpResponse response = null
        try {
            response = client.execute(getRequest)
            int status = response.getStatusLine().getStatusCode()
            def fullJson
            if (status == 200) {
                File exportTwx = new File(getTempDir(snapshotId), "export.twx")
                IO.copy(response.getEntity().getContent(), exportTwx) // Note: Folder must be deleted later.
                println "[Info] Downloaded " + exportTwx.getCanonicalPath()
            }
            else if (status == 401) {
                println "[Info] " + response.getStatusLine()
                throw new Exception("[Error] Invalid credentials.")
            }
            else {
                println "[Info] " + response.getStatusLine()
                throw new Exception("[Error] Unexpected error!")
            }
        } finally {
            if (response) {
                response.close()
            }
        }

        return getTempDir(snapshotId)
    }

    /**
     * param version Snapshot/Version name identifying a folder created previously
     * result New folder in the Agent's temp directory
     */
    private File getTempDir(String version)
    throws IOException {
        File result = tempDirs.get(version)
        if (result == null) {
            result = new File( System.getProperty("user.dir"), UUID.randomUUID().toString())
            IO.mkdirs(result)
            tempDirs.put(version, result)
        }
        return result
    }
}
