from .imports import *
from .constants import *
from .hugpy_marker import *
# ---------------------------------------------------------------------------
# Model Paths — One row of everything we know. All Optional — partial fills are valid.
# ---------------------------------------------------------------------------
def is_model_dir(directory: str) -> bool:
    """A model dir declares itself with a hugpy.json. Fall back to weight
    markers for dirs not yet stamped (legacy / first-run before backfill)."""
    if os.path.isfile(os.path.join(directory, HUGPY_MARKER)):
        return True
    try:
        entries = os.listdir(directory)
    except (OSError, NotADirectoryError):
        return False
    return any(e == "config.json" or e.lower().endswith((".gguf", ".safetensors"))
               for e in entries)

def get_model_dirs(models_home=None):
    root = get_model_home(models_home=models_home)
    found = []
    for dirpath, dirnames, filenames in os.walk(root):
        dirnames[:] = [d for d in dirnames
                       if not is_directory_excluded(join_path(dirpath, d))]
        if is_model_dir(dirpath):
            found.append(dirpath)
            dirnames[:] = []     # model dir is a leaf; don't descend
    return found

def hub_id_for(directory: str, fallback: str | None = None) -> str | None:
    """Repo id from the declared marker; path slice only if unstamped."""
    marker = read_hugpy_marker(directory)
    if marker and marker.get("hub_id"):
        return marker["hub_id"]
    return fallback


def get_model_dirs(models_home=None):
    """Walk MODELS_HOME and return every directory that actually holds a model,
    regardless of how deep it sits. Skips excluded dirs and never lists files."""
    root = get_model_home(models_home=models_home)
    found = []
    for dirpath, dirnames, filenames in os.walk(root):
        # prune excluded subtrees in-place so os.walk doesn't descend them
        dirnames[:] = [d for d in dirnames
                       if not is_directory_excluded(join_path(dirpath, d))]
        if is_model_dir(dirpath):
            found.append(dirpath)
            dirnames[:] = []          # don't descend into a model's own files
    return found

def get_hub_id_from_directory(directory, models_home=None):
    """Repo id = the path of the model dir relative to its task dir.
    (directory is the longer path; strip the task-dir prefix off the FRONT.)"""
    root = get_model_home(models_home=models_home)
    rel = directory[len(root):].strip("/")
    parts = rel.split("/")
    # rel = family/task/owner/repo[/subfolder]; drop family+task, keep the rest
    return "/".join(parts[2:]) if len(parts) > 2 else rel

def is_directory_excluded(directory):
    base = os.path.basename(directory.rstrip("/"))
    if base in EXCLUDE_DIR_NAMES:
        return True
    return any(base.startswith(p) for p in EXCLUDE_DIR_PREFIXES)

def exclude_dirs(directories):
    return [d for d in directories if not is_directory_excluded(d)]
