"""File path filtering for tracing."""

from __future__ import annotations

import os
from functools import cache
from pathlib import Path
from typing import cast

import git

from ..analysis._reference_graph import path_belongs_to_site_packages


def is_git_repo(file_path: str) -> bool:
    """Return True if the path is inside a git repository."""
    try:
        git.Repo(file_path, search_parent_directories=True)
    except git.InvalidGitRepositoryError:
        return False
    else:
        return True


@cache
def ignored_submodule_paths(module_root: str | Path) -> list[Path]:
    """Return resolved paths of git submodules to exclude from tracing."""
    module_root = str(module_root)
    if is_git_repo(module_root):
        git_repo = git.Repo(module_root, search_parent_directories=True)
        working_tree_dir = cast("Path", git_repo.working_tree_dir)
        try:
            return [
                Path(working_tree_dir, submodule.path).resolve()
                for submodule in git_repo.submodules
            ]
        except Exception as e:  # noqa: BLE001
            # no logger since used in the tracer
            print(f"Failed to get submodule paths {e!s}")  # noqa: T201
    return []


def is_test_file_by_pattern(file_path: Path) -> bool:
    """Return True if *file_path* looks like a test file."""
    name = file_path.name.lower()
    if name.startswith("test_") or name == "conftest.py":
        return True
    test_name_patterns = (
        ".test.",
        ".spec.",
        "_test.",
        "_spec.",
    )
    if any(p in name for p in test_name_patterns):
        return True
    path_str = str(file_path).lower()
    test_dir_patterns = (
        os.sep + "test" + os.sep,
        os.sep + "tests" + os.sep,
        os.sep + "__tests__" + os.sep,
    )
    return any(p in path_str for p in test_dir_patterns)


def filter_files_optimized(
    file_path: Path,
    tests_root: Path,
    ignore_paths: list[Path],
    module_root: Path,
) -> bool:
    """Return True if *file_path* should be traced."""
    tests_root_overlaps = (
        tests_root == module_root or module_root.is_relative_to(tests_root)
    )
    if tests_root_overlaps:
        if is_test_file_by_pattern(file_path):
            return False
    elif file_path.is_relative_to(tests_root):
        return False
    if file_path in ignore_paths or any(
        file_path.is_relative_to(ignore_path) for ignore_path in ignore_paths
    ):
        return False
    if path_belongs_to_site_packages(file_path):
        return False
    if not file_path.is_relative_to(module_root):
        return False
    submodule_paths = ignored_submodule_paths(module_root)
    return not (
        file_path in submodule_paths
        or any(
            file_path.is_relative_to(submodule_path)
            for submodule_path in submodule_paths
        )
    )
