# --- auto-package bootstrap (run-safe) ---------------------------------
from ..imports import *
from .dot_utils import get_dot_range
from .sysroot_utils import get_sysroot,get_import_with_sysroot
def clean_imports(imports,commaClean=True):
    chars=["*"]
    if not commaClean:
        chars.append(',')
    if isinstance(imports,str):
        imports = imports.split(',')
    return [eatElse(imp,chars=chars) for imp in imports if imp]
def get_dot_range(import_pkg):
    count = 0
    for char in import_pkg:
        if char != '.':
            break
        count+=1
    return count
def get_cleaned_import_list(line,commaClean=True):
    cleaned_import_list=[]
    if IMPORT_TAG in line:
        imports = line.split(IMPORT_TAG)[1]
        cleaned_import_list+=clean_imports(imports,commaClean=commaClean)
    return cleaned_import_list
def get_module_from_import(imp,path=None):
    path = path or os.getcwd()
    i = get_dot_range(imp)
    imp = eatAll(imp,'.')
    sysroot = get_sysroot(path,i)
    return os.path.join(sysroot, imp)

def safe_import(name: str, *, package: str | None = None, member: str | None = None, file: str | None = None):
    """
    Wrapper over importlib.import_module that:
    - if `name` is relative (starts with '.'), ensures `package` is set.
    - if `package` is missing, derives it from `file` (defaults to __file__).
    """
    file = file or __file__
    ensure_package_context(file)
    if name.startswith(".") and not package:
        
            
        pkg_name = get_module_from_import(name,path=None)
        # also set __package__ if we are running as a script
        if __name__ == "__main__" and (not globals().get("__package__")):
            globals()["__package__"] = pkg_name
        package = pkg_name

    mod = importlib.import_module(name, package=package)
    return getattr(mod, member) if member else mod
def ensure_sysroot_in_syspath(sysroot):
    """
    Ensures Python can treat the sysroot as a valid package root.
    Prevents: ImportError: attempted relative import with no known parent package
    """
    if not sysroot:
        return

    sysroot = os.path.abspath(sysroot)

    # Insert package root ONLY once
    if sysroot not in sys.path:
        sys.path.insert(0, sysroot)
def force_import_module_from_path(name: str, path: str):
    """
    Import a module from an arbitrary file path.
    Allows relative imports that are 'above' the top-level directory.
    """

    path = os.path.abspath(path)
    module_dir = os.path.dirname(path)

    # Make sure parent directory is always importable
    if module_dir not in sys.path:
        sys.path.insert(0, module_dir)

    # Create a module spec that does NOT enforce package structure
    loader = importlib.machinery.SourceFileLoader(name, path)
    spec = importlib.util.spec_from_loader(name, loader)
    module = importlib.util.module_from_spec(spec)

    # 🔥 This line is the magic:
    # Pretend the module belongs to the directory as a package
    module.__package__ = name.rpartition('.')[0]

    # Exec module code, allowing internal imports to resolve
    loader.exec_module(module)

    return module
def dynamic_import(module_path: str, file_path: str, namespace: dict, all_imports=True):
    """
    Emulates:
        from module_path import *
    but includes private (_xxx) names too.
    """
    all_imports = if_none_default(all_imports,True,typ=bool)
    if module_path:
        module = force_import_module_from_path(module_path, file_path)

        # Import literally everything except dunders, unless you want them too.
        names = [n for n in dir(module) if n and ((not all_imports and not n.startswith("_")) or all_imports)]


        for name in names:
            namespace[name] = getattr(module, name)

        return module
def get_all_imports(directory=None,sysroot=None):
    sysroot = sysroot or get_caller_dir(2)
    directory = directory or sysroot
    globs = collect_globs(directory,allowed_exts='.py')
    for glo in [glo for glo in globs.get('files') if glo]:
        imp = get_import_with_sysroot(glo, sysroot)
        dynamic_import(imp,glo, globals())

