/**
 * Licensed Materials - Property of IBM Corp.
 * IBM UrbanCode Deploy
 * (c) Copyright IBM Corporation 2011, 2016. 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.docker

import groovy.json.JsonSlurper
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.utils.URIBuilder
import org.apache.http.HttpResponse

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

public class ICSClient {
    CommandHelper helper
    final def workDir = new File('.').canonicalFile
    def registry
    def username
    def password
    def proxyHost
    def proxyPortString
    def proxyUsername
    def proxyPassword
    def slurper
    def client
    def imageName
    def allowInsecure
    def api
    def bearerToken
    def spaceGuid
    def protocol
    def space
    def org

    public ICSClient( def props) {
        this.registry = props['dockerRegistryName']
        this.username = props['dockerRegistryUsername']
        this.password = props['dockerRegistryPassword']
        this.imageName = props['dockerImageName']
        this.allowInsecure = props['allowInsecure'].toBoolean()
        this.api = props['api']?.trim()
        this.space = props['space']
        this.org = props['org']

        this.proxyHost = props['proxyHost']
        this.proxyPortString = props['proxyPort']
        this.proxyUsername = props['proxyUsername']
        this.proxyPassword = props['proxyPassword']

        this.protocol = "https://"

        this.slurper = new JsonSlurper()

        helper = new CommandHelper(workDir)

        HttpClientBuilder builder = new HttpClientBuilder()

        if (proxyHost) {
            def proxyPort = Integer.parseInt(proxyPortString)
            builder.setProxyHost(proxyHost)
            builder.setProxyPort(proxyPort)
            if (proxyUsername) {
                builder.setProxyUsername(proxyUsername)
                builder.setProxyPassword(proxyPassword)
            }
        }

        if (allowInsecure) {
            XTrustProvider.install()
            builder.setTrustAllCerts(true)
        }

        this.client = builder.buildClient()

        // Confirm registry does exist with the given information
        println "[Action] Loading Cloud Foundry authentication..."
        cfLogin()
        loadCFAuthInfo()
        println "...Authentication successfully loaded."
        println ""
    }

    // set the api for the cf executable and log in
    void cfLogin() {
        def commandArgs

        // Set cf api
        if (api) {
            commandArgs = ["cf", "api", api]
            try {
                runHelperCommand("[Action] Setting cf target api", commandArgs)
            }
            catch (ExitCodeException e) {
                println "[Error] An error occurred when setting the api to ${api}"
                println "[Error] ICS API is not set correctly"
                System.exit(1)
            }
        }

        // Log in
        commandArgs = [
                "cf",
                "login",
                "-u",
                username,
                "-p",
                password
        ]
        if (space) {
            commandArgs << "-s"
            commandArgs << space
        }
        if (org) {
            commandArgs << "-o"
            commandArgs << org
        }

        try {
            runHelperCommand("[Action] Logging into CloudFoundry", commandArgs)
        }
        catch(ExitCodeException e) {
            println "[Error] Authentication error. Check username and password."
        }
    }

    def runHelperCommand(def message, def command) {
        try {
            helper.runCommand(message, command)
        } catch(ExitCodeException e){
            def errorMessage = "[Error] An error occurred while running the following command: ${command}"
            throw new ExitCodeException(errorMessage, e)
        }
    }

    def loadCFAuthInfo() {
        // get location of config.json file
        def cfHomeDir = System.getenv("CF_HOME")

        if (!cfHomeDir) {
            println "[Error] Please make sure the system environment variable CF_HOME is set."
            System.exit(1)
        }

        if (!cfHomeDir.substring(cfHomeDir.length() - 1).equals("\\")) {
            cfHomeDir += "\\"
        }

        try {
            def jsonFile = new File(cfHomeDir + ".cf\\config.json")
            def configInfo = slurper.parseText(jsonFile.text)
            bearerToken = configInfo.AccessToken
            if (bearerToken.toLowerCase().startsWith("bearer ")) {
                bearerToken = bearerToken.substring(7)
            }
            spaceGuid = configInfo.SpaceFields.Guid
        }
        catch (FileNotFoundException ex) {
            println "[Error] Cannot find the config.json file: ${ex.getMessage()}"
            println "[Error] Please make sure the system environment variable CF_HOME is set correctly."
            System.exit(1)
        }
    }

    def getBaseUri() {
        return new URIBuilder("${protocol}${registry}").build()
    }

    def getICSImageUri = { tag ->
        return new URIBuilder(getBaseUri()).setPath("/v3/images/${imageName}:${tag}/json").build()
    }

    def getImageListUri() {
        return new URIBuilder(getBaseUri()).setPath("/v3/images/json").build()
    }

    public def getTags() {
        def tags = []
        def tagsJson
        println "[Action] Requesting list of tags for ${imageName}..."

        tagsJson = requestWithAuth(getImageListUri()).entity?.content.text
        def images = slurper.parseText(tagsJson).Image
        images.each { image ->
            def split = image.split(':')
            if (split[0].equals(imageName)) {
                tags << split[1]
            }
        }


        if (tags) {
            println "...Successfully retrieved ${tags?.size()} tag(s)."
            println ""
        } else {
            println "No tags found"
        }

        return tags
    }

    public def getLabelsForTag = { def tag ->
        def result
        def idJson = requestWithAuth(getICSImageUri(tag)).entity?.content?.text
        result = slurper.parseText(idJson).Config.Labels
        return result
    }

    public def getIdForTag = { def tag ->
        def result
        def idJson = requestWithAuth(getICSImageUri(tag)).entity?.content?.text
        result = slurper.parseText(idJson).Id
        return result
    }

    def requestWithAuth = { uri ->
        def result
        HttpGet initialRequest = new HttpGet(uri)

        initialRequest.addHeader("Content-Type", "application/json")
        initialRequest.addHeader("X-Auth-Token", bearerToken)
        initialRequest.addHeader("X-Auth-Project-Id", spaceGuid)

        HttpResponse initialResponse = client.execute(initialRequest)
        def status = initialResponse.getStatusLine().getStatusCode()

        if (status==401) {
            println "[Error] Authentication error. Login to CF CLI."
            System.exit(1)
        }
        else {
            result = initialResponse
        }

        return result
    }
}
