import java.time.Duration

apply plugin: 'java-library'
apply plugin: 'groovy'
apply plugin: 'org.gradle.test-retry'

apply from: "$rootDir/gradle/spotless.gradle"
apply from: "$rootDir/gradle/codenarc.gradle"
apply from: "$rootDir/gradle/spotbugs.gradle"
apply from: "$rootDir/gradle/checkstyle.gradle"

afterEvaluate {
  if (findProperty('mavenGroupId') == 'io.opentelemetry.javaagent.instrumentation') {
    archivesBaseName = 'opentelemetry-javaagent-' + archivesBaseName
  } else {
    archivesBaseName = 'opentelemetry-' + archivesBaseName
  }
}

// Version to use to compile code and run tests.
def DEFAULT_JAVA_VERSION = 11

def applyCodeCoverage = !(
  project.path.startsWith(":smoke-tests") ||
    //TODO why some tests fail on java 11 if jacoco is present?
    project.path == ":javaagent" ||
    project.path == ":load-generator" ||
    project.path.startsWith(":benchmark") ||
    project.path.startsWith(":instrumentation") ||
    project.path.startsWith(":testing-common"))

if (applyCodeCoverage) {
  apply from: "$rootDir/gradle/jacoco.gradle"
}

if (project.hasProperty("minJavaVersionForTests")) {
  project.ext.release = project.getProperty("minJavaVersionForTests")
} else {
  project.ext.release = JavaVersion.VERSION_1_8
}

java {
  sourceCompatibility = JavaVersion.toVersion(project.ext.release)
  targetCompatibility = JavaVersion.toVersion(project.ext.release)

  toolchain {
    languageVersion = JavaLanguageVersion.of(Math.max(project.ext.release.majorVersion.toInteger(), DEFAULT_JAVA_VERSION))
  }

  // See https://docs.gradle.org/current/userguide/upgrading_version_5.html, Automatic target JVM version
  disableAutoTargetJvm()
  withJavadocJar()
  withSourcesJar()
}

tasks.withType(JavaCompile) {
  options.release = project.ext.release.majorVersion.toInteger()
}
tasks.withType(GroovyCompile) {
  options.release = project.ext.release.majorVersion.toInteger()
}
tasks.withType(ScalaCompile) {
  options.release = project.ext.release.majorVersion.toInteger()
}

apply plugin: "eclipse"
eclipse {
  classpath {
    downloadSources = true
    downloadJavadoc = true
  }
}
if (configurations.find { it.name == 'jmh' }) {
  eclipse.classpath.plusConfigurations += [configurations.jmh]
}

jar {
  /*
  Make Jar build fail on duplicate files

  By default Gradle Jar task can put multiple files with the same name
  into a Jar. This may lead to confusion. For example if auto-service
  annotation processing creates files with same name in `scala` and
  `java` directory this would result in Jar having two files with the
  same name in it. Which in turn would result in only one of those
  files being actually considered when that Jar is used leading to very
  confusing failures.

  Instead we should 'fail early' and avoid building such Jars.
  */
  duplicatesStrategy = 'fail'
}

repositories {
  mavenLocal()
  mavenCentral()
  jcenter()
  maven {
    url "https://repo.typesafe.com/typesafe/releases"
  }
  // this is only needed for the working against unreleased otel-java snapshots
  maven {
    url "https://oss.sonatype.org/content/repositories/snapshots"
    content {
      includeGroup "io.opentelemetry"
    }
  }
}

dependencies {
  compileOnly group: 'org.checkerframework', name: 'checker-qual', version: versions.checkerFramework

  testImplementation enforcedPlatform(group: 'org.junit', name: 'junit-bom', version: versions.junit5)
  testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api'
  testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-params'
  testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine'
  testRuntimeOnly group: 'org.junit.vintage', name: 'junit-vintage-engine'

  testImplementation deps.spock
  testImplementation deps.groovy
  testImplementation deps.testLogging
  testImplementation group: 'info.solidsoft.spock', name: 'spock-global-unroll', version: '0.5.1'
  testImplementation group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.19.0'
}

jar {
  manifest {
    attributes(
      "Implementation-Title": project.name,
      "Implementation-Version": project.version,
      "Implementation-Vendor": "OpenTelemetry",
      "Implementation-URL": "https://github.com/open-telemetry/opentelemetry-java-instrumentation",
    )
  }
}

normalization {
  runtimeClasspath {
    metaInf {
      ignoreAttribute("Implementation-Version")
    }
  }
}

javadoc {
  options.addStringOption('Xdoclint:none', '-quiet')

  doFirst {
    if (project.ext.has("apiLinks")) {
      options.links(*project.apiLinks)
    }
  }
  source = sourceSets.main.allJava
  classpath = configurations.compileClasspath

  options {
    encoding = "utf-8"
    docEncoding = "utf-8"
    charSet = "utf-8"

    setMemberLevel JavadocMemberLevel.PUBLIC
    setAuthor true

    links "https://docs.oracle.com/javase/8/docs/api/"
    source = 8
  }
}

project.afterEvaluate {
  if (project.plugins.hasPlugin('org.unbroken-dome.test-sets') && configurations.hasProperty("latestDepTestRuntime")) {
    tasks.withType(Test).configureEach {
      doFirst {
        def testArtifacts = configurations.testRuntimeClasspath.resolvedConfiguration.resolvedArtifacts
        def latestTestArtifacts = configurations.latestDepTestRuntimeClasspath.resolvedConfiguration.resolvedArtifacts
        assert testArtifacts != latestTestArtifacts: "latestDepTest dependencies are identical to test"
      }
    }
  }
}

def isJavaVersionAllowed(JavaVersion version) {
  if (project.hasProperty('minJavaVersionForTests') && project.getProperty('minJavaVersionForTests').compareTo(version) > 0) {
    return false
  }
  if (project.hasProperty('maxJavaVersionForTests') && project.getProperty('maxJavaVersionForTests').compareTo(version) < 0) {
    return false
  }
  return true
}

def testJavaVersion = rootProject.findProperty('testJavaVersion')
if (testJavaVersion != null) {
  def requestedJavaVersion = JavaVersion.toVersion(testJavaVersion)
  tasks.withType(Test).all {
    javaLauncher = javaToolchains.launcherFor {
      languageVersion = JavaLanguageVersion.of(requestedJavaVersion.majorVersion)
    }
    enabled = isJavaVersionAllowed(requestedJavaVersion)
  }
} else {
  // We default to testing with Java 11 for most tests, but some tests don't support it, where we change
  // the default test task's version so commands like `./gradlew check` can test all projects regardless
  // of Java version.
  if (!isJavaVersionAllowed(JavaVersion.toVersion(DEFAULT_JAVA_VERSION))) {
    tasks.withType(Test) {
      javaLauncher = javaToolchains.launcherFor {
        languageVersion = JavaLanguageVersion.of(project.getProperty('maxJavaVersionForTests').majorVersion)
      }
    }
  }
}

tasks.withType(Test).configureEach {
  useJUnitPlatform()

  // All tests must complete within 15 minutes.
  // This value is quite big because with lower values (3 mins) we were experiencing large number of false positives
  timeout = Duration.ofMinutes(15)

  retry {
    // You can see tests that were retried by this mechanism in the collected test reports and build scans.
    maxRetries = System.getenv("CI") != null ? 5 : 0
  }

  reports {
    junitXml.outputPerTestCase = true
  }

  testLogging {
    exceptionFormat = 'full'
  }
}

tasks.withType(AbstractArchiveTask) {
  preserveFileTimestamps = false
  reproducibleFileOrder = true
}

plugins.withId('net.ltgt.errorprone') {
  dependencies {
    annotationProcessor group: "com.uber.nullaway", name: "nullaway", version: versions.nullaway
    errorprone group: "com.google.errorprone", name: "error_prone_core", version: versions.errorprone
  }

  tasks.withType(JavaCompile) {
    if (!name.toLowerCase().contains("test")) {
      options.errorprone {
        error("NullAway")

        // Doesn't work well with Java 8
        disable("FutureReturnValueIgnored")

        option("NullAway:AnnotatedPackages", "io.opentelemetry,com.linecorp.armeria,com.google.common")
      }
    }
  }
}
