/*
* Licensed Materials - Property of IBM* and/or HCL**
* UrbanCode Deploy
* (c) Copyright IBM Corporation 2016, 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
*/

import com.urbancode.air.AirPluginTool
import com.urbancode.air.XTrustProvider
import com.urbancode.air.plugin.kubernetes.KubernetesHelper
import com.urbancode.air.plugin.kubernetes.HelmHelper
import com.urbancode.ud.client.ComponentClient
import com.urbancode.ud.client.VersionClient
import com.urbancode.ud.client.UDRestClient
import org.apache.http.HttpResponse;

XTrustProvider.install()
def COMPONENT_TAG='kubernetes.image'

// Get step properties
def airTool = new AirPluginTool(this.args[0], this.args[1])
def props = airTool.getStepProperties()
String username                     = props['username']?.trim()
String password                     = props['password']?.trim()
String path                         = props['path'].trim()
String sourceConfigType             = props['sourceConfigType'].trim()
String componentTemplate            = props['componentTemplate'].trim()
String releaseName                  = props['releaseName'].trim()
String componentPrefix              = props['componentPrefix'].trim()
String flags                        = props['flags'].trim()

// Sanitize properties
def serverUrl = System.getenv("AH_WEB_URL");
def serverUri = KubernetesHelper.stringToUri(serverUrl)
if (serverUri.equals(new URI(''))) {
    System.exit(1)
}
if (!username) {
    username = airTool.getAuthTokenUsername()
}
if (!password) {
    password = airTool.getAuthToken()
}

ComponentClient componentClient = new ComponentClient(serverUri, username, password)
VersionClient versionClient = new VersionClient(serverUri, username, password)
UDRestClient restClient = new UDRestClient(serverUri, username, password)

// Set up helper
if (!path) {
    path = "helm"
}
File workDir = new File(".").canonicalFile
KubernetesHelper kh = new KubernetesHelper(workDir, path)

// Run the 'helm get [ release ]' command
ArrayList args = []
args << 'get'
if (HelmHelper.getHelmMajorVersion(kh) > 2) {
    args << 'manifest'
}
args << releaseName
kh.setFlags(args, flags)
releaseAsYaml = kh.getOutputFromCommand('[action]  Getting release ' + releaseName, args, 'Command completed without error and the ouput is:', 'Could not get release ' + releaseName);

imagesToCreateComponentsFor = [];
def List newYamlLines = [];
releaseAsYaml.eachLine { String line ->
    trimmedLine = line.trim();
    if (trimmedLine.length() > 0 && trimmedLine[0] == '#') {
        return;
    }
    else if (trimmedLine.contains("image: ")) {
        // get everything after "image: "
        image = trimmedLine.substring(trimmedLine.indexOf("image: ")+7);
        // there could be comments after the image name
        indexOfComment = image.indexOf("#");
        if (indexOfComment != -1) {
            image = image.substring(0, indexOfComment).trim();
        }
        // remove possible leading/trailing quotes
        firstChar = image.substring(0,1);
        lastChar = image.substring(image.length()-1, image.length());
        if (firstChar == "\"" || firstChar == "'") {
            image = image.substring(1);
        }
        if (lastChar == "\"" || lastChar == "'") {
            image = image.substring(0, image.length()-1);
        }
        parsedImage = KubernetesHelper.parseImageSpec(image);
        println "[info] Found image: " + image
        imagesToCreateComponentsFor.add(parsedImage);
    }
}

// Create components
imagesToCreateComponentsFor.each{ entry ->
    // image names may contain a slash (such as google-samples/gb-frontend)
    // however, having slashes in a component name will prevent us from using
    // the uDeployRestClient. So, we will remove the namespace
    // (everything before and including the slash) when naming our component
    imageNameWithoutNameSpace = getImageNameWithoutNamespace(entry.image);
    componentName = componentPrefix + imageNameWithoutNameSpace;
    sanitizedComponentName = restClient.sanitizePathSegment(componentName);
    def registry = entry.registry
    def image = entry.image
    def tag
    if (entry.version) {
        tag = entry.version
    }
    else {
        tag = 'latest'
    }

    def sourceProps = [:]
    if (registry) {
        sourceProps.put('DockerTagImport/dockerRegistryName', registry)
    }
    else {
        sourceProps.put('DockerTagImport/dockerRegistryName', '')
    }
    sourceProps.put('DockerTagImport/dockerImageName', image)
    sourceProps.put('DockerTagImport/namingConvention', 'tag_only')

    def componentProps = new Properties()
    componentProps.setProperty('docker.image.name', image)
    if (registry) {
        componentProps.setProperty('docker.registry.name', registry)
    }
    else {
        componentProps.setProperty('docker.registry.name', '')
    }

    String componentId = createComponent(componentClient, componentName, sourceProps, componentProps,
                                         sourceConfigType, componentTemplate).toString()


    componentClient.addTagToComponent(componentId, COMPONENT_TAG)

    createVersion(componentClient, componentName, tag, versionClient, registry);
}

println "[info] The step has completed"

/**
 *  @param imageName Name of a container image (which may be in the format namespace/image)
 *  @return The image name with the namespace and slash removed, if they were present
 */
private String getImageNameWithoutNamespace(String imageName) {
    String imageNameWithoutNamespace = imageName;
    int indexOfSlash = imageName.indexOf("/");
    if (indexOfSlash != -1) {
        imageNameWithoutNamespace = imageName.substring(indexOfSlash+1);
    }
    return imageNameWithoutNamespace;
}

/**
 *  @param name The name of the component to create
 *  @param sourceProps The list of source properties to set for the component
 *  @param componentProps The list of properties to set for the component
 *  @param configType The source configuration type
 *  @param template The component template to use when creating the component
 */
private def createComponent(def client, String name, def sourceProps, def componentProps, def configType, def template) {
    def result
    def image = sourceProps['DockerTagImport/dockerImageName']
    try {
        result = KubernetesHelper.parseTextAsJson(client.getComponent(name)).id
        println "[warn] A component named " + name + " already exists"
    }
    catch (IOException e){
        println "[action] Creating component: ${name}"
        result = client.createComponent(
                 name,
                 "Kubernetes image: ${image}",
                 configType,
                 'FULL',
                 template,
                 -1,
                 true,
                 false,
                 sourceProps)
    }

    componentProps.each { componentProp ->
        client.setComponentProperty(result.toString(), componentProp.key, componentProp.value, false)
    }

    return result
}


/**
 *  @param componentClient UDeployRest client for working with components
 *  @param componentName Name of the component to create a version for
 *  @param tag Tag of the container image
 *  @param versionClient UDeployRest client for working with versions
 *  @param registry Registry of the container image
 */
private void createVersion(def componentClient, def componentName, def tag, def versionClient, def registry) {
    def componentId = componentClient.getComponentUUID(componentName).toString();
    def existingVersions = KubernetesHelper.parseTextAsJson(componentClient.getComponentVersionsJsonArray(componentName, false))

    def versionId

    existingVersions.each { def existingVersion ->
        if (tag.equals(existingVersion.name)) {
            versionId = existingVersion.id
        }
    }

    if (!versionId) {
        versionId = versionClient.createVersion(componentId, tag, "Imported from Kubernetes yaml")

        versionClient.setVersionProperty(tag, componentId, 'dockerImageTag', tag, false)
        if (registry) {
            versionClient.setVersionProperty(tag, componentId, 'registry', registry, false)
        }
        else {
            versionClient.setVersionProperty(tag, componentId, 'registry', '', false)
        }
    }
}
