import com.android.annotations.NonNull
import com.android.build.OutputFile
import com.android.builder.testing.api.TestServer
import com.testdroid.api.APIClient
import com.testdroid.api.APIKeyClient
import com.testdroid.api.model.APIProject
import com.testdroid.api.model.APIUser
import groovy.json.JsonSlurper

buildscript {
  repositories {
    google()
    mavenCentral()
    jcenter()
  }

  dependencies {
    classpath "com.android.tools.build:gradle:$androidGradlePluginVersion"
    classpath "org.apache.httpcomponents:httpclient-android:4.3.3"
    classpath "com.testdroid:testdroid-api:2.71"
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
    classpath "io.objectbox:objectbox-gradle-plugin:$objectboxVersion"
    classpath "org.jlleitschuh.gradle:ktlint-gradle:8.2.0"
  }
}

plugins {
  id("com.android.application")
  id("checkstyle")
  id("com.github.triplet.play") version("2.2.1")
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'io.objectbox'
apply plugin: 'jacoco-android'
apply plugin: "org.jlleitschuh.gradle.ktlint"

repositories {
  google()
  mavenCentral()
  maven {
    url "https://maven.google.com"
  }
  jcenter()
}

String[] archs = ['arm64-v8a', 'armeabi-v7a', 'x86', 'x86_64']

dependencies {
  // use jdk8 java.time backport, as long app < Build.VERSION_CODES.O
  implementation("com.jakewharton.threetenabp:threetenabp:1.1.1")

  // Get kiwixlib online if it is not populated locally
  if (!shouldUseLocalVersion()) {
    implementation 'org.kiwix.kiwixlib:kiwixlib:6.0.2'
  } else {
    implementation 'com.getkeepsafe.relinker:relinker:1.3.1'
    implementation fileTree(include: ['*.aar'], dir: 'libs')
  }

  // Android Support
  implementation "androidx.appcompat:appcompat:$appCompatVersion"
  implementation "com.google.android.material:material:$materialVersion"
  implementation "androidx.cardview:cardview:$cardViewVersion"
  implementation "androidx.multidex:multidex:$multidexVersion"
  implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
  implementation "androidx.core:core-ktx:1.0.2"
  implementation "androidx.fragment:fragment-ktx:1.0.0"
  implementation "androidx.collection:collection-ktx:1.1.0"

  androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion")
  androidTestImplementation "androidx.test.espresso:espresso-web:$espressoVersion"
  androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
  androidTestImplementation("com.schibsted.spain:barista:$baristaVersion") {
    exclude group: "com.android.support.test.uiautomator"
  }
  androidTestImplementation("androidx.test.espresso:espresso-contrib:$espressoVersion")
  androidTestImplementation "androidx.annotation:annotation:$annotationVersion"
  androidTestImplementation "androidx.test.ext:junit:1.1.1"
  androidTestImplementation "androidx.test:runner:1.2.0"
  androidTestImplementation "androidx.test:rules:1.2.0"
  androidTestImplementation "androidx.test:core:1.2.0"
  androidTestImplementation "com.squareup.okhttp3:mockwebserver:3.6.0"
  androidTestUtil 'androidx.test:orchestrator:1.1.0'
  // Mockito
  androidTestImplementation "org.mockito:mockito-android:$mockitoVersion"

  // Tab indicator
  implementation "com.pacioianu.david:ink-page-indicator:$inkPageIndicatorVersion"

  // Dagger
  compileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
  androidTestCompileOnly "javax.annotation:javax.annotation-api:$javaxAnnotationVersion"
  implementation "com.google.dagger:dagger:$daggerVersion"
  implementation "com.google.dagger:dagger-android:$daggerVersion"
  kapt "com.google.dagger:dagger-compiler:$daggerVersion"
  kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
  kaptAndroidTest "com.google.dagger:dagger-compiler:$daggerVersion"

  // SquiDB
  implementation 'com.yahoo.squidb:squidb:2.0.0'
  implementation 'com.yahoo.squidb:squidb-annotations:2.0.0'
  kapt 'com.yahoo.squidb:squidb-processor:2.0.0'

  // Square
  implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
  implementation "com.squareup.okhttp3:logging-interceptor:$okHttpVersion"
  implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
  implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofitVersion"
  implementation("com.squareup.retrofit2:converter-simplexml:$retrofitVersion") {
    exclude group: "xpp3", module: "xpp3"
    exclude group: "stax", module: "stax-api"
    exclude group: "stax", module: "stax"
  }


  // ButterKnife
  implementation "com.jakewharton:butterknife:$butterKnifeVersion"
  kapt "com.jakewharton:butterknife-compiler:$butterKnifeVersion"

  // RxJava
  implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
  implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"

  // Leak canary
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0-alpha-2'

  implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
  implementation "android.arch.lifecycle:extensions:1.1.1"
  implementation "io.objectbox:objectbox-kotlin:$objectboxVersion"
  implementation "io.objectbox:objectbox-rxjava:$objectboxVersion"

  testImplementation "org.junit.jupiter:junit-jupiter:5.4.2"
  testImplementation "io.mockk:mockk:1.9"
  testImplementation "org.assertj:assertj-core:3.11.1"
  testImplementation 'com.jraska.livedata:testing-ktx:1.1.0'
  testImplementation 'androidx.arch.core:core-testing:2.0.1'

  androidTestImplementation "io.mockk:mockk-android:1.9"
  androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
  androidTestImplementation "org.assertj:assertj-core:3.11.1"
  androidTestImplementation ("org.simpleframework:simple-xml:2.7.1"){
    exclude module: 'stax'
    exclude module: 'stax-api'
    exclude module: 'xpp3'
  }
}

private boolean shouldUseLocalVersion() {
  file("./libs").exists()
}

// Set custom app import directory
def map = [:]
def custom = new File("app/src")
if (project.hasProperty("customDir")) {
  custom = file(project.property("customDir"))
}

// Set up flavours for each custom app in the directory
if (custom.listFiles()) {
  custom.eachFile() { file ->

    def fileName = file.getName()
    if (fileName.startsWith(".") ||
      fileName.contains("test") ||
      fileName == "main" ||
      fileName.contains("Test")) {
      return
    }
    map.put(fileName, file.getAbsolutePath())
  }
}

jacoco {
  toolVersion = "0.8.3"
}

tasks.withType(Test) {
  jacoco.includeNoLocationClasses = true
}

def branchName = System.getenv('TRAVIS_PULL_REQUEST') ?: "false" == "false"
  ? System.getenv('TRAVIS_BRANCH') ?: "local"
  : System.getenv('TRAVIS_PULL_REQUEST_BRANCH')
def buildNumber = System.getenv('TRAVIS_BUILD_NUMBER') ?: "dev"

ext {
  versionMajor = 2
  versionMinor = 5
  versionPatch = 1
}

private String generateVersionName() {
  "${ext.versionMajor}.${ext.versionMinor}.${ext.versionPatch}"
}

/*
* max version code: 21-0-0-00-00-00
* our template    : UU-D-A-ZZ-YY-XX
* where:
* X = patch version
* Y = minor version
* Z = major version (+ 20 to distinguish from previous, non semantic, versions of the app)
* A = number representing ABI split
* D = number representing density split
* U = unused
*/

private Integer generateVersionCode() {
  20 * 10000 +
    (ext.versionMajor * 10000) +
    (ext.versionMinor * 100) +
    (ext.versionPatch)
}

android {
  compileSdkVersion 28
  testServer new TestDroidUpload()

  defaultConfig {
    minSdkVersion 15
    targetSdkVersion 28
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    multiDexEnabled true
    vectorDrawables.useSupportLibrary = true
    archivesBaseName = "$buildNumber"
  }

  aaptOptions {
    cruncherEnabled true
  }

  testBuildType "debug"

  lintOptions {
    abortOnError true
    checkAllWarnings true
    warningsAsErrors true

    ignore 'SyntheticAccessor',
      //TODO stop ignoring below this
      'MissingTranslation',
      'CheckResult',
      'LabelFor',
      'DuplicateStrings',
      'LogConditional'

    warning 'UnknownNullness',
      'SelectableText',
      'IconDensities',
      'SyntheticAccessor'
    baseline file("lint-baseline.xml")
  }

  testOptions {
    execution 'ANDROIDX_TEST_ORCHESTRATOR'
    unitTests.returnDefaultValues = true
    unitTests.all {
      useJUnitPlatform()
      testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
        outputs.upToDateWhen { false }
        showStandardStreams = true
      }
    }
  }
  sourceSets {
    test {
      java.srcDirs += "$projectDir/src/testShared"
    }

    androidTest {
      java.srcDirs += "$projectDir/src/testShared"
    }
  }


  flavorDimensions "default"

  signingConfigs {
    release {
      storeFile file("../kiwix-android.keystore")
      storePassword System.getenv("KEY_STORE_PASSWORD") ?: "000000"
      keyAlias System.getenv("KEY_ALIAS") ?: "keystore"
      keyPassword System.getenv("KEY_PASSWORD") ?: "000000"
    }
  }

  buildTypes {

    // Main build type for debugging
    debug {
      multiDexKeepProguard file("multidex-instrumentation-config.pro")
      buildConfigField "String", "KIWIX_DOWNLOAD_URL", "\"http://mirror.download.kiwix.org/\""
      buildConfigField "boolean", "KIWIX_ERROR_ACTIVITY", "false"
      testCoverageEnabled true
    }

    // Release Type
    release {
      minifyEnabled true
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
      signingConfig signingConfigs.release
      buildConfigField "String", "KIWIX_DOWNLOAD_URL", "\"http://mirror.download.kiwix.org/\""
      buildConfigField "boolean", "KIWIX_ERROR_ACTIVITY", "true"
    }
  }

  productFlavors {
    // Vanilla Kiwix app
    kiwix {
      println "Configuring Kiwix"
      // Set vanilla config
      buildConfigField "boolean", "IS_CUSTOM_APP", "false"
      buildConfigField "boolean", "HAS_EMBEDDED_ZIM", "false"
      buildConfigField "String", "ZIM_FILE_NAME", "\"\""
      buildConfigField "long", "ZIM_FILE_SIZE", "0"
      buildConfigField "int", "CONTENT_VERSION_CODE", "0"
      buildConfigField "String", "ENFORCED_LANG", "\"\""
      resValue "string", "app_name", "Kiwix"
      resValue "string", "app_search_string", "Search Kiwix"
      if (project.hasProperty("version_code")) {
        def version_code = project.property("version_code")
        versionCode version_code.toInteger()
      } else {
        versionCode generateVersionCode()
      }
      if (project.hasProperty("version_name")) {
        versionName project.property("version_name")
      } else {
        versionName generateVersionName()
      }
    }

    // Custom apps built from a json file, zim file and icon set
    map.each { name, directory ->
      "$name" {
        println "Configuring $name"
        if (name == "kiwix") {
          return
        }
        if (file(directory + "/build.gradle").exists()) {
          apply from: directory + "/build.gradle"
        }
        def jsonFile
        if (project.hasProperty("jsonFile")) {
          // Read json file from properties e.g command line
          jsonFile = file(project.property("jsonFile"))
        } else {
          // If no file provided use the test file
          jsonFile = file(directory + "/info.json")
        }
        def parsedJson = new JsonSlurper().parseText(jsonFile.text)
        def sourceFile = file(parsedJson.zim_file)
        if (!sourceFile.exists()) {
          sourceFile = file(directory + "/" + parsedJson.zim_file)
        }
        if (parsedJson.embed_zim) {
          // Place content in each lib directory for embeded zims
          for (String archName : archs) {
            copy {
              from sourceFile
              into file(directory + "/jniLibs/" + archName)
              rename { String filename -> "libcontent.so" }
            }
          }
          parsedJson.zim_file = "libcontent.so"
        }
        // Set custom config from json
        applicationId "$parsedJson.package"
        buildConfigField "boolean", "IS_CUSTOM_APP", "true"
        buildConfigField "boolean", "HAS_EMBEDDED_ZIM", "$parsedJson.embed_zim"
        def filename
        if (parsedJson.zim_file.lastIndexOf("/") >= 0) {
          filename = parsedJson.zim_file.substring(parsedJson.zim_file.lastIndexOf("/") + 1)
        } else {
          filename = parsedJson.zim_file
        }
        buildConfigField "String", "ZIM_FILE_NAME", "\"$filename\""
        if (project.hasProperty("zim_file_size")) {
          def length = Long.parseLong(project.property("zim_file_size"))
          buildConfigField "long", "ZIM_FILE_SIZE", "${length}L"
        } else {
          long length = sourceFile.length()
          buildConfigField "long", "ZIM_FILE_SIZE", "${length}L"
        }
        if (project.hasProperty("version_code")) {
          def version_code = project.property("version_code")
          versionCode version_code.toInteger()
        } else {
          versionCode parsedJson.version_code.toInteger()
        }
        if (project.hasProperty("version_name")) {
          versionName project.property("version_name")
        } else {
          versionName parsedJson.version_name
        }
        if (project.hasProperty("content_version_code")) {
          def content_version_code = project.property("content_version_code")
          buildConfigField "int", "CONTENT_VERSION_CODE", "$content_version_code"
        } else if (parsedJson.content_version_code != null) {
          buildConfigField "int", "CONTENT_VERSION_CODE", "$parsedJson.content_version_code"
        } else if (project.hasProperty('version_code')) {
          def version_code = project.property('version_code')
          buildConfigField "int", "CONTENT_VERSION_CODE", "$version_code"
        } else if (parsedJson.version_code != null) {
          buildConfigField "int", "CONTENT_VERSION_CODE", "$parsedJson.version_code"
        }
        buildConfigField "String", "ENFORCED_LANG", "\"$parsedJson.enforced_lang\""
        resValue "string", "app_name", "$parsedJson.app_name"
        resValue "string", "app_search_string", "Search " + "$parsedJson.app_name"
      }
    }
  }

  // Set each custom apps respective source directory
  sourceSets {
    map.each { name, directory ->
      "$name" {
        setRoot directory
        jni.srcDirs = []
        jniLibs.srcDir directory + "/jniLibs"
      }
    }
  }

  compileOptions {
    encoding = "UTF-8"
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }

  dexOptions {
    javaMaxHeapSize "4g"
  }

  androidExtensions {
    experimental = true
  }

  def abiCodes = ['arm64-v8a': 6, 'x86': 3, 'x86_64': 4, 'armeabi-v7a': 5]
  def densityCodes = ['mdpi': 2, 'hdpi': 3, 'xhdpi': 4, 'xxhdpi': 5, 'xxxhdpi': 6]
  splits {
    abi {
      enable true
      reset()
      include "x86", "x86_64", 'armeabi-v7a', "arm64-v8a"
      universalApk true
    }
    density {
      enable true
      reset()
      include "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
    }
  }
  applicationVariants.all { variant ->
    variant.outputs.each { output ->
      def baseAbiVersionCode = abiCodes.get(output.getFilter(OutputFile.ABI)) ?: 0
      def baseDensityVersionCode = densityCodes.get(output.getFilter(OutputFile.DENSITY)) ?: 1
      output.versionCodeOverride =
        (baseDensityVersionCode * 10000000) +
          (baseAbiVersionCode * 1000000) +
          variant.versionCode
    }
  }
}

play {
  enabled = true
  serviceAccountCredentials = file("../google.json")
  track = "alpha"
  releaseStatus = "draft"
  resolutionStrategy = "fail"
}

ktlint {
  android = true
}

class TestDroidUpload extends TestServer {
  def buildNumber = System.getenv("TRAVIS_BUILD_NUMBER")
  def API_KEY = System.getenv("PUBLIC_TESTDROID_API_KEY")
  def TESTDROID_SERVER = "https://cloud.testdroid.com"
  def RUNNER_GATEWAY = System.getenv("TESTDROID_RUNNER_GATEWAY")
  def accessGroup = System.getenv("ACCESS_GROUP_ID")

  @Override
  String getName() {
    return "kiwixtest"
  }

  @Override
  void uploadApks(@NonNull String variantName, @NonNull File testApk, File testedApk) {
    APIUser.metaClass.shareFile { id, accessGroup ->
      System.out.println(id)
      try {
        delegate.postResource(createUri(selfURI, "/files/" + id + "/share"),
          [accessGroupId: accessGroup], APIProject.class)
      } catch (Exception e) {
        System.out.println(e.getLocalizedMessage())
      }
    }

    APIClient client = new APIKeyClient(TESTDROID_SERVER, API_KEY)
    APIUser user = client.me()
    String testId = user.uploadFile(testApk).getId()
    user.shareFile(testId, accessGroup)
    String testedId = user.uploadFile(testedApk).getId()
    user.shareFile(testedId, accessGroup)

    new URL(RUNNER_GATEWAY + "?apk=" + testedId + "&test=" + testId + "&buildno=" + buildNumber).
      getText()
  }

  @Override
  boolean isConfigured() {
    return true
  }
}

apply from: "${rootDir}/team-props/git-hooks.gradle"
afterEvaluate {
  tasks['preBuild'].dependsOn installGitHooks
}
