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

/*
 * JIRA REST API Documentation: https://docs.atlassian.com/jira/REST/latest/
 */

import com.urbancode.air.AirPluginTool
import com.urbancode.air.plugin.jira.addcomments.JIRAHelper
import com.urbancode.air.plugin.jira.addcomments.TextUtil
import groovy.json.JsonBuilder
import groovy.json.JsonException
import groovy.json.JsonSlurper
import org.apache.http.impl.client.DefaultHttpClient

final def apTool = new AirPluginTool(this.args[0], this.args[1])
final def props = apTool.getStepProperties()

final def serverUrl        = props['serverUrl']
final def username         = props['username']
final def password         = props['passwordScript']?:props['password']
final def projectKey       = props['projectKey']
final def assignee         = props['assignee']
final def summary          = props['summary']
final def environment      = props['environment']
final def issueDescription = props['issueDescription']
final def priorityName      = props['priorityName']
final def issueTypeName    = props['issueTypeName']
def proxyHost = props['proxyHost']?.trim()
def proxyPort = props['proxyPort']?.trim()
def parentIssueKey = props['parentIssueKey']?.trim()
boolean allowInsecure = (props['allowInsecure']?:"false").toBoolean()
def labels                 = TextUtil.textToList(props['labels'])
def components             = TextUtil.textToList(props['components'])
def fixVersions            = TextUtil.textToList(props['fixVersions'])
def customFields           = props['customFields']?.trim()

// Constants
final def dueDate          = Calendar.getInstance()  // right meow

// Construct an empty JIRAHelper class to call helper functions
JIRAHelper jira            = new JIRAHelper()       // Created to call helper methods

//------------------------------------------------------------------------------
// Script content
//------------------------------------------------------------------------------

println "Server:\t$serverUrl"
println "Project:\t$projectKey"
println ""

// Convert components list of strings to a list of maps for the REST call
components = components.collect{ [name: it] }

// Convert fixVersions list of strings to a list of maps for the REST call
fixVersions = fixVersions.collect{ [name: it] }

// Parse custom fields
if (customFields) {
    try {
        customFields = new JsonSlurper().parseText(customFields)
        if (customFields instanceof List) {
            println "Expected Custom Fields to be a JSON object, but received a JSON array:"
            println()
            println new JsonBuilder(customFields)
            println()
            System.exit(1)
        }
    } catch (JsonException e) {
        println 'Failed to parse Custom Fields JSON:'
        println()
        println customFields
        println()
        System.exit(1)
    }
}

try {
    // Construct the HTTP client to allow user authentication
    DefaultHttpClient client
    client = jira.createClient(username, password, proxyHost, proxyPort, allowInsecure)

    def projectDetails = jira.getProjectDetails(client, serverUrl, projectKey)
    def allIssueTypes = jira.getIssueTypes(client, serverUrl, projectKey)
     
    // Fail if the given project is not found
    if (!projectDetails) {
        println String.format('No project found with key "%s".', projectKey)
        System.exit(1)
    }

    def metaIssueType = allIssueTypes.values.find{it.name == issueTypeName}    
    def issueDetails = jira.getIssueDetails(client, serverUrl, projectKey, metaIssueType.id)

    // Fail if the given issue type is not allowed in the given project
    if (!metaIssueType) {
        println String.format('"%s" is not an allowed issue type in the project "%s".', issueTypeName, projectKey)
        System.exit(1)
    }

    // Create a list of objects representing the allowed fields [{"id": String, "name": String, "required": boolean}...]
    def allowedFields = issueDetails.values.collect { i ->
        [id: i.fieldId, name: i.name, required: i.required]
    }

    // Create Issue as a HashMap object
    def fieldMap = [:]

    // Add custom fields to JSON
    customFields.each { key, value ->
        def id = allowedFields.find{
            it.name == key && it.id.startsWith('customfield_')
        }?.id

        // Fail if the given custom field name is not in the list of allowed fields for this project and issue type
        if (!id) {
            println String.format('"%s" is not an allowed custom field for the given project and issue type.', key)
            System.exit(1)
        }

        fieldMap.put(id, value)
    }

    // Add standard fields to JSON
    fieldMap.put("issuetype", ["name": issueTypeName])
    fieldMap.put("project", ["key": projectKey])
    fieldMap.put("assignee", ["name": assignee])
    fieldMap.put("priority", ["name": priorityName])
    fieldMap.put("summary", summary)
    fieldMap.put("description", issueDescription)
    if (components)  { fieldMap.put('components', components) }
    if (fixVersions) { fieldMap.put('fixVersions', fixVersions) }
    if (labels)      { fieldMap.put('labels', labels) }
    if (parentIssueKey){
        fieldMap.put("parent", ["key": parentIssueKey])
    }
    else {
        if (environment) { fieldMap.put("environment", environment) }

        if (allowedFields*.id.contains('duedate')) {
            fieldMap.put("duedate", dueDate)
        }
    }

    def issueMap = [:]
    issueMap.put("fields",fieldMap)

    // Change mapping to JSON and prepare it to be sent via REST call
    JsonBuilder issueJSON = new JsonBuilder(issueMap)

    if (!jira.createIssue(client, serverUrl, issueJSON)) {
        println "Create Issue failed. Review error output for details."
        System.exit(1)
    }
}
catch (Exception e) {
    e.printStackTrace()
    throw new IllegalStateException("Full execution of create issue failed.")
}
