def defineAuth() {
  def api = "https://ocpcluster-a.arbetsformedlingen.se:443"
  env.API = sh(script:"set +x; echo ${ api }", returnStdout: true).replaceAll(/https?/, 'insecure')
  def encodedToken = openshift.selector('secret/imagepromote-token-ocp-a').object().data.tokenbase64
  env.TOKEN = sh(script:"set +x; echo ${ encodedToken } | base64 --decode", returnStdout: true)
}

def generateTag() {
  echo '### Generating build tag... ###'
  def hash = getVersionHash()
  def tag = "${ hash }"
  echo "### build tag: \"${ tag }\" ###"
  return tag
}

def getVersionHash() {
  return sh(returnStdout: true, script: "git tag --points-at HEAD").trim()
}
def getShortCommitHash() {
  return sh(returnStdout: true, script: "git log -n 1 --pretty=format:'%h'").trim()
}

def pushToExternalRegistry( String appName,
                            String tag,
                            String imageProject,
                            String internalRegistry,
                            String externalRegistry) {
  withCredentials([usernamePassword(credentialsId: "${ openshift.project() }-nexus-secret", usernameVariable: "REG_USER", passwordVariable: "REG_PWD")]) {
    echo "Copying image..."
    echo "from docker://${ internalRegistry }/${ imageProject }/${ appName }:${ tag }"
    echo "to docker://${ externalRegistry }/app-af-nexus/${ appName }:latest"
    sh "skopeo copy docker://${ internalRegistry }/${ imageProject }/${ appName }:${ tag } docker://${ externalRegistry }/app-af-nexus/${ appName }:latest --src-creds jenkins:\$(oc whoami -t) --dest-creds \"$REG_USER:$REG_PWD\" --src-tls-verify=false --dest-tls-verify=false --format v2s2"
    // todo: annotate the image with a label
  }
}

def rollout(String appName,
            String imageStreamName,
            String imageTag,
            String label,
            String imageProject,
            String registry,
            boolean useConfigMap,
            String configMapKey,
            String configMapPath) {
  if (useConfigMap) {
    echo "useConfigMap was set to true"
    def configMap = openshift.selector("configmap", configMapKey)
    if (configMap.exists()) {
      echo "Found existing config map. Removing..."
      openshift.selector("configmap", configMapKey).delete();
    }
    echo "Applying configmap from path: ${configMapPath} ..."
    openshift.apply(readFile(configMapPath))
  }

  echo "Setting image for Deployment Config: ${ appName } to ${ registry }/${ imageProject }/${ imageStreamName }:${ imageTag } ..."
  openshift.raw("set image dc/${ appName } ${ appName }=${registry}/${ imageProject }/${ imageStreamName }:${ imageTag } --record=true")

  echo "Labeling Deployment Config with build: ${ label } ..."
  openshift.raw("patch dc ${ appName } -p \"{\\\"spec\\\":{\\\"template\\\":{\\\"metadata\\\":{\\\"labels\\\":{\\\"build\\\":\\\"${ label }\\\"}}}}}}\"")

  echo "Rolling out..."
  openshift.selector("dc", "${ appName }").rollout().status();

  def latestDeploymentVersion = openshift.selector('dc',"${ appName }").object().status.latestVersion
  echo "Labeling Replication Controller ${ appName }-${ latestDeploymentVersion } with build: ${ label } ..."
  openshift.raw("patch rc ${ appName }-${ latestDeploymentVersion } -p \"{\\\"metadata\\\":{\\\"labels\\\":{\\\"build\\\":\\\"${ label }\\\"}}}\"")
}

def selectTag(String applicationName,
              Integer timeoutTime = 10,
              String timeoutUnit = 'MINUTES') {
  def tagToPromote = ""
  def imageStreamsSelector = openshift.selector('is')
  def cancelled = false

  imageStreamsSelector.withEach { is ->
    def streamName = is.name()
    if (streamName == "imagestream/" + applicationName) {
      def tags = sortTags(is.object().spec.tags)
      try {
        timeout(time: timeoutTime, unit: timeoutUnit) {
          tagToPromote = input  message: "We need some input from you:",
            ok: "Proceed",
            parameters: [
              choice(name: 'Tag', choices: tags, description: 'What tag do you want to promote?')
            ]
        }
      } catch(err) {
        def user = err.getCauses()[0].getUser()
        if('SYSTEM' == user.toString()) { // SYSTEM means timeout.
          echo "Pipeline timed out waiting for user input"
          currentBuild.result = 'NOT_BUILT'
        } else {
          echo "Aborted by ${user}"
          currentBuild.result = 'ABORTED'
        }
        error('Pipeline timed out or was aborted')
      }
    }
  }

  return tagToPromote
}

@NonCPS
def sortTags(tags) {
  def sorted = tags.sort { a, b -> a.generation <=> b.generation }.reverse()
  def arr = []
  sorted.each { tag ->
    arr.add("$tag.name")
  }
  return arr
}

def selectTarget(ArrayList<String> targets, Integer timeoutTime = 10, String timeoutUnit = 'MINUTES') {
  def target = ""
  try {
    timeout(time: timeoutTime, unit: timeoutUnit) {
      target = input  message: "We need some input from you!",
        ok: "Proceed",
        parameters: [
          choice(name: 'Target', choices: targets, description: 'Select target for promotion: ')
        ]
    }
  } catch(err) {
    def user = err.getCauses()[0].getUser()
    if('SYSTEM' == user.toString()) { // SYSTEM means timeout.
      echo "Pipeline timed out waiting for user input"
      currentBuild.result = 'NOT_BUILT'
    } else {
      echo "Aborted by ${user}"
      currentBuild.result = 'ABORTED'
    }
    error('Pipeline timed out or was aborted')
  }
  return target
}

return this

def createVulnerabilityScan(String projectName, String projectVersion, String apiKey) {
  echo "### Generating vulnerability scan for \"${ projectVersion }\" of \"${ projectName }\""
  sh """
        cyclonedx-bom -o bom.xml -d
        set +x
        REPORT=\$(cat bom.xml|base64 -w 0)
        cat > payload.json <<EOF
{
\"projectName\": \"${projectName}\",
\"projectVersion\": \"${projectVersion}\",
\"autoCreate\": \"True\",
\"bom\": \"\${REPORT}\"
}
EOF
        curl -X \"PUT\" \"http://dependency-tracker-infra-dependencytracker.tocp.arbetsformedlingen.se/api/v1/bom\" -H 'Content-Type: application/json' \
        -H 'X-API-Key: ${apiKey}' \
        -d @payload.json
    """
  echo "Go to http://dependency-tracker-infra-dependencytracker.tocp.arbetsformedlingen.se and login to see your report"
}

def tagGitWithBuild(String tag, String credentials) {
  try {
    sshagent([credentials]) {
      echo "### Creating the tag \"${tag}\" ###"
      sh(returnStdout: false, script: "git fetch --tags --q")
      sh(returnStdout: false, script: "git tag \"${ tag }\"")
      try {
        sh(returnStdout: false, script: "git push origin \"${ tag }\"")
      } catch (err) {
        currentBuild.result = 'UNSTABLE'
        echo "Error occured when trying to push tag to origin. Did the tag exist already?"
        echo "Message: ${err}"
      }
    }
  } catch (err) {
    currentBuild.result = 'UNSTABLE'
    echo "Error occured when trying to tag commit. Did you check if you have the plugin SSH Agent installed? This step needs to be executed with the proper credentials."
    echo "Message: ${err}"
  }
}

def updateDeployTag(String appName, String project, String tag, String credentials) {
  try {
    sshagent([credentials]) {
      echo "Attempting to find a commit with the tag \"${ tag }\" ..."
      def commitSHA = sh (
        script: "git show-ref -s ${tag} || echo \"\"",
        returnStdout: true
      )
      def tagName = "ocp/deployed/${ appName }/${ project }"
      if (commitSHA != '') {
        echo "Tagging SHA: ${ commitSHA } with tag: ${ tagName }"
        def existingTagSHA =  sh (
          script: "git show-ref -s  ${ tagName } || echo \"\"",
          returnStdout: true,
        ).trim()
        echo "existingTagSHA: \"${existingTagSHA}\""
        if (existingTagSHA != '') {
          echo "Removing existing tag..."
          sh(returnStdout: false, script: "git tag -d ${ tagName }") // deletes local deploy tag
          sh(returnStdout: false, script: "git push origin :${ tagName }")  // deletes original remote tag
        }
        sh(returnStdout: false, script: "git tag ${ tagName } ${ commitSHA }") // creates new local deploy tag
        try {
          sh(returnStdout: false, script: "git push origin ${ tagName }") // creates new remote tag
        }
        catch (err) {
          currentBuild.result = 'UNSTABLE'
          echo "Error occured when trying to push tag to origin. Make sure tags are fetched so the function knows if it needs to remove existing tags first."
          echo "Message: ${err}"
        }
      } else {
        echo "Warning! Couldn\'t find any commits with the tag ocp/${ appName }/${ tag }"
        echo "This function assumes that you are tagging your commits with this pattern when generating new images"
        currentBuild.result = 'UNSTABLE'
      }
    }
  } catch (err) {
    currentBuild.result = 'UNSTABLE'
    echo "Error occured when trying to tag commit. Did you check if you have the plugin SSH Agent installed? This step needs to be executed with the proper credentials."
    echo "Message: ${err}"
  }
}
