import groovy.json.JsonSlurper
import com.android.build.gradle.tasks.ExternalNativeBuildJsonTask

buildscript {
    def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['RNGH_kotlinVersion']

    repositories {
        mavenCentral()
        google()
    }

    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
        classpath("com.android.tools.build:gradle:8.10.1")
        classpath("com.diffplug.spotless:spotless-plugin-gradle:7.0.4")
    }
}

def isNewArchitectureEnabled() {
    // To opt-in for the New Architecture, you can either:
    // - Set `newArchEnabled` to true inside the `gradle.properties` file
    // - Invoke gradle with `-newArchEnabled=true`
    // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
    return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

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

def isGHExampleApp() {
    return safeExtGet("isGHExampleApp", false)
}

def resolveReactNativeDirectory() {
    def reactNativeLocation = safeExtGet("REACT_NATIVE_NODE_MODULES_DIR", null)
    if (reactNativeLocation != null) {
        return file(reactNativeLocation)
    }

    // Fallback to node resolver for custom directory structures like monorepos.
    def reactNativePackage = file(
        providers.exec {
            workingDir(rootDir)
            commandLine("node", "--print", "require.resolve('react-native/package.json')")
        }.standardOutput.asText.get().trim()
    )

    if (reactNativePackage.exists()) {
        return reactNativePackage.parentFile
    }

    throw new Exception(
            "[react-native-gesture-handler] Unable to resolve react-native location in " +
                    "node_modules. You should add project extension property (in app/build.gradle) " +
                    "`REACT_NATIVE_NODE_MODULES_DIR` with path to react-native."
    )
}

if (isNewArchitectureEnabled()) {
    apply plugin: 'com.facebook.react'
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

if (project == rootProject) {
    apply from: "spotless.gradle"
}

def getExternalLibVersion(project){
    def inputFile = new File(project.projectDir, "../package.json")
    def json = new JsonSlurper().parseText(inputFile.text)
    def libVerision = json.version as String
    def (major, minor, patch) = libVerision.tokenize('.')

    // Handle cases where version is a pre-release one, e.g. "2.3.0-alpha.1"
    def patchVersion = patch.find(/(\d+)/) ? patch.find(/(\d+)/) : "0"

    return [Integer.parseInt(major), Integer.parseInt(minor), Integer.parseInt(patchVersion)]
}

// Check whether Reanimated 2.3 or higher is installed alongside Gesture Handler
def shouldUseCommonInterfaceFromReanimated() {
    def reanimated = rootProject.subprojects.find { it.name == 'react-native-reanimated' }

    if (reanimated == null) {
        return false
    }

    def (major, minor, patch) = getExternalLibVersion(reanimated)
    
    return (major == 2 && minor >= 3) || major >= 3
}

def shouldUseCommonInterfaceFromRNSVG() {
    // common interface compatible with react-native-svg >= 15.11.2
    def rnsvg = rootProject.subprojects.find { it.name == 'react-native-svg' }

    if (rnsvg == null) {
        return false
    }

    def (major, minor, patch) = getExternalLibVersion(rnsvg)


    return (major == 15 && minor == 11 && patch >= 2) ||
            (major == 15 && minor > 11) ||
            major > 15
}

def reactNativeArchitectures() {
    def value = project.getProperties().get("reactNativeArchitectures")
    return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}

def REACT_NATIVE_DIR = resolveReactNativeDirectory()

def reactProperties = new Properties()
file("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) }

def REACT_NATIVE_VERSION = reactProperties.getProperty("VERSION_NAME")
def REACT_NATIVE_MINOR_VERSION = REACT_NATIVE_VERSION.split("\\.")[1].toInteger()

repositories {
    mavenCentral()
}

android {
    compileSdkVersion safeExtGet("compileSdkVersion", 33)

    namespace = "com.swmansion.gesturehandler"
    buildFeatures {
        buildConfig = true
        prefab = true
    }

    // Used to override the NDK path/version on internal CI or by allowing
    // users to customize the NDK path/version from their root project (e.g. for M1 support)
    if (rootProject.hasProperty("ndkPath")) {
        ndkPath rootProject.ext.ndkPath
    }
    if (rootProject.hasProperty("ndkVersion")) {
        ndkVersion rootProject.ext.ndkVersion
    }

    defaultConfig {
        minSdkVersion safeExtGet('minSdkVersion', 24)
        targetSdkVersion safeExtGet('targetSdkVersion', 33)
        buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
        buildConfigField "int", "REACT_NATIVE_MINOR_VERSION", REACT_NATIVE_MINOR_VERSION.toString()

        if (isNewArchitectureEnabled()) {
            var appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
            externalNativeBuild {
                cmake {
                    cppFlags "-O2", "-frtti", "-fexceptions", "-Wall", "-Werror", "-std=c++20", "-DANDROID"
                    arguments "-DREACT_NATIVE_DIR=${REACT_NATIVE_DIR}",
                            "-DREACT_NATIVE_MINOR_VERSION=${REACT_NATIVE_MINOR_VERSION}",
                            "-DANDROID_STL=c++_shared",
                            "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON"
                    abiFilters(*reactNativeArchitectures())
                }
            }
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    if (isNewArchitectureEnabled()) {
        externalNativeBuild {
            cmake {
                path "src/main/jni/CMakeLists.txt"
            }
        }
    }

    packagingOptions {
        // For some reason gradle only complains about the duplicated version of libreact_render libraries
        // while there are more libraries copied in intermediates folder of the lib build directory, we exclude
        // only the ones that make the build fail (ideally we should only include libgesturehandler but we
        // are only allowed to specify exclude patterns)
        exclude "**/libreact_render*.so"
        exclude "**/libreactnative.so"
        exclude "**/libjsi.so"
        exclude "**/libc++_shared.so"
    }

    sourceSets.main {
        java {
            if (shouldUseCommonInterfaceFromReanimated()) {
                srcDirs += 'reanimated/src/main/java'
            } else {
                srcDirs += 'noreanimated/src/main/java'
            }

            if (shouldUseCommonInterfaceFromRNSVG()) {
                srcDirs += 'svg/src/main/java'
            } else {
                srcDirs += 'nosvg/src/main/java'
            }

            if (isNewArchitectureEnabled()) {
                srcDirs += 'fabric/src/main/java'
            } else {
                // 'paper/src/main/java' includes files from codegen so the library can compile with
                // codegen turned off
                srcDirs += 'paper/src/main/java'
            }
        }
    }

    if (isGHExampleApp()) {
        tasks.withType(ExternalNativeBuildJsonTask) {
            compileTask ->
                compileTask.doLast {
                    def rootDir = new File("${project.projectDir}/..")
                    def generated = new File("${compileTask.abi.getCxxBuildFolder()}/compile_commands.json")
                    def output = new File("${rootDir}/compile_commands.json")
                    output.text = generated.text

                    println("Generated clangd metadata.")
                }
        }
    }
}

def kotlin_version = safeExtGet('kotlinVersion', project.properties['RNGH_kotlinVersion'])

dependencies {
    implementation 'com.facebook.react:react-native:+' // from node_modules


    if (shouldUseCommonInterfaceFromReanimated()) {
        // Include Reanimated as dependency to load the common interface
        implementation(rootProject.subprojects.find { it.name == 'react-native-reanimated' }) {
            // resolves "Duplicate class com.facebook.jni.CppException"
            exclude group: 'com.facebook.fbjni'
        }
    }

    if (shouldUseCommonInterfaceFromRNSVG()) {
        implementation rootProject.subprojects.find { it.name == 'react-native-svg' }
    }

    implementation 'androidx.appcompat:appcompat:1.7.0'
    implementation "androidx.core:core-ktx:1.16.0"
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
