import com.android.tools.profgen.ArtProfileKt
import com.android.tools.profgen.ArtProfileSerializer
import com.android.tools.profgen.DexFile

plugins {
    id "com.android.application"
    id "kotlin-android"
    id "kotlin-kapt"
    id "kotlin-parcelize"
    id "checkstyle"
    id "org.sonarqube" version "4.0.0.2929"
}

android {
    compileSdk 34
    namespace 'org.schabi.newpipe'

    defaultConfig {
        applicationId "org.schabi.newpipe"
        resValue "string", "app_name", "NewPipe"
        minSdk 21
        targetSdk 33
        if (System.properties.containsKey('versionCodeOverride')) {
            versionCode System.getProperty('versionCodeOverride') as Integer
        } else {
            versionCode 1005
        }
        versionName "0.28.0"
        if (System.properties.containsKey('versionNameSuffix')) {
            versionNameSuffix System.getProperty('versionNameSuffix')
        }

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

        javaCompileOptions {
            annotationProcessorOptions {
                arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
            }
        }
    }

    buildTypes {
        debug {
            debuggable true

            // suffix the app id and the app name with git branch name
            def workingBranch = getGitWorkingBranch()
            def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "")
            if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
                // default values when branch name could not be determined or is master or dev
                applicationIdSuffix ".debug"
                resValue "string", "app_name", "NewPipe Debug"
            } else {
                applicationIdSuffix ".debug." + normalizedWorkingBranch
                resValue "string", "app_name", "NewPipe " + workingBranch
                archivesBaseName = 'NewPipe_' + normalizedWorkingBranch
            }
        }

        release {
            if (System.properties.containsKey('packageSuffix')) {
                applicationIdSuffix System.getProperty('packageSuffix')
                resValue "string", "app_name", "NewPipe " + System.getProperty('packageSuffix')
                archivesBaseName = 'NewPipe_' + System.getProperty('packageSuffix')
            }
            minifyEnabled true
            shrinkResources false // disabled to fix F-Droid's reproducible build
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            archivesBaseName = 'app'
        }
    }

    lint {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
        abortOnError false
        // suppress false warning ("Resource IDs will be non-final in Android Gradle Plugin version
        // 5.0, avoid using them in switch case statements"), which affects only library projects
        disable 'NonConstantResourceId'
    }

    compileOptions {
        // Flag to enable support for the new language APIs
        coreLibraryDesugaringEnabled true

        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
        encoding 'utf-8'
    }

    kotlinOptions {
        jvmTarget = JavaVersion.VERSION_17
    }

    sourceSets {
        androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
    }

    androidResources {
        generateLocaleConfig = true
    }

    buildFeatures {
        viewBinding true
        buildConfig true
    }

    packagingOptions {
        resources {
            // remove two files which belong to jsoup
            // no idea how they ended up in the META-INF dir...
            excludes += ['META-INF/README.md', 'META-INF/CHANGES',
                         // 'COPYRIGHT' belongs to RxJava...
                         'META-INF/COPYRIGHT']
        }
    }
}

ext {
    checkstyleVersion = '10.12.1'

    androidxLifecycleVersion = '2.6.2'
    androidxRoomVersion = '2.6.1'
    androidxWorkVersion = '2.8.1'

    stateSaverVersion = '1.4.1'
    exoPlayerVersion = '2.18.7'
    googleAutoServiceVersion = '1.1.1'
    groupieVersion = '2.10.1'
    markwonVersion = '4.6.2'

    leakCanaryVersion = '2.12'
    stethoVersion = '1.6.0'
}

configurations {
    checkstyle
    ktlint
}

checkstyle {
    getConfigDirectory().set(rootProject.file("checkstyle"))
    ignoreFailures false
    showViolations true
    toolVersion = checkstyleVersion
}

tasks.register('runCheckstyle', Checkstyle) {
    source 'src'
    include '**/*.java'
    exclude '**/gen/**'
    exclude '**/R.java'
    exclude '**/BuildConfig.java'
    exclude 'main/java/us/shandian/giga/**'

    classpath = configurations.checkstyle

    showViolations true

    reports {
        xml.getRequired().set(true)
        html.getRequired().set(true)
    }
}

def outputDir = "${project.buildDir}/reports/ktlint/"
def inputFiles = project.fileTree(dir: "src", include: "**/*.kt")

tasks.register('runKtlint', JavaExec) {
    inputs.files(inputFiles)
    outputs.dir(outputDir)
    getMainClass().set("com.pinterest.ktlint.Main")
    classpath = configurations.ktlint
    args "src/**/*.kt"
    jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
}

tasks.register('formatKtlint', JavaExec) {
    inputs.files(inputFiles)
    outputs.dir(outputDir)
    getMainClass().set("com.pinterest.ktlint.Main")
    classpath = configurations.ktlint
    args "-F", "src/**/*.kt"
    jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
}

afterEvaluate {
    if (!System.properties.containsKey('skipFormatKtlint')) {
        preDebugBuild.dependsOn formatKtlint
    }
    preDebugBuild.dependsOn runCheckstyle, runKtlint
}

sonar {
    properties {
        property "sonar.projectKey", "TeamNewPipe_NewPipe"
        property "sonar.organization", "teamnewpipe"
        property "sonar.host.url", "https://sonarcloud.io"
    }
}

dependencies {
/** Desugaring **/
    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs_nio:2.0.4'

/** NewPipe libraries **/
    // You can use a local version by uncommenting a few lines in settings.gradle
    // Or you can use a commit you pushed to GitHub by just replacing TeamNewPipe with your GitHub
    // name and the commit hash with the commit hash of the (pushed) commit you want to test
    // This works thanks to JitPack: https://jitpack.io/
    implementation 'com.github.TeamNewPipe:nanojson:e9d656ddb49a412a5a0a5d5ef20ca7ef09549996'
    // WORKAROUND: if you get errors with the NewPipeExtractor dependency, replace `v0.24.3` with
    // the corresponding commit hash, since JitPack sometimes deletes artifacts.
    // If there’s already a git hash, just add more of it to the end (or remove a letter)
    // to cause jitpack to regenerate the artifact.
    implementation 'com.github.TeamNewPipe:NewPipeExtractor:7adbc48a0aa872c016b8ec089e278d5e12772054'
    implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'

/** Checkstyle **/
    checkstyle "com.puppycrawl.tools:checkstyle:${checkstyleVersion}"
    ktlint 'com.pinterest:ktlint:0.45.2'

/** Kotlin **/
    implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"

/** AndroidX **/
    implementation 'androidx.appcompat:appcompat:1.7.1'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    implementation 'androidx.core:core-ktx:1.12.0'
    implementation 'androidx.documentfile:documentfile:1.0.1'
    implementation 'androidx.fragment:fragment-ktx:1.6.2'
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}"
    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
    implementation 'androidx.media:media:1.7.0'
    implementation 'androidx.preference:preference:1.2.1'
    implementation 'androidx.recyclerview:recyclerview:1.3.2'
    implementation "androidx.room:room-runtime:${androidxRoomVersion}"
    implementation "androidx.room:room-rxjava3:${androidxRoomVersion}"
    kapt "androidx.room:room-compiler:${androidxRoomVersion}"
    implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
    // Newer version specified to prevent accessibility regressions with RecyclerView, see:
    // https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-alpha01
    implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02'
    implementation "androidx.work:work-runtime-ktx:${androidxWorkVersion}"
    implementation "androidx.work:work-rxjava3:${androidxWorkVersion}"
    implementation 'com.google.android.material:material:1.11.0'
    implementation "androidx.webkit:webkit:1.9.0"

/** Third-party libraries **/
    // Instance state boilerplate elimination
    implementation 'com.github.livefront:bridge:v2.0.2'
    implementation "com.evernote:android-state:$stateSaverVersion"
    kapt "com.evernote:android-state-processor:$stateSaverVersion"

    // HTML parser
    implementation "org.jsoup:jsoup:1.17.2"

    // HTTP client
    implementation "com.squareup.okhttp3:okhttp:4.12.0"

    // Media player
    implementation "com.google.android.exoplayer:exoplayer-core:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:exoplayer-dash:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:exoplayer-database:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:exoplayer-datasource:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:exoplayer-hls:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:exoplayer-smoothstreaming:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:exoplayer-ui:${exoPlayerVersion}"
    implementation "com.google.android.exoplayer:extension-mediasession:${exoPlayerVersion}"

    // Metadata generator for service descriptors
    compileOnly "com.google.auto.service:auto-service-annotations:${googleAutoServiceVersion}"
    kapt "com.google.auto.service:auto-service:${googleAutoServiceVersion}"

    // Manager for complex RecyclerView layouts
    implementation "com.github.lisawray.groupie:groupie:${groupieVersion}"
    implementation "com.github.lisawray.groupie:groupie-viewbinding:${groupieVersion}"

    // Image loading
    //noinspection GradleDependency --> 2.8 is the last version, not 2.71828!
    implementation "com.squareup.picasso:picasso:2.8"

    // Markdown library for Android
    implementation "io.noties.markwon:core:${markwonVersion}"
    implementation "io.noties.markwon:linkify:${markwonVersion}"

    // Crash reporting
    implementation "ch.acra:acra-core:5.11.3"

    // Properly restarting
    implementation 'com.jakewharton:process-phoenix:2.1.2'

    // Reactive extensions for Java VM
    implementation "io.reactivex.rxjava3:rxjava:3.1.8"
    implementation "io.reactivex.rxjava3:rxandroid:3.0.2"
    // RxJava binding APIs for Android UI widgets
    implementation "com.jakewharton.rxbinding4:rxbinding:4.0.0"

    // Date and time formatting
    implementation "org.ocpsoft.prettytime:prettytime:5.0.8.Final"

/** Debugging **/
    // Memory leak detection
    debugImplementation "com.squareup.leakcanary:leakcanary-object-watcher-android:${leakCanaryVersion}"
    debugImplementation "com.squareup.leakcanary:plumber-android:${leakCanaryVersion}"
    debugImplementation "com.squareup.leakcanary:leakcanary-android-core:${leakCanaryVersion}"
    // Debug bridge for Android
    debugImplementation "com.facebook.stetho:stetho:${stethoVersion}"
    debugImplementation "com.facebook.stetho:stetho-okhttp3:${stethoVersion}"

/** Testing **/
    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.mockito:mockito-core:5.6.0'

    androidTestImplementation "androidx.test.ext:junit:1.1.5"
    androidTestImplementation "androidx.test:runner:1.5.2"
    androidTestImplementation "androidx.room:room-testing:${androidxRoomVersion}"
    androidTestImplementation "org.assertj:assertj-core:3.24.2"
}

static String getGitWorkingBranch() {
    try {
        def gitProcess = "git rev-parse --abbrev-ref HEAD".execute()
        gitProcess.waitFor()
        if (gitProcess.exitValue() == 0) {
            return gitProcess.text.trim()
        } else {
            // not a git repository
            return ""
        }
    } catch (IOException ignored) {
        // git was not found
        return ""
    }
}

// fix reproducible builds
project.afterEvaluate {
    tasks.compileReleaseArtProfile.doLast {
        outputs.files.each { file ->
            if (file.toString().endsWith(".profm")) {
                println("Sorting ${file} ...")
                def version = ArtProfileSerializer.valueOf("METADATA_0_0_2")
                def profile = ArtProfileKt.ArtProfile(file)
                def keys = new ArrayList(profile.profileData.keySet())
                def sortedData = new LinkedHashMap()
                Collections.sort keys, new DexFile.Companion()
                keys.each { key -> sortedData[key] = profile.profileData[key] }
                new FileOutputStream(file).with {
                    write(version.magicBytes$profgen)
                    write(version.versionBytes$profgen)
                    version.write$profgen(it, sortedData, "")
                }
            }
        }
    }
}
