def defaultMapboxMapsImpl = "mapbox"

def getDefaultMapboxMapsVersion() {
    def packageJson = new groovy.json.JsonSlurper().parseText(
        new File(projectDir.getPath(), "../package.json").text
    )
    return packageJson.mapbox.android
}

def defaultMapboxMapsVersion = getDefaultMapboxMapsVersion()

def safeExtGet(prop, fallback) {
    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}



def getCoroutinesVersion(kotlinVersion) {
    return kotlinVersion >= '1.9' ? '1.8.0' : '1.6.4'
}

// expo plugin
if (rootProject.ext.has('expoRNMapboxMapsImpl')) {
    rootProject.ext.set('RNMapboxMapsImpl', rootProject.ext.get('expoRNMapboxMapsImpl'))
}
if (rootProject.ext.has('expoRNMapboxMapsVersion')) {
    rootProject.ext.set('RNMapboxMapsVersion', rootProject.ext.get('expoRNMapboxMapsVersion'))
}

buildscript {
  repositories {
    google()
    mavenCentral()
  }

  ext {
    rnmapboxDefaultKotlinVersion = '1.7.21'
  }

  project.ext.set("kotlinVersion", rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : rnmapboxDefaultKotlinVersion)
  dependencies {
      classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${project.kotlinVersion}"
  }
}

apply plugin: 'com.facebook.react'
apply plugin: 'com.android.library'

if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") {
  apply plugin: 'kotlin-android'
}

android {
    def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION
    // Check AGP version for backward compatibility reasons
    if (agpVersion.tokenize('.')[0].toInteger() >= 7) {
        namespace = "com.rnmapbox.rnmbx"
    }
    if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "maplibre") {
        msg = '@rnmapbox/maps: Maplibre implementation has been removed, set RNMapboxMapsImpl to mapbox- see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre#android'
        logger.error(msg)
        throw new GradleException(msg)
    }
    else if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox-gl") {
        msg = '@rnmapbox/maps: MapboxGL implementation is DEPRECATED has been removed, set RNMapboxMapsImpl to mapbox  - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre#android'
        logger.error(msg)
        throw new GradleException(msg)
    }
    else if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") {
        // Validate Mapbox version is v11+
        def mapboxVersion = safeExtGet("RNMapboxMapsVersion", defaultMapboxMapsVersion)
        def majorMapboxVersion = mapboxVersion.split("\\.")[0] as Integer
        if (majorMapboxVersion < 11) {
            def msg = """
❌ ERROR: Mapbox v10 is no longer supported as of @rnmapbox/maps 10.3.0
Please upgrade to Mapbox v11.x or use @rnmapbox/maps 10.2.x
"""
            logger.error(msg)
            throw new GradleException(msg)
        }

        sourceSets {
            main {
                java.srcDirs = ['src/main/java']
                java.srcDirs += 'src/main/mapbox-v11-compat/v11'
                java.srcDirs += 'src/main/rn-compat/rn75'

                // Adapted from react-native-screens for consistency
                // https://github.com/software-mansion/react-native-screens/blob/main/android/build.gradle
                def resolveReactNativeDirectory = {
                    // 1. User-defined path
                    def userDefinedRnDirPath = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null)
                    if (userDefinedRnDirPath != null) {
                        return file(userDefinedRnDirPath)
                    }
                    
                    // 2. Standard monorepo location
                    def standardRnDirFile = file("$rootDir/../node_modules/react-native/")
                    if (standardRnDirFile.exists()) {
                        return standardRnDirFile
                    }
                    
                    // 3. Legacy location
                    def legacyRnDirFile = file("$projectDir/../node_modules/react-native/")
                    if (legacyRnDirFile.exists()) {
                        return legacyRnDirFile
                    }
                    
                    // 4. Try Node resolution as fallback
                    try {
                        def maybeRnPackagePath = providers.exec {
                            workingDir(rootDir)
                            commandLine("node", "--print", "require.resolve('react-native/package.json')")
                        }.standardOutput.asText.get().trim()
                        
                        if (maybeRnPackagePath != null && !maybeRnPackagePath.isBlank()) {
                            def maybeRnPackageFile = file(maybeRnPackagePath)
                            if (maybeRnPackageFile.exists()) {
                                return maybeRnPackageFile.parentFile
                            }
                        }
                    } catch (Exception e) {
                        logger.debug("@rnmapbox/maps: Node resolution for react-native failed: ${e.message}")
                    }
                    
                    return null
                }
                
                def detectReactNativeVersion = {
                    def rnDir = resolveReactNativeDirectory()
                    if (rnDir == null) {
                        return null
                    }
                    
                    // Try gradle.properties first (like react-native-screens)
                    def gradlePropertiesFile = file("$rnDir/ReactAndroid/gradle.properties")
                    if (gradlePropertiesFile.exists()) {
                        try {
                            def reactProperties = new Properties()
                            gradlePropertiesFile.withInputStream { reactProperties.load(it) }
                            def version = reactProperties.getProperty("VERSION_NAME")
                            if (version != null) {
                                return version
                            }
                        } catch (Exception e) {
                            logger.debug("@rnmapbox/maps: Failed to read gradle.properties: ${e.message}")
                        }
                    }
                    
                    // Fallback to package.json
                    def packageJsonFile = file("$rnDir/package.json")
                    if (packageJsonFile.exists()) {
                        try {
                            def packageJson = new groovy.json.JsonSlurper().parseText(packageJsonFile.text)
                            return packageJson.version
                        } catch (Exception e) {
                            logger.debug("@rnmapbox/maps: Failed to read package.json: ${e.message}")
                        }
                    }
                    
                    return null
                }
                
                // Add lifecycle compatibility source sets
                // Priority order:
                // 1. User-defined override (RNMapboxMapsLifecycleCompat)
                // 2. React Native version detection (0.77+ uses new API)
                // 3. Conservative default (v25 for better compatibility)
                
                def lifecycleCompat = safeExtGet("RNMapboxMapsLifecycleCompat", null)
                
                if (lifecycleCompat == "v25" || lifecycleCompat == "old") {
                    logger.info("@rnmapbox/maps: Using v25 lifecycle compatibility (ViewTreeLifecycleOwner.set) - user override")
                    java.srcDirs += 'src/main/lifecycle-compat/v25'
                } else if (lifecycleCompat == "v26" || lifecycleCompat == "new") {
                    logger.info("@rnmapbox/maps: Using v26 lifecycle compatibility (setViewTreeLifecycleOwner) - user override")
                    java.srcDirs += 'src/main/lifecycle-compat/v26'
                } else {
                    // Auto-detect based on React Native version
                    def rnVersion = null
                    try {
                        rnVersion = detectReactNativeVersion()
                    } catch (Exception e) {
                        logger.debug("@rnmapbox/maps: Failed to detect React Native version: ${e.message}")
                    }
                    
                    if (rnVersion != null) {
                        try {
                            def versionParts = rnVersion.split("\\.")
                            def majorVersion = versionParts[0].toInteger()
                            def minorVersion = versionParts[1].toInteger()
                            
                            // React Native < 0.77 needs the old lifecycle API
                            if (majorVersion == 0 && minorVersion < 77) {
                                logger.info("@rnmapbox/maps: Detected React Native ${rnVersion} - using v25 lifecycle compatibility (old API)")
                                java.srcDirs += 'src/main/lifecycle-compat/v25'
                            } else {
                                logger.info("@rnmapbox/maps: Detected React Native ${rnVersion} - using v26 lifecycle compatibility (new API)")
                                java.srcDirs += 'src/main/lifecycle-compat/v26'
                            }
                        } catch (Exception e) {
                            logger.warn("@rnmapbox/maps: Failed to parse React Native version '${rnVersion}', defaulting to v26 compatibility")
                            java.srcDirs += 'src/main/lifecycle-compat/v26'
                        }
                    } else {
                        // Cannot detect RN version, default to new API (v26) for future compatibility
                        def targetSdk = safeExtGet("targetSdkVersion", 28)
                        logger.info("@rnmapbox/maps: Unable to detect React Native version, using v26 lifecycle compatibility (new API, targetSdk=${targetSdk})")
                        logger.info("@rnmapbox/maps: If you encounter issues with RN < 0.78, set RNMapboxMapsLifecycleCompat='v25' in your app's android/build.gradle ext block")
                        java.srcDirs += 'src/main/lifecycle-compat/v26'
                    }
                }

            }
        }

        packagingOptions {
            pickFirst 'lib/x86/libc++_shared.so'
            pickFirst 'lib/x86_64/libc++_shared.so'
            pickFirst 'lib/arm64-v8a/libc++_shared.so'
            pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        }
    }
    else {
        msg = "RNMapboxMapsImpl should be one of: mapbox, mapbox-gl, maplibre got: ${safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl)}"
        logger.error(msg)
        throw new GradleException(msg)
    }

    compileSdkVersion safeExtGet("compileSdkVersion", 28)
    buildToolsVersion safeExtGet("buildToolsVersion", '28.0.3')

    defaultConfig {
        minSdkVersion safeExtGet('minSdkVersion', 21)
        targetSdkVersion safeExtGet('targetSdkVersion', 26)
        versionCode 1
        versionName "1.0"
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

def customizableDependencies(name, defaultDependencies) {
    if (rootProject.ext.has(name)) {
        def libs = rootProject.ext.get(name)
        if (libs instanceof CharSequence) {
            libs.split(';').each {
                implementation it
            }
        } else {
            libs.delegate = defaultDependencies.owner.delegate
            libs.call()
        }
    } else {
        defaultDependencies.delegate = defaultDependencies.owner.delegate
        defaultDependencies.call()
    }
}

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

    // React Native
    implementation "com.facebook.react:react-native:+"

    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${safeExtGet('kotlinxCoroutinesCoreVersion', getCoroutinesVersion(project.kotlinVersion))}"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${safeExtGet('kotlinxCoroutinesAndroidVersion', getCoroutinesVersion(project.kotlinVersion))}"

    // Mapbox SDK
    customizableDependencies('RNMapboxMapsLibs') {
        if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") {
            def targetSdk = safeExtGet("targetSdkVersion", 28)
            def mapboxVersion = safeExtGet("RNMapboxMapsVersion", defaultMapboxMapsVersion)
            
            // Use NDK27 variant for Android 15+ (API 35+) to support 16KB page size
            // Required by Google Play for apps targeting Android 15+ by November 1, 2025
            // See: https://github.com/rnmapbox/maps/issues/3896
            // Mapbox Docs: https://docs.mapbox.com/android/maps/guides/#ndk-27
            if (targetSdk >= 35) {
                implementation "com.mapbox.maps:android-ndk27:${mapboxVersion}"
            } else {
                implementation "com.mapbox.maps:android:${mapboxVersion}"
            }
            
            implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:6.11.0'
            implementation 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0'
        } else {
            msg = '@rnmapbox/maps: RNMapboxMapsImpl has invalid value - only mapbox supported - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre#android'
            logger.error(msg)
            throw new GradleException(msg)
        }
    }

    // Dependencies
    customizableDependencies('RNMapboxMapsSupportLibs') {
        //implementation "com.android.support:support-vector-drawable:28.0.0"
        implementation "com.android.support:support-annotations:28.0.0"
        //implementation "com.android.support:appcompat-v7:28.0.0"
    }
    customizableDependencies('RNMapboxMapsOkHTTPLibs') {
        implementation "com.squareup.okhttp3:okhttp:4.9.0"
        implementation "com.squareup.okhttp3:okhttp-urlconnection:4.9.0"
    }

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.2'
    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.2'
    testImplementation 'org.jetbrains.kotlin:kotlin-test'
    testImplementation "org.mockito.kotlin:mockito-kotlin:5.2.1"
}


tasks.withType(Test).configureEach {
    useJUnitPlatform()
}
