import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import com.bmuschko.gradle.docker.tasks.image.DockerPushImage

plugins {
  id "com.bmuschko.docker-remote-api" version "6.7.0"
}

def buildLinuxTestImagesTask = tasks.create("buildLinuxTestImages") {
  group = "build"
  description = "Builds all Linux Docker images for the test matrix"

}

def buildWindowsTestImagesTask = tasks.create("buildWindowsTestImages") {
  group = "build"
  description = "Builds all Windows Docker images for the test matrix"
}

ext {
  matrix = []
}

tasks.create("pushMatrix", DockerPushImage) {
  group = "publishing"
  description = "Push all Docker images for the test matrix"
  images.set(project.ext.matrix)
}

// Each line under appserver describes one matrix of (version x vm x jdk), dockerfile key overrides
// Dockerfile name, args key passes raw arguments to docker build
def targets = [
  "jetty"    : [
    [version: ["9.4.39"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"], args: [sourceVersion: "9.4.39.v20210325"]],
    [version: ["9.4.39"], vm: ["openj9"], jdk: ["8", "11", "16"], args: [sourceVersion: "9.4.39.v20210325"]],
    [version: ["10.0.7"], vm: ["hotspot"], jdk: ["11", "17", "18"], args: [sourceVersion: "10.0.7"]],
    [version: ["10.0.7"], vm: ["openj9"], jdk: ["11", "16"], args: [sourceVersion: "10.0.7"]],
    [version: ["11.0.7"], vm: ["hotspot"], jdk: ["11", "17", "18"], args: [sourceVersion: "11.0.7"], war: "servlet-5.0"],
    [version: ["11.0.7"], vm: ["openj9"], jdk: ["11", "16"], args: [sourceVersion: "11.0.7"], war: "servlet-5.0"]
  ],
  "liberty"  : [
    // running configure.sh is failing while building the image with Java 17
    [version: ["20.0.0.12"], vm: ["hotspot", "openj9"], jdk: ["8", "11", "16"], args: [release: "2020-11-11_0736"]],
    // running configure.sh is failing while building the image with Java 18
    [version: ["21.0.0.10"], vm: ["hotspot"], jdk: ["8", "11", "17"], args: [release: "2021-09-20_1900"]],
    [version: ["21.0.0.10"], vm: ["openj9"], jdk: ["8", "11", "16"], args: [release: "2021-09-20_1900"]]
  ],
  "payara"   : [
    [version: ["5.2020.6"], vm: ["hotspot", "openj9"], jdk: ["8", "11"]],
    [version: ["5.2021.8"], vm: ["hotspot", "openj9"], jdk: ["8", "11"]]
  ],
  "tomcat"   : [
    [version: ["7.0.109"], vm: ["hotspot", "openj9"], jdk: ["8"], args: [majorVersion: "7"]],
    [version: ["8.5.72"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"], args: [majorVersion: "8"]],
    [version: ["8.5.72"], vm: ["openj9"], jdk: ["8", "11"], args: [majorVersion: "8"]],
    [version: ["9.0.54"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"], args: [majorVersion: "9"]],
    [version: ["9.0.54"], vm: ["openj9"], jdk: ["8", "11"], args: [majorVersion: "9"]],
    [version: ["10.0.12"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"], args: [majorVersion: "10"], war: "servlet-5.0"],
    [version: ["10.0.12"], vm: ["openj9"], jdk: ["8", "11"], args: [majorVersion: "10"], war: "servlet-5.0"]
  ],
  "tomee"    : [
    [version: ["7.0.9"], vm: ["hotspot", "openj9"], jdk: ["8"]],
    [version: ["7.1.4"], vm: ["hotspot", "openj9"], jdk: ["8"]],
    [version: ["8.0.8"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"]],
    [version: ["8.0.8"], vm: ["openj9"], jdk: ["8", "11", "16"]],
    [version: ["9.0.0-M7"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"], war: "servlet-5.0"],
    [version: ["9.0.0-M7"], vm: ["openj9"], jdk: ["8", "11", "16"], war: "servlet-5.0"]
  ],
  "websphere": [
    // TODO (trask) this is a recent change, check back in a while and see if it's been fixed
    // 8.5.5.20 only has linux/ppc64le image
    [version: ["8.5.5.19", "9.0.5.9"], vm: ["openj9"], jdk: ["8"], windows: false]
  ],
  "wildfly"  : [
    [version: ["13.0.0.Final"], vm: ["hotspot", "openj9"], jdk: ["8"]],
    [version: ["17.0.1.Final", "21.0.0.Final", "25.0.1.Final"], vm: ["hotspot"], jdk: ["8", "11", "17", "18"]],
    [version: ["17.0.1.Final", "21.0.0.Final", "25.0.1.Final"], vm: ["openj9"], jdk: ["8", "11", "16"]]
  ]
]

tasks.register("printSmokeTestsConfigurations") {
  targets.each { server, matrices ->
    def smokeTestServer = findProperty('smokeTestServer')
    if (smokeTestServer != null && server != smokeTestServer) {
      return
    }
    println server
    def serverName = String.valueOf(Character.toUpperCase(server.charAt(0))) + server.substring(1)
    matrices.forEach { entry ->
      entry.version.forEach { version ->
        def dotIndex = version.indexOf('.')
        def majorVersion = dotIndex != -1 ? version.substring(0, dotIndex) : version
        entry.jdk.forEach { jdk ->
          entry.vm.forEach { vm ->
            println "@AppServer(version = \"$version\", jdk = \"$jdk${vm == 'hotspot' ? '' : '-openj9'}\")"
            println "class ${serverName}${majorVersion}Jdk${jdk}${vm == 'hotspot' ? '' : 'Openj9'} extends ${serverName}SmokeTest {"
            println "}"
          }
        }
      }
    }
  }
}

createDockerTasks(buildLinuxTestImagesTask, targets, false)
createDockerTasks(buildWindowsTestImagesTask, targets, true)

def configureImage(Task parentTask, server, dockerfile, version, vm, jdk, warProject, Map<String, String> extraArgs, boolean isWindows, String extraTag) {
  // Using separate build directory for different images
  def dockerWorkingDir = new File(project.buildDir, "docker-$server-$version-jdk$jdk-$vm-$warProject")
  def dockerFileName = isWindows ? "${dockerfile}.windows.dockerfile" : "${dockerfile}.dockerfile"
  def platformSuffix = isWindows ? "-windows" : ""

  def prepareTask = tasks.register("${server}ImagePrepare-$version-jdk$jdk-$vm$platformSuffix", Copy) {
    def warTask = warProject != null ? project(":$warProject").tasks["war"] : project.tasks.war
    it.dependsOn(warTask)
    it.into(dockerWorkingDir)
    it.from("src/$dockerFileName")
    it.from("src/main/docker/$server")
    it.from(warTask.archiveFile) {
      rename { _ -> "app.war" }
    }
  }

  def vmSuffix = vm == "hotspot" ? "" : "-$vm"
  def image = "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-servlet-$server:$version-jdk$jdk$vmSuffix$platformSuffix-$extraTag"

  def jdkImage
  if (vm == "hotspot") {
    if (jdk == "18") {
      jdkImage = "openjdk:${jdk}"
    } else {
      jdkImage = "eclipse-temurin:${jdk}"
    }
  } else if (vm == "openj9") {
    jdkImage = "adoptopenjdk:${jdk}-openj9"
  } else {
    throw new GradleException("Unexpected vm: $vm")
  }

  if (server == "wildfly") {
    // wildfly url without .zip or .tar.gz suffix
    def serverBaseUrl
    int majorVersion = version.substring(0, version.indexOf(".")) as int
    if (majorVersion >= 25) {
      serverBaseUrl = "https://github.com/wildfly/wildfly/releases/download/${version}/wildfly-${version}"
    } else {
      serverBaseUrl = "https://download.jboss.org/wildfly/${version}/wildfly-${version}"
    }
    extraArgs = extraArgs + [baseDownloadUrl: serverBaseUrl]
  } else if (server == "payara") {
    if (version == "5.2020.6") {
      extraArgs = extraArgs + [domainName: "production"]
    } else {
      extraArgs = extraArgs + [domainName: "domain1"]
    }
  }

  def buildTask = tasks.register("${server}Image-$version-jdk$jdk$vmSuffix$platformSuffix", DockerBuildImage) {
    it.dependsOn(prepareTask)
    group = "build"
    description = "Builds Docker image with $server $version on JDK $jdk-$vm${isWindows ? ' on Windows' : ''}"

    it.inputDir.set(dockerWorkingDir)
    it.images.add(image)
    it.dockerFile.set(new File(dockerWorkingDir, dockerFileName))
    it.buildArgs.set(extraArgs + [jdk: jdk, vm: vm, version: version, jdkImage: jdkImage])
    it.doLast {
      project.ext.matrix.add(image)
    }
  }

  parentTask.dependsOn(buildTask)
  return image
}

def createDockerTasks(Task parentTask, targets, isWindows) {
  String extraTag = findProperty("extraTag") ?: new Date().format("yyyyMMdd.HHmmSS")
  Set<String> resultImages = []
  targets.each { server, matrices ->
    def smokeTestServer = findProperty('smokeTestServer')
    if (smokeTestServer != null && server != smokeTestServer) {
      return
    }
    matrices.forEach { entry ->
      def dockerfile = entry["dockerfile"]?.toString() ?: server
      def extraArgs = (entry["args"] ?: [:]) as Map<String, String>
      def warProject = entry["war"] ?: "servlet-3.0"
      def supportsWindows = entry["windows"] != null ? entry["windows"] : true

      entry.version.forEach { version ->
        entry.vm.forEach { vm ->
          entry.jdk.forEach { jdk ->
            if (supportsWindows || !isWindows) {
              resultImages.add(configureImage(parentTask, server, dockerfile, version, vm, jdk, warProject, extraArgs, isWindows, extraTag))
            }
          }
        }
      }
    }
  }
  return resultImages
}