"""Low-level helpers for filesystem and permission handling."""

from __future__ import annotations

import os
import subprocess
from pathlib import Path
from typing import List

from .config import project_root


def run(cmd: List[str], check: bool = True) -> subprocess.CompletedProcess:
    """
    Execute a subprocess command while capturing its output.

    Args:
        cmd: The command and arguments to run.
        check: Whether to raise `CalledProcessError` on non-zero exit codes.

    Returns:
        CompletedProcess with stdout/stderr captured as text.
    """
    return subprocess.run(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True,
        check=check,
    )


def maybe_sudo(cmd: List[str]) -> List[str]:
    """
    Ensure mount-related commands run with `sudo` unless already executed as root.

    Args:
        cmd: Original command to run.

    Returns:
        Possibly prefixed command list depending on the current effective UID.
    """
    if os.geteuid() == 0:
        return cmd
    if not cmd:
        return cmd
    head = cmd[0]
    if head in {"mount", "umount"} or cmd[:2] == ["mount", "--bind"]:
        return ["sudo"] + cmd
    return cmd


def have(cmd: str) -> bool:
    """
    Check whether the given executable exists on the PATH.

    Args:
        cmd: Executable name to check.

    Returns:
        True if `shutil.which` finds the program, False otherwise.
    """
    from shutil import which

    return which(cmd) is not None


def ensure_dir(path: Path) -> None:
    """
    Create a directory and all parents if they are missing.

    Args:
        path: Directory path to ensure.
    """
    path.mkdir(parents=True, exist_ok=True)


def resolve_source(path_str: str) -> Path:
    """
    Resolve a source path specified in the config.

    Relative paths are interpreted against the project root, while absolute
    paths are returned as-is (after normalization).

    Args:
        path_str: Path string from the configuration.

    Returns:
        Absolute Path to the source directory.
    """
    candidate = Path(path_str)
    if not candidate.is_absolute():
        candidate = (project_root() / candidate).resolve()
    return candidate


def on_ntfs(path: Path) -> bool:
    """
    Heuristic to determine if a path lives on NTFS (WSL /mnt/ prefix).

    Args:
        path: Path to evaluate.

    Returns:
        True for paths under `/mnt/`, False otherwise.
    """
    try:
        return str(path).startswith("/mnt/")
    except Exception:
        return False
