import os
import re

from .settings_addon import getAddonPreferences

from .utils import isWindows

from .utils_debug import debug_err, debug_log

def _ensureNpmFoldersExist():
    try:
        # see NE-3684
        # when running npx command this folder needs to exist on windows (it can be empty)
        # perhaps a bug in npm or npx 
        if isWindows():
            roamingNpmPath = os.getenv("APPDATA") + "/npm"
            if not os.path.exists(roamingNpmPath):
                os.makedirs(roamingNpmPath)
    except Exception as e:
        debug_err("Error creating npm folders", e)
        pass

def expectedPackageVersions():
    return {
        "@needle-tools/engine": "^4.5",
        "three": "npm:@needle-tools/three@^0.169.0",
        "@types/three": "0.169.0",
        "@needle-tools/helper": "^1.11.3",
        "@needle-tools/needle-component-compiler": "^2.4.1-pre"
    }

def getToolPackageNpxCommand(command:str):
    _ensureNpmFoldersExist()
    packageName = "@needle-tools/helper"
    version = expectedPackageVersions()[packageName]
    npxCommand =  f"npx --yes {packageName}@{version} {command}"
    print("cmd:", npxCommand)
    return npxCommand

_lastPackageVersions = {
    "directory": None,
    "versions": None,
}
def getPackageVersions(projectDirectory, packageNames:list) -> list:
    if not projectDirectory or projectDirectory is None: 
        return []
    global _lastPackageVersions
    if _lastPackageVersions["directory"] == projectDirectory:
        return _lastPackageVersions["versions"]
    
    packageJsonPath = projectDirectory + "/package.json"
    if not os.path.exists(packageJsonPath):
        return
    results = {}
    with open(packageJsonPath, "r") as f:
        packageJson = f.read()
        for key in packageNames:
            regex = r"\"(" + key + ")\": ?\"(.+?)\""
            match = re.search(regex, packageJson, re.MULTILINE)
            if match:
                results[key] = match.group(2)

    _lastPackageVersions["directory"] = projectDirectory
    _lastPackageVersions["versions"] = results
    return results

def updatePackageVersions(projectDirectory, force:bool = False):
    if projectDirectory is None or not projectDirectory: 
        return
    packageJsonPath = projectDirectory + "/package.json"
    if not os.path.exists(packageJsonPath):
        return
    # check if the user has disabled package management
    if(force == False):
        addonsettings = getAddonPreferences()
        if addonsettings:
            if addonsettings.manage_packages == False:
                return
    with open(packageJsonPath, "r") as f:
        packageJson = f.read()
        originalPackageJson = packageJson
        expected = expectedPackageVersions()
        changed = False
        for key in expected:
            version = expected[key]
            regex = r"\"(" + key + ")\": ?\"(.+?)\""
            subs = "\"\\1\": \""+ version + "\""
            match = re.search(regex, packageJson, re.MULTILINE)
            if match:
                currentVersion = match.group(2)
                if key != "three" and currentVersion.startswith("npm:"):
                    print("Skipping package version update for " + key + " because it is a explicit remote dependency")
                    continue
                # if a user has installed SOME other threejs version then we dont want to change that
                elif key == "three" and not currentVersion.startswith("npm:@needle-tools/three@") and len(currentVersion) > 5:
                    print("Skipping package version update for " + key + " because it has a three dependency that is NOT a needle-tools version: \"" + currentVersion + "\"")
                    continue
                if currentVersion.startswith("file:"):
                    # check if directorx exists
                    path = currentVersion[5:]
                    # check if path is absolute
                    if not os.path.isabs(path):
                        path = projectDirectory + "/" + path
                    if os.path.exists(path):
                        print("Skipping package version update for " + key + " because it is a local dependency")
                        continue
                    else:
                        debug_log("Updating package version for " + key + " because it is a local dependency but the path does not exist at " + path)
                if currentVersion == version:
                    continue
                changed = True
                debug_log("Updating package version for \"" + key + "\" from \"" + currentVersion + "\" to \"" + version + "\"")
                packageJson = re.sub(regex, subs, packageJson, 0, re.MULTILINE)
        if changed:
            debug_log("Updating package.json at " + projectDirectory)
            with open(packageJsonPath, "w") as f:
                f.write(packageJson)
