import mimetypes
from pathlib import Path
from .config import PathConfig

"""
One data stucture:
All Files - a set of files (Path)
Excluded files - a list/set of files (Path)
Included files - a list/set of files (Path)

Logic:
take a FileTree.All Files and filter it.

Input:

- Set of files

Logic:

1. filter excluded files to get initial included/excluded list, and add exclusions to Results.NotCounted
2. if custom inclusions exist, filter included files to get added exclusions and new included list. Add new exclusions to Results.NotCounted
4. Attempt to load included files to memory:
    4a. If successful, load into TokenQueue
    4b. If unsuccessful, add to Results.NotCounted
"""


def filter_file(file: Path, config: PathConfig, gitignore: set[Path]) -> bool:
    mime_type, _ = mimetypes.guess_type(file)
    if not mime_type:
        return True
    base_type = mime_type.split("/")[0]
    if base_type == "video":
        return True
    if base_type == "image" and not config.include_images:
        return True
    if not config.include_symlinks and file.is_symlink():
        return True
    if not config.include_dotfiles and any(part.startswith(".") for part in file.parts):
        return True
    if not config.include_gitignore and file in gitignore:
        return True
    if excluded_file(file, config.exclude):
        return True
    if not included_file(file, config.include):
        return True
    return False


def excluded_file(file: Path, exclusions: list[str]):
    return len(exclusions) > 0 and file in exclusions


def included_file(file: Path, inclusions: list[str]):
    return len(inclusions) > 0 and file in inclusions


def parse_gitignore(directory: Path) -> set[Path]:
    # TODO: ensure that this matches the gitignore spec: https://git-scm.com/docs/gitignore
    """
    Reads the .gitignore file in the given root directory, interprets its patterns,
    and returns a set of Paths representing all files and directories within root that match
    those patterns. Lines that are empty or start with '#' (comments) are ignored.

    For pattern matching:
      - Patterns that start with '/' are treated as relative to the root.
      - Patterns that contain a slash (but do not start with '/') are also treated as relative.
      - Patterns without any slash are searched recursively using rglob.
      - If a pattern ends with '/', it is interpreted as a directory (the trailing slash is removed
        before matching).

    Args:
        root (Path): The root directory containing the .gitignore file.

    Returns:
        Set[Path]: A set of Paths that match the patterns specified in the .gitignore file.
    """

    ignored: set[Path] = set()
    gitignore_file: Path = directory / ".gitignore"

    try:
        with gitignore_file.open("r") as f:
            patterns: list[str] = []
            for line in f:
                stripped = line.strip()
                # Skip empty lines or comments.
                if not stripped or stripped.startswith("#"):
                    continue
                patterns.append(stripped)
    except FileNotFoundError:
        return ignored  # No .gitignore file found.

    for pattern in patterns:
        # Check if the pattern is meant for directories (ends with a slash)
        if pattern.endswith("/"):
            # Remove trailing slash for glob matching.
            pattern = pattern.rstrip("/")

        # If the pattern starts with '/', it is anchored to the root.
        if pattern.startswith("/"):
            # Remove the leading slash.
            pattern = pattern[1:]
            # Use glob relative to the root (non-recursive).
            matches = directory.glob(pattern)
        # If the pattern contains a slash somewhere, treat it as relative to the root.
        elif "/" in pattern:
            matches = directory.glob(pattern)
        else:
            # Pattern without a slash: search recursively.
            matches = directory.rglob(pattern)

        for match in matches:
            ignored.add(Path(match))

    return ignored
