/*
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Deploy
 * IBM Urbancode Release
 * (c) Copyright IBM Corporation 2016, 2017. All Rights Reserved.
 *
 * U.S. Government Users Restricted Rights - Use, duplication or disclosure restricted by
 * GSA ADP Schedule Contract with IBM Corp.
 */

package com.urbancode.air.plugin.openshift

import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPatch
import org.apache.http.client.methods.HttpPost
import org.apache.http.client.methods.HttpPut
import org.apache.http.client.methods.HttpUriRequest
import org.apache.http.entity.StringEntity
import org.apache.http.HttpEntity
import org.apache.http.HttpResponse
import org.apache.http.util.EntityUtils

import com.urbancode.air.XTrustProvider
import com.urbancode.commons.httpcomponentsutil.HttpClientBuilder

public class OpenShiftRestHelper {
    def client
    def disableCerts
    def insecure
    def project
    def token
    def url
    def username
    def password

    // Replace DeployConfig parameters
    def configJSON

    // Replace parameters
    def config
    def configFile

    // Create/Patch Secrets parameters
    def appSecret
    def pullSecret
    def httpCode
    def secretJSON
    def serviceAccount

    public OpenShiftRestHelper(props) {

        this.config = props['config']
        this.configFile = props['configFile']
        this.insecure = props['insecure']
        this.url = props['url']
        this.disableCerts = props['disableCerts']
        this.httpCode = props['httpCode']
        this.pullSecret = props['pullSecret']
        this.appSecret = props['appSecret']
        this.secretJSON = props['secretJSON']?.trim()
        this.configJSON = props['configJSON']?.trim()
        this.serviceAccount = props['serviceAccount']
        this.project = props['project']
        this.username = props['username']
        this.password = props['password']
        this.token = props['token']

        if (!url.endsWith("/")) {
            url += "/"
        }

        HttpClientBuilder builder = new HttpClientBuilder()

        if (disableCerts) {
            XTrustProvider.install()
            builder.setTrustAllCerts(true)
        }
        this.client = builder.buildClient()

        if (!insecure) {
            System.setProperty("https.protocols", "TLSv1")
        }

        // If token not provided as a parameter, get a session token based on username/password.
        if (!this.token)
            this.token = getToken()
    }

    public String getToken() {
        String token = null
        String encoding = ("${username}:${password}").getBytes().encodeBase64().toString()
        HttpGet tokenRequest = new HttpGet(url + "oauth/token/request")
        tokenRequest.addHeader("Content-Type", "application/x-www-form-urlencoded")
        tokenRequest.addHeader("Accept", "application/json,application/xml")
        tokenRequest.addHeader("Authorization","Basic " + encoding)
        HttpResponse response = client.execute(tokenRequest)

        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()
        println "code: " + statusCode
        if (statusCode != 200) {
            println("[Error] Token retrieval failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.getText("UTF-8"))
        }
        else {
            println("[OK] Token retrieval was successful.")
        }

        HttpEntity r_entity = response.getEntity()
        def ent = EntityUtils.toString(r_entity)

        String[] lines = ent.split('\n')
        lines.each { String line ->
            if (line.contains("<code>")) {
                token = line.substring(line.indexOf("<code>")+6,line.indexOf("</code>"))
            }
        }
        println "token: " + token
        return token

    }

    private void replaceConfig() {
        String replaceURL = "oapi/v1/namespaces/${project}/deploymentconfigs/${config}"

        HttpPut putRequest = new HttpPut(url + replaceURL)
        putRequest.addHeader("Authorization", "Bearer ${token}")
        putRequest.addHeader("Content-Type", "application/json")

        if (!configJSON.contains("\r") && !configJSON.contains("\n")) {
            def configJsonFile = new File(configJSON)
            if (configJsonFile.exists()){
                configJSON = configJsonFile.text
            }
        }

        def response = doRequest(putRequest, configJSON)

        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()

        if (statusCode != 200) {
            println("[Error] Replacement failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.getText("UTF-8"))
        }
        else {
            println("[OK] DeploymentConfig replacement was successful.")
        }
    }

    private void patchSecret() {
        println "project: ${project}"
        String secretURL = "/api/v1/namespaces/${project}/serviceaccounts/${serviceAccount}"
        String patchData = ""
        if (pullSecret) {
            patchData = "{\"imagePullSecrets\":[{\"name\":\"${pullSecret}\"}]}"
            HttpPatch patchRequest = new HttpPatch(url + secretURL)
            patchRequest.addHeader("Authorization", "Bearer ${token}")
            patchRequest.addHeader("Content-Type", "application/strategic-merge-patch+json")

            def response = doRequest(patchRequest, patchData)

            def statusLine = response.getStatusLine()
            def statusCode = statusLine.getStatusCode()

            if (statusCode != 200) {
                println("[Error] Pull secret patching failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
                throw new RuntimeException(response.entity?.content?.getText("UTF-8"))
            }
            else {
                println("[OK] Pull secret patching was successful.")
            }
        }
        if (appSecret) {
            patchData = "{\"secrets\":[{\"name\":\"${appSecret}\"}]}"
            HttpPatch patchRequest = new HttpPatch(url + secretURL)
            patchRequest.addHeader("Authorization", "Bearer ${token}")
            patchRequest.addHeader("Content-Type", "application/strategic-merge-patch+json")

            def response = doRequest(patchRequest, patchData)

            def statusLine = response.getStatusLine()
            def statusCode = statusLine.getStatusCode()

            if (statusCode != 200) {
                println("[Error] App secret patching failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
                throw new RuntimeException(response.entity?.content?.getText("UTF-8"))
            }
            else {
                println("[OK] App secret patching was successful.")
            }
        }
    }

    private void createSecret() {
        String secretUrl = "/api/v1/namespaces/${project}/secrets"

        HttpPost createRequest = new HttpPost(url + secretUrl)
        createRequest.addHeader("Authorization", "Bearer ${token}")
        createRequest.addHeader("Content-Type", "application/json")

        if (!secretJSON.contains("\r") && !secretJSON.contains("\n")) {
            def secretJsonFile = new File(secretJSON)
            if (secretJsonFile.exists()){
                secretJSON = secretJsonFile.text
            }
        }

        def response = doRequest(createRequest, secretJSON)

        def statusLine = response.getStatusLine()
        def statusCode = statusLine.getStatusCode()

        if (statusCode != 201) {
            println("[Error] Secret creation failed with an Http response code of ${statusCode}: ${statusLine.getReasonPhrase()}")
            throw new RuntimeException(response.entity?.content?.getText("UTF-8"))
        }
        else {
            println("[OK] Secret creation was successful.")
        }
    }


    // Specify a json string to provide a string entity to the http request
    private HttpResponse doRequest(HttpUriRequest request, String contentString) {
        request.addHeader("Accept", "application/json,application/xml")

        if (contentString) {
            StringEntity input
            try {
                input = new StringEntity(contentString)
            }
            catch(UnsupportedEncodingException ex) {
                println("Unsupported characters in http request content: ${contentString}")
                System.exit(1)
            }
            request.setEntity(input)
        }
        HttpResponse response = client.execute(request)
        return response
    }

}