import groovy.json.JsonSlurper
import java.nio.file.Paths

ext.rnta_node_gradle = true

if (!hasProperty("rnta_utils_gradle")) {
    apply(from: "${buildscript.sourceFile.getParent()}/utils.gradle")
}

def _dependencies = [:]

/**
 * Finds the path of the installed npm package with the given name using Node's
 * module resolution algorithm, which searches "node_modules" directories up to
 * the file system root. This handles various cases, including:
 *
 *   - Working in the open-source RN repo:
 *       Gradle: /path/to/react-native/ReactAndroid
 *       Node module: /path/to/react-native/node_modules/[package]
 *
 *   - Installing RN as a dependency of an app and searching for hoisted
 *     dependencies:
 *       Gradle: /path/to/app/node_modules/react-native/ReactAndroid
 *       Node module: /path/to/app/node_modules/[package]
 *
 *   - Working in a larger repo (e.g., Facebook) that contains RN:
 *       Gradle: /path/to/repo/path/to/react-native/ReactAndroid
 *       Node module: /path/to/repo/node_modules/[package]
 *
 * The search begins at the given base directory (a File object). The returned
 * path is a string.
 */
ext.findNodeModulesPath = { String packageName, File baseDir ->
    def module = _dependencies[packageName]
    if (module != null) {
        return module.path
    }

    def basePath = baseDir.toPath().normalize()

    // Node's module resolution algorithm searches up to the root directory,
    // after which the base path will be null
    while (basePath) {
        def candidatePath = Paths.get(basePath.toString(), "node_modules", packageName)
        if (candidatePath.toFile().exists()) {
            // Resolve the real path in case we're dealing with symlinks
            def resolvedPath = candidatePath.toRealPath().toString()
            _dependencies[packageName] = [path: resolvedPath]
            return resolvedPath
        }

        basePath = basePath.getParent()
    }

    return null
}

ext.getPackageManifest = { String packageName, File baseDir ->
    def module = _dependencies[packageName]
    if (module != null && module.manifest != null) {
        return module.manifest
    }

    def packagePath = findNodeModulesPath(packageName, baseDir)
    def packageJson = file("${packagePath}/package.json")
    def manifest = new JsonSlurper().parseText(packageJson.text)
    _dependencies[packageName].manifest = manifest
    return manifest
}

ext.getPackageVersion = { String packageName, File baseDir ->
    def manifest = getPackageManifest(packageName, baseDir)
    return manifest["version"]
}

ext.getPackageVersionNumber = { String packageName, File baseDir ->
    return toVersionNumber(getPackageVersion(packageName, baseDir))
}
