import java.util.concurrent.TimeUnit

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

// Derive versionCode from git commit count so sideload/Play upgrades
// always see a strictly-greater value without anyone remembering to
// bump by hand.  ANDROID_VERSION_CODE env var wins for CI pipelines
// that prefer explicit values; fallback is `1` when neither is
// available (e.g. building from a tarball with no .git).
val ledgrabVersionCode: Int = run {
    System.getenv("ANDROID_VERSION_CODE")?.toIntOrNull()?.let { return@run it }
    try {
        val process = ProcessBuilder("git", "rev-list", "--count", "HEAD")
            .directory(rootDir)
            .redirectErrorStream(true)
            .start()
        if (process.waitFor(5, TimeUnit.SECONDS) && process.exitValue() == 0) {
            process.inputStream.bufferedReader().readText().trim().toIntOrNull() ?: 1
        } else {
            1
        }
    } catch (_: Exception) {
        1
    }
}

android {
    namespace = "com.ledgrab.android"
    compileSdk = 34

    defaultConfig {
        applicationId = "com.ledgrab.android"
        minSdk = 24          // Android 7.0 — covers nearly all TV boxes
        targetSdk = 34
        // Derived from git commit count (or ANDROID_VERSION_CODE env var
        // in CI).  See ledgrabVersionCode above.  Was stuck at 1 before —
        // sideload updates silently refused to install.
        versionCode = ledgrabVersionCode
        versionName = "0.6.1"

        ndk {
            // All three ABIs: arm64-v8a (real TV hardware), x86_64 (modern
            // emulators), x86 (legacy emulators). Wheels in android/wheels/
            // must be kept in sync — see build-scripts/build-pydantic-core.sh.
            abiFilters += listOf("arm64-v8a", "x86_64", "x86")
        }
    }

    // Per-ABI APK splits — reduces download size by ~60% vs universal APK.
    // Each split contains only one native ABI's shared libraries + wheels.
    splits {
        abi {
            isEnable = true
            reset()
            include("arm64-v8a", "x86_64", "x86")
            isUniversalApk = true  // also produce a fat APK for sideloading
        }
    }

    // Signing config from env vars (CI) — only registered when all four are set.
    // Local release builds fall back to the debug signing config.
    val ciKeystorePath = System.getenv("ANDROID_KEYSTORE_PATH")
    val ciKeystorePassword = System.getenv("ANDROID_KEYSTORE_PASSWORD")
    val ciKeyAlias = System.getenv("ANDROID_KEY_ALIAS")
    val ciKeyPassword = System.getenv("ANDROID_KEY_PASSWORD")
    val hasCiSigning = listOf(ciKeystorePath, ciKeystorePassword, ciKeyAlias, ciKeyPassword)
        .all { !it.isNullOrBlank() } && file(ciKeystorePath!!).exists()

    signingConfigs {
        if (hasCiSigning) {
            create("release") {
                storeFile = file(ciKeystorePath!!)
                storePassword = ciKeystorePassword
                keyAlias = ciKeyAlias
                keyPassword = ciKeyPassword
            }
        }
    }

    buildTypes {
        release {
            // TODO(minify): keep R8 disabled until Chaquopy reflection is
            // verified end-to-end. Chaquopy resolves Kotlin classes & static
            // methods (PythonBridge, UsbSerialBridge, Root) by name from
            // Python via PyObject — silent stripping breaks the app at
            // runtime, after release. proguard-rules.pro contains keep
            // rules covering the known entry points, but until we have
            // a release smoke test that exercises every PyObject path we
            // do NOT ship a minified release.
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro",
            )
            signingConfig = if (hasCiSigning) {
                signingConfigs.getByName("release")
            } else {
                signingConfigs.getByName("debug")
            }
        }
    }

    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }

    kotlinOptions {
        jvmTarget = "17"
    }
}

chaquopy {
    defaultConfig {
        version = "3.11"

        pip {
            // Pre-built wheels directory (for pydantic-core etc.) as an
            // absolute file:// URI with forward slashes. Pip requires
            // exactly three slashes after `file:` for an empty-host local
            // path; the path-normalization differs by platform:
            //   Windows: absolute path is "C:/..."  → prefix "file:///"
            //   Linux:   absolute path is "/..."    → prefix "file://"
            // Using a fixed "file:///" prefix on both made CI produce
            // "file:////workspace/…", which pip rejects as non-local.
            val wheelsPath = rootDir.absolutePath.replace("\\", "/")
            val wheelsUrlPrefix = if (wheelsPath.startsWith("/")) "file://" else "file:///"
            options("--find-links", "$wheelsUrlPrefix$wheelsPath/wheels/")

            // ── Android-compatible dependencies ─────────────────
            // Listed explicitly because pyproject.toml includes
            // desktop-only packages with no Android wheels.
            // See CLAUDE.md "Android Dependency Sync" for policy.
            install("fastapi")
            install("uvicorn")           // without [standard] — no uvloop/httptools
            install("httpx")
            install("numpy")
            install("pydantic")          // needs pydantic-core wheel in wheels/
            install("pydantic-settings")
            install("PyYAML")
            install("structlog")
            install("python-json-logger")
            install("python-dateutil")
            install("python-multipart")
            install("jinja2")
            install("zeroconf")
            install("aiomqtt")
            install("openrgb-python")
            // opencv-python-headless: no cp311 Android wheel on Chaquopy.
            // LedGrab's cv2 usage is guarded with try/except ImportError
            // and falls back to numpy/Pillow alternatives on Android.
            install("Pillow")
            install("websockets")
            install("cryptography")     // AES-GCM secret-box for HA/MQTT credentials
        }
    }
}

// LedGrab Python source is included via a directory junction:
//   android/app/src/main/python/ledgrab -> server/src/ledgrab
// This is the standard Chaquopy way to include local Python packages.
// Create the junction (run from repo root, no admin needed):
//   cmd /c "mklink /J android\app\src\main\python\ledgrab server\src\ledgrab"


dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
    implementation("androidx.appcompat:appcompat:1.7.0")
    implementation("androidx.leanback:leanback:1.0.0")
    implementation("com.google.android.material:material:1.12.0")
    implementation("androidx.lifecycle:lifecycle-service:2.8.7")
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
    // QR code generation for displaying server URL on TV
    implementation("com.google.zxing:core:3.5.3")
    // USB-serial drivers (CH340, CP2102, FTDI, Prolific, CDC-ACM) for
    // driving Adalight/AmbiLED controllers plugged into Android TV boxes.
    implementation("com.github.mik3y:usb-serial-for-android:3.8.1")
}
