/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

plugins {
    id("com.android.application")
    id("com.facebook.react.codegen")
}

/**
 * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
 * and bundleReleaseJsAndAssets).
 * These basically call `react-native bundle` with the correct arguments during the Android build
 * cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
 * bundle directly from the development server. Below you can see all the possible configurations
 * and their defaults. If you decide to add a configuration block, make sure to add it before the
 * `apply from: "react.gradle"` line.
 *
 * project.ext.react = [
 *   // the name of the generated asset file containing your JS bundle
 *   bundleAssetName: "index.android.bundle",
 *
 *   // the entry file for bundle generation
 *   entryFile: "index.android.js",
 *
 *   // whether to bundle JS and assets in debug mode
 *   bundleInDebug: false,
 *
 *   // whether to bundle JS and assets in release mode
 *   bundleInRelease: true,
 *
 *   // whether to bundle JS and assets in another build variant (if configured).
 *   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
 *   // The configuration property is in the format 'bundleIn${productFlavor}${buildType}'
 *   // bundleInFreeDebug: true,
 *   // bundleInPaidRelease: true,
 *   // bundleInBeta: true,
 *
 *   // the root of your project, i.e. where "package.json" lives
 *   root: "../../",
 *
 *   // where to put the JS bundle asset in debug mode
 *   jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
 *
 *   // where to put the JS bundle asset in release mode
 *   jsBundleDirRelease: "$buildDir/intermediates/assets/release",
 *
 *   // where to put drawable resources / React Native assets, e.g. the ones you use via
 *   // require('./image.png')), in debug mode
 *   resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
 *
 *   // where to put drawable resources / React Native assets, e.g. the ones you use via
 *   // require('./image.png')), in release mode
 *   resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
 *
 *   // by default the gradle tasks are skipped if none of the JS files or assets change; this means
 *   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
 *   // date; if you have any other folders that you want to ignore for performance reasons (gradle
 *   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
 *   // for example, you might want to remove it from here.
 *   inputExcludes: ["android/**", "ios/**"],
 *
 *   // Root dir for all JS files for the app. Defaults to `root` above.
 *   jsRootDir: "../..",
 *
 *   // Enable Fabric at build time and runtime.
 *   enableFabric: true,
 *
 *   // Java package name to use for any codegen artifacts produced during build time.
 *   // Defaults to "com.facebook.fbreact.specs".
 *   codegenJavaPackageName: "com.facebook.fbreact.specs",
 * ]
 */

project.ext.react = [
    cliPath: "$rootDir/cli.js",
    bundleAssetName: "RNTesterApp.android.bundle",
    entryFile: file("../../js/RNTesterApp.android.js"),
    root: "$rootDir",
    inputExcludes: ["android/**", "./**", ".gradle/**"],
    composeSourceMapsPath: "$rootDir/scripts/compose-source-maps.js",
    hermesCommand: "$rootDir/node_modules/hermes-engine/%OS-BIN%/hermesc",
    enableHermesForVariant: { def v -> v.name.contains("hermes") },
    jsRootDir: "$rootDir/RNTester",
    enableCodegen: true, // Keep this here until it's sync'ed to Android template.
    enableFabric: (System.getenv('USE_FABRIC') ?: '0').toBoolean(),
]

apply from: "../../../../react.gradle"

/**
 * Set this to true to create three separate APKs instead of one:
 *   - A universal APK that works on all devices
 *   - An APK that only works on ARM devices
 *   - An APK that only works on x86 devices
 * The advantage is the size of the APK is reduced by about 4MB.
 * Upload all the APKs to the Play Store and people will download
 * the correct one based on the CPU architecture of their device.
 */
def enableSeparateBuildPerCPUArchitecture = true

/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = true

/**
 * Build and enable codegen-related output in RN Tester app.
 */
def enableCodegen = project.ext.react.enableCodegen

/**
 * Build and enable Fabric in RN Tester app.
 */
def enableFabric = project.ext.react.enableFabric

/**
 * Use the international variant of JavaScriptCore
 * This variant includes the ICU i18n library to make APIs like `Date.toLocaleString`
 * and `String.localeCompare` work when using with locales other than en-US.
 * Note that this variant is about 6MiB larger per architecture than the default.
 */
def useIntlJsc = false

android {
    compileSdkVersion 29

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    dexOptions {
        javaMaxHeapSize "4g"
    }
    flavorDimensions "vm"
    productFlavors {
        hermes {
            dimension "vm"
        }
        jsc {
            dimension "vm"
        }
    }

    defaultConfig {
        applicationId "com.facebook.react.uiapp"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testBuildType System.getProperty('testBuildType', 'debug')  // This will later be used to control the test apk build type
        testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
        buildConfigField("boolean", "ENABLE_FABRIC", "$enableFabric")
        buildConfigField("boolean", "ENABLE_TURBOMODULE", "$enableCodegen") // If using codegen, assume using TurboModule
    }
    signingConfigs {
        release {
            storeFile file(MYAPP_RELEASE_STORE_FILE)
            storePassword MYAPP_RELEASE_STORE_PASSWORD
            keyAlias MYAPP_RELEASE_KEY_ALIAS
            keyPassword MYAPP_RELEASE_KEY_PASSWORD
        }
    }
    splits {
        abi {
            enable enableSeparateBuildPerCPUArchitecture
            universalApk false
            reset()
            include "armeabi-v7a", "x86", "x86_64", "arm64-v8a"
        }
    }
    buildTypes {
        debug {
            signingConfig signingConfigs.release
        }
        release {
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            signingConfig signingConfigs.release
            // Detox-specific additions to pro-guard
            proguardFile "${rootProject.projectDir}/../node_modules/detox/android/detox/proguard-rules-app.pro"
        }
    }
    sourceSets.main {
        java {
            // SampleTurboModule.
            srcDirs += [
                "$rootDir/ReactCommon/react/nativemodule/samples/platform/android",
            ]
        }
    }
}

configurations {
  hermesDebugImplementation {}
  hermesReleaseImplementation {}
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

    // Build React Native from source
    implementation project(':ReactAndroid')

    implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"

    def hermesPath = '$projectDir/../../../../../node_modules/hermes-engine/android/'
    hermesDebugImplementation files(hermesPath + "hermes-debug.aar")
    hermesReleaseImplementation files(hermesPath + "hermes-release.aar")

    debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.fbjni'
    }

    debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
    }

    debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
        exclude group:'com.facebook.flipper'
    }

    if (useIntlJsc) {
        jscImplementation 'org.webkit:android-jsc-intl:+'
    } else {
        jscImplementation 'org.webkit:android-jsc:+'
    }

    // Use detox test library
    androidTestImplementation('com.wix:detox:+') { transitive = true }
    androidTestImplementation 'junit:junit:4.12'
}

react {
    jsRootDir = file("$rootDir/packages/rn-tester")
    reactNativeRootDir = file("$rootDir")
    useJavaGenerator = System.getenv("USE_CODEGEN_JAVAPOET") ?: false
}

if (enableCodegen) {
    // TODO: Move all this logic to CodegenPlugin.java.
    def reactAndroidProjectDir = project(':ReactAndroid').projectDir;
    def reactAndroidBuildDir = project(':ReactAndroid').buildDir;

    android {
        defaultConfig {
            externalNativeBuild {
                ndkBuild {
                    abiFilters "armeabi-v7a", "x86", "x86_64", "arm64-v8a"
                    arguments "APP_PLATFORM=android-21",
                            "APP_STL=c++_shared",
                            "NDK_TOOLCHAIN_VERSION=clang",
                            // The following paths assume building React Native from source.
                            "GENERATED_SRC_DIR=$buildDir/generated/source",
                            "PROJECT_BUILD_DIR=$buildDir",
                            "REACT_ANDROID_DIR=$reactAndroidProjectDir",
                            "REACT_ANDROID_BUILD_DIR=$reactAndroidBuildDir"
                    cFlags "-Wall", "-Werror", "-fexceptions", "-frtti", "-DWITH_INSPECTOR=1"
                    cppFlags "-std=c++1y"
                    targets "rntester_appmodules"
                }
            }
        }
        externalNativeBuild {
            ndkBuild {
                path "$projectDir/src/main/jni/Android.mk"
            }
        }
    }

    def packageReactNdkLibs = tasks.register("packageReactNdkLibs", Copy) {
        // TODO: handle extracting .so from prebuilt :ReactAndroid.
        dependsOn(":ReactAndroid:packageReactNdkLibs")
        from("$reactAndroidBuildDir/react-ndk/exported")
        into("$buildDir/react-ndk/exported")
    }

    def cleanProjectNdkBuild = tasks.register("cleanProjectNdkBuild", Exec) {
        ignoreExitValue(true)
        tasks.forEach {
            t ->
                if (t.name.startsWith("externalNativeBuildClean")) {
                    dependsOn(t);
                }
        }
        // This .cxx folder may cause stale ndkBuild configuration.
        // See https://stackoverflow.com/a/58288851.
        commandLine("rm", "-rf", "$projectDir/.cxx")
    }

    afterEvaluate {
        preBuild.dependsOn(packageReactNdkLibs)
        clean.dependsOn(cleanProjectNdkBuild)
    }
}
