import org.gradle.api.internal.project.IsolatedAntBuilder

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

apply plugin: StagePlugin

class VerifyStageTask extends DefaultTask {

  @TaskAction
  def run() {
    // check if credentials are set
    if (project.findProperty("asfNexusUsername") == null) {
      throw new GradleException("Missing nexus username")
    }
    if (project.findProperty("asfNexusPassword") == null) {
      throw new GradleException("Missing nexus password")
    }
    if (project.findProperty('signing.keyId') == null) {
      throw new GradleException("Missing GPG key ID")
    }
    if (project.findProperty('signing.gnupg.keyName') == null) {
      throw new GradleException("Missing GPG key name")
    }
    // make sure we are building a release
    if (System.getenv('BUILD_RELEASE') != 'true') {
      throw new GradleException("BUILD_RELEASE is not set to true. Run export BUILD_RELEASE=true")
    }
    // make sure signing is enabled
    if (System.getenv("ENABLE_SIGNING") != 'true') {
      throw new GradleException("ENABLE_SIGNING is not set to true. Run export ENABLE_SIGNING=true")
    }

    // make sure there are no local changes.
    def status = new ByteArrayOutputStream()
    project.exec {
      commandLine 'git', 'status', '-s'
      standardOutput = status
    }
    if (status.size() != 0) {
      throw new GradleException("Local changes detected")
    }

    // check the version matches the branch.
    def branchOutput = new ByteArrayOutputStream()
    project.exec {
      commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
      standardOutput = branchOutput
    }
    def branch = branchOutput.toString().trim()
    if (!project.version.startsWith(branch)) {
      throw new GradleException("$project.version does not start with $branch")
    }
  }
}

class StageBuildTask extends DefaultTask {

  @TaskAction
  def run() {
    // run the build, publishing the artifacts to Nexus as staging
    project.exec { commandLine "./gradlew", "clean", "build" }
    project.exec { commandLine "./gradlew", "publish" }
  }
}

class SubversionStageTask extends DefaultTask {
  @TaskAction
  def run() {
    if (!new File("_staged/$project.version-incubating").exists())
      // create _staged folder
      project.exec { commandLine "mkdir", "-p", "_staged" }

    // create the folder in SVN where we will stage the binaries
    project.exec {
      commandLine "svn", "mkdir", "-m", "Add new Apache Tuweni folder for release $project.version", "https://dist.apache.org/repos/dist/dev/incubator/tuweni/$project.version-incubating", "--force-interactive"
    }

    // check out the SVN repository where we will store the binaries
    project.exec {
      commandLine "svn", "checkout", "https://dist.apache.org/repos/dist/dev/incubator/tuweni/$project.version-incubating", "_staged/$project.version-incubating", "--force-interactive"
    }
  }
}

class CopyStagedTask extends DefaultTask {

  @TaskAction
  def copy() {
    // copy distributions over to the folder
    project.exec {
      commandLine "bash", "-c", "cp dist/build/distributions/tuweni-* _staged/$project.version-incubating/"
    }

    // add incubating to the version.
    def fileNames = []
    def fileOutput = new ByteArrayOutputStream()
    project.exec {
      commandLine "ls", "_staged/$project.version-incubating/"
      standardOutput fileOutput
    }
    fileOutput.toString().split("\n").each {
      fileNames.add([
        it,
        it.replace(project.version, "$project.version-incubating")
      ])
    }

    fileNames.each {
      def src = it[0]
      def target = it[1]
      project.exec {
        workingDir "_staged/$project.version-incubating/"
        commandLine "mv", src, target
      }
    }

    // now commit the staged files
    project.exec {
      workingDir "_staged/$project.version-incubating/"
      commandLine 'bash', '-c', 'svn add tuweni-*'
    }
    project.exec {
      workingDir "_staged/$project.version-incubating/"
      commandLine 'svn', 'ci', '-m', "Add Apache Tuweni $project.version release candidate", "--force-interactive"
    }
  }
}

class GitStageTask extends DefaultTask {
  @TaskAction
  def run() {
    def branchOutput = new ByteArrayOutputStream()
    project.exec {
      commandLine 'git', 'rev-parse', '--abbrev-ref', 'HEAD'
      standardOutput = branchOutput
    }
    def branch = branchOutput.toString().trim()
    // tag the repo
    project.exec {
      commandLine 'git', 'tag', '-m', "Release $project.version-incubating", "v$project.version-incubating-rc"
    }
    project.exec {
      commandLine 'git', 'push', 'origin', branch, '--tags'
    }
  }
}

class EmailPromptTask extends DefaultTask {
  @TaskAction
  def run() {
    println("""
To: dev@tuweni.apache.org
Subject:[VOTE] Tuweni $project.version-incubating release
We're voting on the source distributions available here:
https://dist.apache.org/repos/dist/dev/incubator/tuweni/$project.version-incubating/
The release tag is present here:
https://github.com/apache/incubator-tuweni/releases/tag/v$project.version-incubating-rc

This release includes the following changes:

// TODO fill changes
""")
  }
}

class StageTask extends DefaultTask {

  @TaskAction
  def stage() {
    project.exec { commandLine "./gradlew", "stageVerify", "stageBuild", "stageSVN", "stageCopy", "stageGitTag", "stageEmail" }
  }
}

class StagePlugin implements Plugin<Project> {
  void apply(Project project) {
    configureDependencies(project)
    project.plugins.apply(JavaPlugin)

    Task stageTask = project.task("stage",
    type: StageTask,
    group: 'Build',
    description: 'Stages Apache Tuweni.')

    Task verifyStage = project.task("stageVerify",
    type: VerifyStageTask,
    group: "Build",
    description: 'Verifies Apache Tuweni can be staged.')

    Task buildStage = project.task("stageBuild",
    type: StageBuildTask,
    group: "Build",
    description: 'Builds Apache Tuweni to be staged.')

    Task subversionStage = project.task("stageSVN",
    type: SubversionStageTask,
    group: "Build",
    description: 'Creates staging folder on SVN and checks it out')

    Task copyStage = project.task("stageCopy",
    type: CopyStagedTask,
    group: 'Build',
    description: 'Copy over distributions to staged area and push them to SVN')

    Task gitStageTask = project.task("stageGitTag",
    type: GitStageTask,
    group: 'Build',
    description: 'Tag in git the current stage')

    Task emailPrompt = project.task("stageEmail",
    type: EmailPromptTask,
    group: 'Build',
    description: 'Email example to console showing what to send')
  }

  void configureDependencies(final Project project) {
    project.repositories { mavenCentral() }
  }
}
