import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import java.security.KeyFactory
import java.security.Signature
import java.security.spec.X509EncodedKeySpec

buildscript {
  ext.ReactNativeAlpr = [
    kotlinVersion: "2.0.21",
    minSdkVersion: 24,
    compileSdkVersion: 36
  ]

  ext.getExtOrDefault = { prop ->
    if (rootProject.ext.has(prop)) {
      return rootProject.ext.get(prop)
    }
    return ReactNativeAlpr[prop]
  }

  repositories {
    google()
    mavenCentral()
  }

  dependencies {
    classpath "com.android.tools.build:gradle:8.7.2"
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${getExtOrDefault('kotlinVersion')}"
  }
}

apply plugin: "com.android.library"

if (project.extensions.findByName("kotlin") == null) {
  apply plugin: "kotlin-android"
}

def packageJson = new JsonSlurper().parse(file("../package.json"))
def alprVersion = packageJson.version
// Set ALPR_CORE_DIR to the absolute path of a core checkout to build it from source instead of the binaries.
def coreRoot = System.getenv("ALPR_CORE_DIR")
def useCoreSource = coreRoot != null && coreRoot != ""
def coreDir = useCoreSource ? new File(coreRoot, "android/alpr") : null
if (useCoreSource && !coreDir.isDirectory()) {
  throw new GradleException("ALPR_CORE_DIR is set, but ${coreDir} does not exist")
}
android {
  namespace "app.parkr.alpr.reactnative"
  compileSdkVersion getExtOrDefault("compileSdkVersion")

  defaultConfig {
    minSdkVersion getExtOrDefault("minSdkVersion")
  }

  compileOptions {
    sourceCompatibility JavaVersion.VERSION_17
    targetCompatibility JavaVersion.VERSION_17
  }

  if (useCoreSource) {
    // LiteRT is built with Kotlin 2.4; let the app's older Kotlin read it when compiling the core sources.
    project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
      compilerOptions.freeCompilerArgs.add("-Xskip-metadata-version-check")
    }
    sourceSets {
      main {
        java.srcDirs += "${coreDir}/src/main/java"
        assets.srcDirs += "${coreDir}/src/main/assets"
      }
    }
  }
}

dependencies {
  implementation "com.facebook.react:react-android"
  implementation project(":expo-modules-core")
  if (useCoreSource) {
    implementation "androidx.exifinterface:exifinterface:1.3.7"
    implementation "androidx.lifecycle:lifecycle-runtime:2.6.2"
    implementation "com.google.android.gms:play-services-litert:17.0.0"
    implementation "androidx.camera:camera-core:1.5.1"
    implementation "androidx.camera:camera-camera2:1.5.1"
    implementation "androidx.camera:camera-lifecycle:1.5.1"
    implementation "androidx.camera:camera-view:1.5.1"
  } else {
    // From Maven Central, which React Native and Expo apps include by default.
    implementation "app.parkr:alpr:${alprVersion}"
  }
}

def alprPublicKeys = [
  "2026-1": "pebhl12eGUtAYyk_gJp6i6RHnVnSqC_46VLHmeIp0ss",
  "2026-2": "gFejwoYrliBTPgJbjyMIfKTC_Z2X_uiGEmtE0sWHbEE",
]

def alprTelemetryDisabled = {
  def dnt = System.getenv("DO_NOT_TRACK")
  def opt = System.getenv("ALPR_TELEMETRY")
  (dnt != null && dnt != "" && dnt != "0" && dnt.toLowerCase() != "false") || opt == "0" || opt == "false"
}

def alprLicenseState = { String key, String appId ->
  if (key == null || key.trim().isEmpty()) return "missing"
  try {
    def parts = key.trim().split("\\.")
    if (parts.length != 2) return "invalid"
    def decoder = Base64.getUrlDecoder()
    def payload = new JsonSlurper().parse(decoder.decode(parts[0]))
    def raw = alprPublicKeys[payload.kid]
    if (raw == null) return "invalid"
    def spki = new ByteArrayOutputStream()
    spki.write([0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00] as byte[])
    spki.write(decoder.decode(raw))
    def publicKey = KeyFactory.getInstance("Ed25519").generatePublic(new X509EncodedKeySpec(spki.toByteArray()))
    def verifier = Signature.getInstance("Ed25519")
    verifier.initVerify(publicKey)
    verifier.update(parts[0].getBytes("UTF-8"))
    if (!verifier.verify(decoder.decode(parts[1]))) return "invalid"
    if (!(payload.ids ?: []).contains(appId)) return "other-app"
    if (payload.exp != null && System.currentTimeMillis() / 1000 > (payload.exp as double)) return "expired"
    return payload.trial ? "trial" : "licensed"
  } catch (Exception ignored) {
    return "invalid"
  }
}

def alprAppInfo = { ->
  def app = rootProject.subprojects.find { it.plugins.hasPlugin("com.android.application") }
  if (app == null) return null
  def appId = app.android.defaultConfig.applicationId
  def manifest = app.file("src/main/AndroidManifest.xml")
  def key = null
  if (manifest.exists()) {
    def matcher = manifest.text =~ /android:name="app\.parkr\.alpr\.LICENSE_KEY"\s+android:value="([^"]+)"/
    if (matcher.find()) key = matcher.group(1)
  }
  return [appId: appId, key: key]
}

["Debug", "Release"].each { variant ->
  def check = tasks.register("alprBuildCheck${variant}") {
    outputs.upToDateWhen { false }
    doLast {
      def info = alprAppInfo()
      if (info == null || info.appId == null) return
      def state = alprLicenseState(info.key, info.appId)
      if (variant == "Release" && !(state in ["licensed", "trial"])) {
        logger.warn("react-native-alpr: no valid license key for ${info.appId} (${state}). Pro features will be disabled in this release build. Get a key or a 30-day trial at https://alpr.parkr.app")
      }
      if (alprTelemetryDisabled()) return
      def body = JsonOutput.toJson([
        source: "gradle",
        appId: info.appId,
        platform: "android",
        buildType: variant.toLowerCase(),
        sdkVersion: alprVersion,
        framework: "react-native",
        ci: System.getenv("CI") != null,
        licenseState: state,
      ])
      try {
        def connection = new URL("https://alpr.parkr.app/t/build").openConnection()
        connection.connectTimeout = 2000
        connection.readTimeout = 2000
        connection.requestMethod = "POST"
        connection.doOutput = true
        connection.setRequestProperty("Content-Type", "application/json")
        connection.outputStream.withStream { it.write(body.getBytes("UTF-8")) }
        connection.responseCode
      } catch (Exception ignored) {
      }
    }
  }
  tasks.matching { it.name == "pre${variant}Build" }.configureEach { dependsOn(check) }
}
