plugins {
    id 'com.microsoft.identity.buildsystem' version '0.2.5'
    id 'com.android.library'
    id 'pmd'
    id 'checkstyle'
    id 'maven-publish'
    id 'kotlin-android'

    // Test retries
    id 'org.gradle.test-retry' version '1.5.6'
}

apply from: 'versioning/version_tasks.gradle'

group = 'com.microsoft.identity.client'

buildSystem {
    desugar = false
}

def enableCodeCoverage = false

if (project.hasProperty("codeCoverageEnabled")) {
    enableCodeCoverage = codeCoverageEnabled.toBoolean()
}

codeCoverageReport {
    coverage.enabled = enableCodeCoverage
}

// https://blog.gradle.org/gradle-flaky-test-retry-plugin
tasks.withType(Test) {
    retry {
        // The maximum number of test failures that are allowed before retrying is disabled.
        maxRetries = 2
        // The maximum number of times to retry an individual test.
        maxFailures = 10
        // Controls whether tests that initially fail and then pass on retry should fail the task.
        failOnPassedAfterRetry = false
    }
}

android {
    namespace "com.microsoft.identity.msal"
    compileOptions {
        // Sets Java compatibility to Java 8
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    compileSdk rootProject.ext.compileSdkVersion

    defaultConfig {
        multiDexEnabled true
        minSdkVersion rootProject.ext.minSdkVersion
        targetSdkVersion rootProject.ext.targetSdkVersion
        versionCode getAppVersionCode()
        versionName getAppVersionName()
        project.archivesBaseName = "msal"
        project.version = android.defaultConfig.versionName
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildFeatures {
        buildConfig = true
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }

    buildTypes {
        // testCoverageEnabled flag is set to true to get coverage reports for Android Tests
        debug {
            testCoverageEnabled enableCodeCoverage
            debuggable true
            buildConfigField("String", "VERSION_NAME", "\"${project.version}\"")
        }
        release {
            minifyEnabled false
            debuggable false
            consumerProguardFiles 'consumer-rules.pro'
            buildConfigField("String", "VERSION_NAME", "\"${project.version}\"")
        }
    }

    publishNonDefault true

    lintOptions {
        abortOnError true
        disable 'MissingPermission'
        disable 'LongLogTag'
        disable 'DefaultLocale'
        disable 'UnusedResources'
        disable 'GradleDependency'
        disable 'GradleOverrides'
        disable 'OldTargetApi'
        disable 'ExportedService'
    }

    testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }

    flavorDimensions "main"

    productFlavors {
        // The 'local' productFlavor sources common from mavenLocal and is intended to be used
        // during development.
        local {
            dimension "main"
            versionNameSuffix "-local"
        }

        snapshot {
            dimension "main"
        }

        // The 'dist' productFlavor sources common from a central repository and is intended
        // to be used for releases.
        dist {
            dimension "main"
        }
    }

    sourceSets {
        main {
            manifest.srcFile 'src/main/AndroidManifest.xml'
            java.srcDirs = ['src/main/java', 'src/main/kotlin']
        }
    }

    libraryVariants.all { variant ->
        variant.outputs.all {
            def fileName = "${archivesBaseName}-${version}.aar"
            outputFileName = fileName
        }
    }

    testOptions {
        unitTests.all {
            if (!project.hasProperty('labtest')) {
                // Disabling network based e2e tests if labtest not specified in build
                // to turn on pass labtest as build param
                // example: ./gradlew testLocalDebugUnitTest -Plabtest
                exclude 'com/microsoft/identity/client/e2e/tests/network'
            }
            testLogging {
                exceptionFormat = "full"
            }
        }
    }
}

// Task to generate javadoc
task javadoc(type: Javadoc) {
    failOnError false
    source = android.sourceSets.main.java.srcDirs
    configurations.api.setCanBeResolved(true)
    classpath += configurations.api

    options.memberLevel = JavadocMemberLevel.PUBLIC
    options.addStringOption('Xdoclint:none', '-quiet')

    exclude '**/BuildConfig.Java'
    exclude '**/R.java'
    destinationDir = reporting.file("$project.buildDir/outputs/jar/javadoc/")
}
// Task to generate javadoc.jar
task javadocJar(type: Jar, dependsOn: javadoc) {
    from javadoc.destinationDir
    archiveClassifier.set('javadoc')
    destinationDirectory = reporting.file("$project.buildDir/outputs/jar/")
}

task sourcesJar(type: Jar) {
    from android.sourceSets.main.java.srcDirs
    archiveClassifier.set('sources')
    destinationDirectory = reporting.file("$project.buildDir/outputs/jar/")
}

// In dev, we want to keep the dependencies (common4j, common) to 1.0.+ to be able to be consumed by daily dev pipeline.
// In release/*, we change these to specific versions being consumed.
def commonVersion = "1.0.+"
if (project.hasProperty("distCommonVersion")) {
    commonVersion = project.distCommonVersion
}
// Used for testfixtures
def common4jVersion = "1.0.+"
if (project.hasProperty("distCommon4jVersion")) {
    distCommon4jVersion = project.distCommon4jVersion
}
dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlinVersion"
    testImplementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlinVersion"
    androidTestImplementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.ext.kotlinVersion"

    implementation "androidx.appcompat:appcompat:$rootProject.ext.appCompatVersion"
    implementation "androidx.browser:browser:$rootProject.ext.browserVersion"
    implementation "com.google.code.gson:gson:$rootProject.ext.gsonVersion"
    implementation ("com.nimbusds:nimbus-jose-jwt:$rootProject.ext.nimbusVersion") {
        exclude module: 'asm'
    }
    implementation 'org.apache.httpcomponents.core5:httpcore5:5.3'
    implementation "androidx.constraintlayout:constraintlayout:$rootProject.ext.constraintLayoutVersion"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$rootProject.ext.kotlinXCoroutinesVersion"
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$rootProject.ext.kotlinXCoroutinesVersion"

    compileOnly "com.github.spotbugs:spotbugs-annotations:$rootProject.ext.spotBugsAnnotationVersion"

    compileOnly "org.projectlombok:lombok:$rootProject.ext.lombokVersion"
    annotationProcessor "org.projectlombok:lombok:$rootProject.ext.lombokVersion"

    // test dependencies
    testImplementation "junit:junit:$rootProject.ext.junitVersion"
    testImplementation "org.mockito:mockito-core:$rootProject.ext.mockitoCoreVersion"
    testImplementation ("org.robolectric:robolectric:$rootProject.ext.robolectricVersion")
    testImplementation "androidx.test:core:$rootProject.ext.androidxTestCoreVersion"    
    testLocalImplementation project(':testutils')
    testDistImplementation("com.microsoft.identity:testutils:0.0+") {
        exclude module: 'common'
        exclude group: 'com.microsoft.identity', module: 'LabApiUtilities'
    }
    testImplementation("org.mockito.kotlin:mockito-kotlin:$rootProject.ext.mockitoKotlinVersion") {
        exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
    }

    testImplementation "io.mockk:mockk:$rootProject.ext.mockkVersion"

    testImplementation "org.powermock:powermock-module-junit4:$rootProject.ext.powerMockVersion"
    testImplementation "org.powermock:powermock-module-junit4-rule:$rootProject.ext.powerMockVersion"
    testImplementation "org.powermock:powermock-api-mockito2:$rootProject.ext.powerMockVersion"
    testImplementation "org.powermock:powermock-classloading-xstream:$rootProject.ext.powerMockVersion"
    
    // instrumentation test dependencies
    androidTestImplementation "androidx.test.ext:junit:$rootProject.ext.androidxJunitVersion"
    // Set this dependency to use JUnit 4 rules
    androidTestImplementation "androidx.test:rules:$rootProject.rulesVersion"
    androidTestImplementation "org.mockito:mockito-android:$rootProject.ext.mockitoAndroidVersion"
    // 'local' flavor dependencies
    localApi(project(":common")) {
        transitive = true
    }

    snapshotApi(group: 'com.microsoft.identity', name: 'common', version: commonVersion, changing: true)

    distApi("com.microsoft.identity:common:${commonVersion}") {
        transitive = true
    }

    testLocalImplementation(testFixtures(project(":common4j")))
    testDistImplementation(testFixtures("com.microsoft.identity:common4j:${common4jVersion}"))

    implementation "io.opentelemetry:opentelemetry-api:$rootProject.ext.openTelemetryVersion"
}

def configDir = new File(buildscript.sourceFile.parentFile.parentFile, 'config')
ext.checkstyleConfigDir = "$configDir/checkstyle"

checkstyle {
    ignoreFailures = false
    reportsDir = file("$project.buildDir/outputs/")
}

task checkstyle(type: Checkstyle) {
    configFile file("${project.rootDir}/config/checkstyle/checkstyle.xml")

    configProperties.checkstyleConfigDir = checkstyleConfigDir
    configProperties.checkstyleSuppressionsPath = file("${project.rootDir}/config/checkstyle/suppressions.xml").absolutePath
    source 'src'
    include '**/*.java'
    exclude '**/gen/**'
    classpath = files()
}

pmd {
    ignoreFailures = false
    reportsDir = file("$project.buildDir/outputs/")
}

task pmd(type: Pmd) {
    description 'Run pmd'
    group 'verification'

    ruleSets = ["java-basic", "java-braces", "java-strings", "java-unusedcode"]
    source = fileTree('src/main/java')

    reports {
        xml.required = false
        html.required = true
    }
}

afterEvaluate {
    // This task customization renames the output AAR file after the 'assembleDistRelease' build.
    // When the 'renameOutput' property is set to true, it locates the generated AAR named
    // 'msal-dist-release.aar' and renames it to 'msal-<version>.aar'.
    // This is useful for publishing to repositories (e.g., Maven) that expect the artifact name
    // to include the version number.
    tasks.named("assembleDistRelease").configure {
        if (project.findProperty("renameOutput")?.toString()?.toBoolean() == true) {
            def buildFile = file("$buildDir/outputs/aar/${archivesBaseName}-dist-release.aar")
            println "Build file $buildFile"
            doLast {
                def renamedFile = file("$buildDir/outputs/aar/${archivesBaseName}-${version}.aar")
                println "Renaming build file $buildFile to '$renamedFile'"
                if (!buildFile.renameTo(renamedFile)) {
                    println "Rename failed!"
                }
            }
        }
    }
    publishing {
        publications {
            msal(MavenPublication) {
                from components.findByName('distRelease')
                groupId 'com.microsoft.identity.client'
                artifactId 'msal'
                //Edit the 'version' here for VSTS RC build
                version = project.version

                pom {
                    name = 'msal'
                    description = 'Microsoft Identity library for Android gives you the ability to add authentication to your application with just a few lines of additional code. Using our MSAL SDKs you can quickly and easily extend your existing application to all the employees that use MSA, B2C, Azure AD and Active Directory on-premises using Active Directory Federation Services, including Office365 customers.'
                    url = 'https://github.com/AzureAD/microsoft-authentication-library-for-android'
                    developers {
                        developer {
                            id = 'microsoft'
                            name = 'Microsoft'
                        }
                    }
                    licenses {
                        license {
                            name = 'MIT License'
                        }
                    }
                    inceptionYear = '2016'
                    scm {
                        url = 'https://github.com/AzureAD/microsoft-authentication-library-for-android/tree/master'
                    }
                    properties = [
                            branch : 'dev',
                            version: project.version
                    ]
                }
            }

        }

        // Repositories to which Gradle can publish artifacts
        repositories {
            maven {
                name "vsts-maven-adal-android"
                url "https://identitydivision.pkgs.visualstudio.com/_packaging/AndroidADAL/maven/v1"
                credentials {
                    username System.getenv("ENV_VSTS_MVN_ANDROID_MSAL_USERNAME") != null ? System.getenv("ENV_VSTS_MVN_ANDROID_MSAL_USERNAME") : project.findProperty("vstsUsername")
                    password System.getenv("ENV_VSTS_MVN_ANDROID_MSAL_ACCESSTOKEN") != null ? System.getenv("ENV_VSTS_MVN_ANDROID_MSAL_ACCESSTOKEN") : project.findProperty("vstsMavenAccessToken")
                }
            }
        }
    }
}

tasks.whenTaskAdded { task ->
    if (task.name.contains('assemble')) {
        task.dependsOn 'pmd'
    }

    if (task.name.contains('assemble')
        && !task.name.contains('Snapshot')
        && !task.name.contains('Test')
        && !task.name.contains('Local')) {
        task.dependsOn 'javadocJar', 'sourcesJar'
    }
}

// This is used to generate the pom file for publishing to external maven in maven-release-jobs.yml
tasks.withType(GenerateMavenPom).all {
    destination = layout.buildDirectory.file("poms/${project.name}-${project.version}.pom").get().asFile
}
