import sys
import shutil
import subprocess
import importlib
import os

# CLI exceptions: tool -> (install target, instructions)
CLI_EXCEPTIONS = {
    "firebase": ("firebase-tools", "npm install -g firebase-tools"),
    "heroku": ("heroku", "npm install -g heroku"),
    "npm": (None, "Install Node.js from https://nodejs.org/"),
    "git": (None, "Install Git from https://git-scm.com/"),
    "aws": ("awscli", "pip install awscli"),
    "terraform": (None, "Download from https://www.terraform.io/downloads"),
    "yarn": ("yarn", "npm install -g yarn"),
    "docker": (None, "Install Docker from https://www.docker.com/get-started")
}

# Python CLI wrappers we want to run directly
PYTHON_CLIS = ["black", "isort", "pylint", "flake8", "mypy", "pytest"]

def is_executable(cmd):
    """Check if CLI exists (handles .exe, .cmd on Windows)."""
    if shutil.which(cmd):
        return True
    if os.name == "nt" and (shutil.which(cmd + ".cmd") or shutil.which(cmd + ".exe")):
        return True
    return False

def get_python_cli_exe(cmd):
    """Return the full path to a Python CLI executable on Windows."""
    if os.name == "nt":
        scripts_path = os.path.join(sys.exec_prefix, "Scripts", cmd + ".exe")
        if os.path.exists(scripts_path):
            return scripts_path
    # fallback to PATH
    return shutil.which(cmd) or shutil.which(cmd + ".exe") or shutil.which(cmd + ".cmd")

def install_package(package):
    """Auto-install Python package if missing."""
    try:
        importlib.import_module(package)
    except ModuleNotFoundError:
        print(f"'{package}' not found, installing via pip...")
        subprocess.run([sys.executable, "-m", "pip", "install", package], check=True)

def run_cli(cmd, args):
    """Run CLI command, auto-installing if in exceptions."""
    if cmd in CLI_EXCEPTIONS:
        install_target, instructions = CLI_EXCEPTIONS[cmd]
        if install_target:
            # npm-based installs
            if install_target.endswith("-tools") or install_target in ["heroku", "yarn"]:
                if not is_executable("npm"):
                    print(f"'npm' is required to install '{install_target}'. {instructions}")
                    return
                print(f"'{cmd}' CLI not found. Installing {install_target} via npm...")
                npm_path = shutil.which("npm")
                if os.name == "nt":
                    subprocess.run(["cmd", "/c", npm_path, "install", "-g", install_target], check=True)
                else:
                    subprocess.run([npm_path, "install", "-g", install_target], check=True)
            else:
                # pip-based installs
                print(f"'{cmd}' CLI not found. Installing {install_target} via pip...")
                subprocess.run([sys.executable, "-m", "pip", "install", install_target], check=True)
        else:
            print(f"'{cmd}' CLI not found. {instructions}")
            return
    elif not is_executable(cmd):
        print(f"'{cmd}' CLI not found in PATH. Try installing it manually.")
        return

    # Resolve executable (Windows-safe for Python CLIs)
    exe_path = get_python_cli_exe(cmd)

    if exe_path is None:
        print(f"Could not find executable for {cmd}")
        return

    # Remove Caki folder from PATH temporarily (Windows collision fix)
    env = os.environ.copy()
    if os.name == "nt":
        current_dir = os.getcwd()
        paths = env["PATH"].split(";")
        filtered = [p for p in paths if os.path.normcase(current_dir) != os.path.normcase(p)]
        env["PATH"] = ";".join(filtered)

    # Run the executable
    if os.name == "nt" and exe_path.endswith(".cmd"):
        subprocess.run(["cmd", "/c", exe_path] + args, env=env)
    else:
        subprocess.run([exe_path] + args, env=env)

def run_library(package, code=None):
    """Auto-install Python package and execute code."""
    install_package(package)
    if code:
        exec(code, globals())
    else:
        print(f"Library '{package}' installed. No code to run.")

def main():
    import argparse
    parser = argparse.ArgumentParser(description="Caki: auto-install CLI or Python packages")
    parser.add_argument("target", help="Command or Python package to run")
    parser.add_argument("args", nargs="*", help="CLI arguments or Python code")
    parser.add_argument("--code", help="Python code to execute with library", default=None)
    parser.add_argument("-v", "--version", action="version", version="caki 0.7.5")
    args = parser.parse_args()

    target = args.target
    code = args.code
    extra_args = args.args

    # Determine CLI vs library
    if code is not None:
        # Force library execution if --code is given
        run_library(target, code)
    elif is_executable(target) or target in CLI_EXCEPTIONS:
        run_cli(target, extra_args)
    else:
        # Treat as library if no CLI exists
        if extra_args:
            code = " ".join(extra_args)
        run_library(target, code)

if __name__ == "__main__":
    main()