/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

import groovy.transform.Field
import hudson.model.Job
import hudson.model.Result
import org.hitachivantara.ci.JobItem
import org.hitachivantara.ci.config.BuildData
import org.hitachivantara.ci.jenkins.JobBuild
import org.hitachivantara.ci.jenkins.JobException
import org.hitachivantara.ci.jenkins.JobUtils
import org.yaml.snakeyaml.Yaml
import org.jenkinsci.plugins.workflow.actions.WarningAction
import org.jenkinsci.plugins.workflow.graph.FlowNode

import static org.hitachivantara.ci.config.LibraryProperties.IS_MINION
import static org.hitachivantara.ci.config.LibraryProperties.IS_MULTIBRANCH_MINION

@Field BuildData buildData = BuildData.instance

/**
 * Get the next build number for the job with the given name
 * @param jobName
 * @return
 */
Integer nextBuildNumber(String jobName) {
  Job job = JobUtils.findJobByName(jobName)
  if (!job) {
    // might be a relative path, attempt to find it based on the current job location
    Job currentJob = JobUtils.findJobByName(env.JOB_NAME)
    if (currentJob.parent) {
      job = JobUtils.findJobByName("${currentJob.parent.fullName}/${jobName}")
    }
  }

  if (!job) {
    throw new JobException("Unknown job: ${jobName}")
  }

  return job.nextBuildNumber
}

/**
 * Trigger the job with the given name
 * @param jobName
 * @param parameters
 * @param waitUntilDone
 */
void trigger(String jobName, Map parameters, waitUntilDone = true) {
  utils.handleError(
    new JobBuild(jobName)
      .withParameters(parameters)
      .getExecution(!waitUntilDone),
    { Throwable e ->
      throw e
    }
  )
}

/**
 * Converts a Map to a List with Jenkins specific properties types to be used in job configuration or to pass as
 * parameters to an external job call
 * @param properties
 * @param forConfig
 * @return
 */
List toParameters(Map properties, boolean forConfig = false) {
  String valueKey = forConfig ? 'defaultValue' : 'value'

  properties.collect { key, value ->
    switch (value) {
      case Boolean:
        return booleanParam(name: key, (valueKey): value)

      case String:
        if (value.contains("\n")) {
          return text(name: key, (valueKey): value)
        }
        return string(name: key, (valueKey): value)

      case Map:
        // TODO: this yaml management should probably be done with a step
        return text(name: key, (valueKey): value ? new Yaml().dump(value) : '')

      default:
        return string(name: key, (valueKey): value.toString())
    }
  }
}

/**
 * Sets the build result on the current build
 * @param run
 * @param result
 */
void setBuildResult(Object result) {
  currentBuild.result = String.valueOf(result)
  setStageResult(result)
}

/**
 * Set the current build as UNSTABLE
 * @param run
 */
void setBuildUnstable() {
  setBuildResult(Result.UNSTABLE)
}

void setStageResult(Object result) {
  FlowNode f = getContext(FlowNode.class)
  if (f != null) {
    // getContext is a new step, we want to mark the immediate previous one
    f.addOrReplaceAction(new WarningAction(Result.fromString(String.valueOf(result))))
    f.parents.each {
      it.addOrReplaceAction(new WarningAction(Result.fromString(String.valueOf(result))))
    }
  }
}

/**
 * Archive Job Item tests on the current job
 * @param item
 */
void archiveTests(JobItem item) {
  if (!buildData.getBool(IS_MINION) || buildData.getBool(IS_MULTIBRANCH_MINION)) {
    log.debug "Archiving tests for job item ${item.jobID} with pattern ${item.testsArchivePattern}"
    List paths = item.modulePaths ?: [item.buildWorkDir]
    paths.each { String path ->
      dir(path) {
        junit allowEmptyResults: true, testResults: item.testsArchivePattern
      }
    }
  }
}