plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "app.chanora.poc.audio"
    compileSdk = 34

    defaultConfig {
        applicationId = "app.chanora.poc.audio"
        minSdk = 24      // matches DEC-004
        targetSdk = 34
        versionCode = 1
        versionName = "0.1.0-poc"

        ndk {
            // Keep all four common ABIs so the same APK works on both
            // the x86_64 emulator and a physical arm64 device.
            abiFilters += listOf("x86_64", "arm64-v8a", "armeabi-v7a", "x86")
        }
    }

    sourceSets {
        getByName("main") {
            // cargo-ndk drops .so files here.
            jniLibs.srcDirs("src/main/jniLibs")
        }
    }

    buildTypes {
        getByName("debug") {
            isMinifyEnabled = false
        }
        getByName("release") {
            isMinifyEnabled = false
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
    packaging {
        // Avoid duplicate-resource conflicts from native libs if any
        // future deps bring them in.
        resources.excludes += setOf("META-INF/AL2.0", "META-INF/LGPL2.1")
    }
}

dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
    implementation("androidx.appcompat:appcompat:1.7.0")
}

// ---------------------------------------------------------------------
// Rust cdylib build via cargo-ndk.
//
// Each ABI maps to a Rust target triple; cargo-ndk handles linker
// selection. The task copies the produced .so into the per-ABI
// jniLibs directory expected by Android Gradle Plugin.
// ---------------------------------------------------------------------

val rustCrateDir = rootProject.projectDir.parentFile  // ../  -> the spike root
val rustTargetDir = file("$rustCrateDir/target")
val jniLibsDir = file("$projectDir/src/main/jniLibs")

val cargoBuildRust = tasks.register("cargoBuildRust") {
    group = "build"
    description = "Builds the Rust cdylib for all enabled Android ABIs via cargo ndk."

    val abis = listOf(
        Triple("x86_64",       "x86_64-linux-android",      "x86_64"),
        Triple("arm64-v8a",    "aarch64-linux-android",     "arm64-v8a"),
        Triple("armeabi-v7a",  "armv7-linux-androideabi",   "armeabi-v7a"),
        Triple("x86",          "i686-linux-android",        "x86")
    )

    doLast {
        // Resolve cargo: try CARGO_HOME/bin first, then PATH, then the
        // rustup shim location.
        val cargoBinDir = System.getenv("CARGO_HOME")?.let { "$it/bin" }
            ?: "${System.getProperty("user.home")}/.cargo/bin"
        val cargo = listOf("$cargoBinDir/cargo", "/usr/local/bin/cargo", "/usr/bin/cargo")
            .firstOrNull { file(it).exists() }
            ?: error("cargo not found; install via rustup")
        val cargoNdkBin = listOf("$cargoBinDir/cargo-ndk", "/usr/local/bin/cargo-ndk")
            .firstOrNull { file(it).exists() }
        check(cargoNdkBin != null) { "cargo-ndk not installed (cargo install cargo-ndk)" }

        val ndkHome = System.getenv("ANDROID_NDK_HOME")
            ?: System.getenv("NDK_HOME")
            ?: "/opt/android-sdk/ndk/26.3.11579264"
        check(file(ndkHome).exists()) { "NDK not found at $ndkHome" }

        // cargo-ndk is a cargo subcommand; invoke via `cargo ndk ...`.
        // We must ensure cargo's PATH lookup can find cargo-ndk too.
        // `-p 26` selects API 26 for the NDK toolchain so cpal can
        // link against libaaudio (introduced in API 26). minSdk in
        // the Android module stays at 24 — the device just won't
        // execute the AAudio code path below API 26; cpal/Oboe falls
        // back to OpenSL ES there.
        val abiArgs = abis.flatMap { listOf("-t", it.first) }
        val cargoCmd = listOf(cargo, "ndk", "-P", "26") + abiArgs +
            listOf("-o", jniLibsDir.absolutePath, "build", "--release",
                   "--manifest-path", "$rustCrateDir/Cargo.toml")

        println("[cargoBuildRust] running: ${cargoCmd.joinToString(" ")}")

        exec {
            commandLine(cargoCmd)
            environment("ANDROID_NDK_HOME", ndkHome)
            environment("PATH", "$cargoBinDir:${System.getenv("PATH")}")
        }
    }
}

// Make Android's preBuild depend on the Rust build so AGP picks up the .so files.
tasks.matching { it.name == "preBuild" }.configureEach {
    dependsOn(cargoBuildRust)
}
