import com.dropbox.stone.java.StoneTask
import com.dropbox.stone.java.model.ClientSpec
import com.dropbox.stone.java.model.StoneConfig
import com.vanniktech.maven.publish.SonatypeHost

plugins {
    id 'java-library'
    id "com.github.blindpirate.osgi"
    id "org.jetbrains.kotlin.jvm"
    id "com.vanniktech.maven.publish"
    id "com.github.ben-manes.versions"
    id "com.dropbox.dependency-guard"
    id "com.dropbox.stone.java"
    id "org.jetbrains.kotlinx.binary-compatibility-validator"
}

dependencyGuard {
    configuration("runtimeClasspath")
}

sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8

ext {
    mavenName = 'Official Dropbox Java SDK'
    generatedSources = file("$buildDir/generated-sources")
    generatedResources = file("$buildDir/generated-resources")
    authInfoPropertyName = 'com.dropbox.test.authInfoFile'
}

tasks.register('versionWriterTask') {
    String versionName
    if (project.hasProperty("VERSION_NAME")) {
        versionName = "${project.property("VERSION_NAME")}"
    } else {
        versionName = project.version
    }
    it.inputs.property("versionName", versionName)

    def generatedDir = project.layout.buildDirectory.dir("generated/version")
    it.outputs.dir(generatedDir)

    it.doLast {
        def versionFile = generatedDir.get().file("com/dropbox/core/DbxSdkVersion.java").asFile
        versionFile.parentFile.mkdirs()
        versionFile.text = """// Generated file. Do not edit
package com.dropbox.core;

public final class DbxSdkVersion {
    public static final String Version = "${versionName}";
}
"""
    }
}
sourceSets.main.java.srcDir(versionWriterTask)

dependencies {
    api(dropboxJavaSdkLibs.jackson.core)
    api(dropboxJavaSdkLibs.jsr305)

    compileOnly dropboxJavaSdkLibs.appengine.api
    compileOnly dropboxJavaSdkLibs.jakarta.servlet.api
    compileOnly dropboxJavaSdkLibs.kotlin.stdlib
    compileOnly dropboxJavaSdkLibs.okhttp2
    compileOnly dropboxJavaSdkLibs.okhttp3

    testImplementation dropboxJavaSdkLibs.appengine.api
    testImplementation dropboxJavaSdkLibs.appengine.api.labs
    testImplementation dropboxJavaSdkLibs.appengine.api.stubs
    testImplementation dropboxJavaSdkLibs.appengine.testing
    testImplementation dropboxJavaSdkLibs.guava
    testImplementation dropboxJavaSdkLibs.jmh.core
    testImplementation dropboxJavaSdkLibs.jmh.generator
    testImplementation dropboxJavaSdkLibs.mockito.core
    testImplementation dropboxJavaSdkLibs.okhttp2
    testImplementation dropboxJavaSdkLibs.okhttp3
    testImplementation dropboxJavaSdkLibs.testng
    testImplementation dropboxJavaSdkLibs.truth
}

configurations {
    withoutOsgi.extendsFrom api
}

tasks.named("compileJava", JavaCompile) {
    options.compilerArgs << '-Xlint:all'
    options.warnings = true
    options.deprecation = true
    options.encoding = 'utf-8'
}

tasks.named("compileTestKotlin") {
    dependsOn(tasks.named("generateTestStone"))
}

tasks.named("test", Test) {
    useTestNG()

    // TestNG specific options
    options.parallel 'methods'
    options.threadCount 4

    // exclude integration tests
    exclude '**/IT*.class'
    exclude '**/*IT.class'
    exclude '**/*IT$*.class'

    testLogging {
        showStandardStreams = true // System.out.println
    }
}

def getAuthInfoFile() {
    if (!project.hasProperty(authInfoPropertyName)) {
        throw new GradleException('' +
                "These tests require the \"${authInfoPropertyName}\" " +
                "project property be set to point to an authorization JSON file " +
                "(e.g. ./gradlew integrationTest -P${authInfoPropertyName}=auth.json)."
        )
    }

    def authInfoFile = file(project.property(authInfoPropertyName))
    if (!authInfoFile.exists()) {
        throw new GradleException('' +
                "The test auth info file does not exist: \"${authInfoFile.absolutePath}\". " +
                "Please ensure the \"${authInfoPropertyName}\" project property is set to point to " +
                "the correct authorization JSON file."
        )
    }
    return authInfoFile
}

tasks.register('integrationTest', Test) {
    description 'Runs integration tests against Production or Dev servers.'
    enabled = project.hasProperty(authInfoPropertyName)

    useTestNG()

    // only select integration tests (similar to maven-failsafe-plugin rules)
    include '**/IT*.class'
    include '**/*IT.class'
    include '**/*IT$*.class'

    exclude '**/*V1IT.class'
    exclude '**/*V1IT$*.class'

    testLogging {
        showStandardStreams = true // System.out.println
    }

    reports {
        html {
            destination = file("${buildDir}/reports/integration-tests")
        }
    }

    project.ext {
        httpRequestorPropertyName = 'com.dropbox.test.httpRequestor'
    }

    if (project.hasProperty(authInfoPropertyName)) {
        systemProperty project.authInfoPropertyName.toString(), getAuthInfoFile().absolutePath
    }
    if (project.hasProperty(httpRequestorPropertyName)) {
        systemProperty project.httpRequestorPropertyName.toString(), project.property(httpRequestorPropertyName)
    }

    // Will ensure that integration tests are re-run every time because they are not hermetic
    outputs.upToDateWhen { false }
}


tasks.named("javadoc", Javadoc) {
    String versionName
    if (project.hasProperty("VERSION_NAME")) {
        versionName = "${project.property("VERSION_NAME")}"
    } else {
        versionName = ""
    }

    title "${project.mavenName} ${versionName} API"
    failOnError true

    // JDK 8's javadoc has an on-by-default lint called "missing", which requires that everything
    // be documented. Disable this lint because we intentionally don't document some things.
    //
    // NOTE: ugly hack to set our doclint settings due to strange handling of string options by the
    // javadoc task.
    if (JavaVersion.current().isJava8Compatible()) {
        options.addBooleanOption "Xdoclint:all,-missing", true
    }
    options.addStringOption "link", "http://docs.oracle.com/javase/8/docs/api/"
}

tasks.named("jar", Jar) {
    // OsgiManifest since we import 'osgi' plugin
    manifest {
        name project.name
        description project.description
        license 'http://opensource.org/licenses/MIT'
        instruction 'Import-Package',
                'android.*;resolution:=optional',
                'com.google.appengine.*;resolution:=optional',
                'com.squareup.okhttp;resolution:=optional',
                'okhttp3;resolution:=optional',
                'okio;resolution:=optional',
                'kotlin.*;resolution:=optional',
                '*'

        def noeeProp = 'osgi.bnd.noee'
        def noee = providers.gradleProperty(noeeProp).forUseAtConfigurationTime().getOrElse(
                providers.systemProperty(noeeProp).forUseAtConfigurationTime().getOrElse('false')
        )
        instruction '-noee', noee
    }
}

tasks.register('jarWithoutOsgi', Jar) {
    dependsOn(tasks.named("classes"))
    archiveClassifier.set('withoutOsgi')
    from sourceSets.main.output
}

tasks.register('sourcesJar', Jar) {
    dependsOn(tasks.named("classes"))
    archiveClassifier.set('sources')
    from sourceSets.main.allSource
}

tasks.register('javadocJar', Jar) {
    dependsOn(tasks.named("javadoc"))
    archiveClassifier.set('javadoc')
    from javadoc.destinationDir
}

artifacts {
    archives sourcesJar
    archives javadocJar
    withoutOsgi jarWithoutOsgi
}

// reject dependencyUpdates candidates with alpha or beta in their names:
tasks.named("dependencyUpdates") {
    resolutionStrategy {
        componentSelection { rules ->
            rules.all { ComponentSelection selection ->
                boolean rejected = ['alpha', 'beta', 'rc'].any { qualifier ->
                    selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
                }
                if (rejected) {
                    selection.reject('Release candidate')
                }
            }
        }
    }
}

tasks.named("generateStone", StoneTask) {
    String unusedClassesToGenerate = 'AuthError, PathRoot, PathRootError, AccessError, RateLimitError'
    String packageName = 'com.dropbox.core.v2'
    String globalRouteFilter = 'alpha_group=null and beta_group=null'
    stoneConfigs.addAll([
            new StoneConfig(
                    packageName: packageName,
                    globalRouteFilter: globalRouteFilter,
                    client: new ClientSpec(
                            name: 'DbxClientV2Base',
                            javadoc: 'Base class for user auth clients.',
                            requestsClassnamePrefix: "DbxUser",
                            routeFilter: 'auth="user" or auth="noauth" or auth="app, user"',
                            unusedClassesToGenerate: unusedClassesToGenerate,
                    ),
            ),
            new StoneConfig(
                    packageName: packageName,
                    globalRouteFilter: globalRouteFilter,
                    client: new ClientSpec(
                            name: 'DbxTeamClientV2Base',
                            javadoc: 'Base class for team auth clients.',
                            requestsClassnamePrefix: 'DbxTeam',
                            routeFilter: 'auth="team"',
                    ),
            ),
            new StoneConfig(
                    packageName: packageName,
                    globalRouteFilter: globalRouteFilter,
                    client: new ClientSpec(
                            name: 'DbxAppClientV2Base',
                            javadoc: 'Base class for app auth clients.',
                            requestsClassnamePrefix: "DbxApp",
                            routeFilter: 'auth="app" or auth="app, user"',
                    )
            ),

    ])
    outputDir.set(project.layout.buildDirectory.dir("generated_stone_source/main/src"))
    sourceSets { main { java.srcDir(outputDir) } }
}

tasks.named("generateTestStone", StoneTask) {
    String packageName = 'com.dropbox.core.stone'
    stoneConfigs.addAll([
            new StoneConfig(
                    packageName: packageName,
                    dataTypesOnly: true,
            ),
            new StoneConfig(
                    packageName: packageName,
                    client: new ClientSpec(
                            name: 'DbxClientV2Base',
                            javadoc: 'TestClass.',
                            requestsClassnamePrefix: "DbxTest",
                    )
            ),
    ])
    outputDir.set(project.layout.buildDirectory.dir("generated_stone_source/test/src"))
    sourceSets { test { java.srcDir(outputDir) } }
}

mavenPublishing {
    publishToMavenCentral(SonatypeHost.S01)
    signAllPublications()
}
