from ..path.metafile import getmetapath, getmetafilepkg
from ..path.utils import __load__
import importlib, platform
from typing import Union
from pathlib import Path
from types import ModuleType as module
from importlib import metadata


def version(name: str | module) -> str:
    """
    Get the version string of a given Python module or package.

    This function attempts multiple strategies to determine the version:
    1. Check __version__ attribute.
    2. Check VERSION attribute.
    3. Check nested attributes like name.version or name.__about__.__version__.
    4. Try importlib.metadata.version(name) for installed packages.
    5. Fallback to the current Python version.

    Parameters
    ----------
    name : str | module
            Name of the module (e.g. "requests") or the module object itself.

    Returns
    -------
    str
            Version of the module or the current Python version if unavailable.
    """
    if not isinstance(name, (str, module)):
        raise TypeError(f"Expected str or module, got <{type(name).__name__}>")

    # Convert to module object if given as string
    if isinstance(name, str):
        try:
            name = __import__(name)
        except ImportError:
            try:
                return metadata.version(name)
            except metadata.PackageNotFoundError:
                return platform.python_version()

    # Try direct attributes
    for attr in ("__version__", "VERSION"):
        if hasattr(name, attr):
            return str(getattr(name, attr))

    # Try nested version sources
    nested_paths = [
        ("version",),
        ("__about__", "__version__"),
        ("about", "__version__"),
        ("__info__", "__version__"),
    ]
    for path in nested_paths:
        obj = name
        try:
            for p in path:
                obj = getattr(obj, p)
            if isinstance(obj, str):
                return obj
        except AttributeError:
            continue

    # Try importlib.metadata
    try:
        return metadata.version(name.__name__)
    except metadata.PackageNotFoundError:
        return platform.python_version()


def metafiles(name) -> list:
    """
    Get all metadata file paths associated with a given package or module.

    Parameters
    ----------
    name : str
            Name of the target package/module.

    Returns
    -------
    list[str]
            A list of absolute paths (as strings) pointing to metadata files
            located under the package’s metadata directory.

    Raises
    ------
    FileNotFoundError
            If no metadata path exists for the given module.

    Notes
    -----
    This function recursively scans the directory returned by `getmetapath(name)`
    using `.rglob("*")`, ensuring that every nested metadata file is included.

    Examples
    --------
    >>> metafiles("numpy")
    ['/usr/local/lib/python3.13/site-packages/numpy-1.26.4.dist-info/METADATA', ...]
    """
    return [str(metafile) for metafile in getmetapath(name).rglob("*")]


def show(name, *, text: bool = False) -> Union[None, str]:
    """
    Display or return the content of the metadata file for a given package.

    Parameters
    ----------
    name : str
            Name of the module or package to inspect.
    text : bool, optional
            If True, the function returns the file content as a string.
            If False, it prints the content directly to stdout.

    Returns
    -------
    str | None
            Returns a string if `text=True`, otherwise prints the content and returns None.

    Raises
    ------
    FileNotFoundError
            If the metadata file cannot be found for the specified module.
    TypeError
            If the metadata path is invalid or unreadable.

    Examples
    --------
    >>> show("requests")
    Metadata-Version: 2.1
    Name: requests
    Version: 2.31.0
    ...
    >>> show("requests", text=True)
    'Metadata-Version: 2.1\\nName: requests\\nVersion: 2.31.0\\n...'
    """
    try:
        load = __load__(getmetafilepkg(name))
        if text:
            return load
        print(load)
    except (TypeError, FileNotFoundError):
        raise FileNotFoundError(f"MetaFile not found for '{name}'") from None


def hasmeta(name) -> bool:
    """
    Check whether a metadata file exists for the given module or package.

    Parameters
    ----------
    name : str
            Name of the target package or module.

    Returns
    -------
    bool
            True if the metadata file exists, False otherwise.

    Examples
    --------
    >>> hasmeta("requests")
    True
    >>> hasmeta("nonexistent_package")
    False
    """
    try:
        return getmetafilepkg(name) is not None
    except Exception:
        return False
