"""Tests for nogic.ignore module."""

from pathlib import Path

import pytest

from nogic.ignore import (
    DEFAULT_IGNORE_PATTERNS,
    load_gitignore_patterns,
    build_ignore_matcher,
)


class TestDefaultPatterns:
    def test_has_git_pattern(self):
        assert ".git/" in DEFAULT_IGNORE_PATTERNS

    def test_has_node_modules(self):
        assert "node_modules/" in DEFAULT_IGNORE_PATTERNS

    def test_has_pycache(self):
        assert "__pycache__/" in DEFAULT_IGNORE_PATTERNS

    def test_has_venv(self):
        assert ".venv/" in DEFAULT_IGNORE_PATTERNS


class TestLoadGitignorePatterns:
    def test_no_gitignore(self, tmp_path):
        patterns = load_gitignore_patterns(tmp_path)
        assert patterns == []

    def test_reads_gitignore(self, tmp_path):
        (tmp_path / ".gitignore").write_text("*.log\nbuild/\n")
        patterns = load_gitignore_patterns(tmp_path)
        assert patterns == ["*.log", "build/"]

    def test_skips_comments_and_blanks(self, tmp_path):
        (tmp_path / ".gitignore").write_text(
            "# comment\n\n*.log\n  \n# another comment\nbuild/\n"
        )
        patterns = load_gitignore_patterns(tmp_path)
        assert patterns == ["*.log", "build/"]

    def test_strips_whitespace(self, tmp_path):
        (tmp_path / ".gitignore").write_text("  *.log  \n  build/  \n")
        patterns = load_gitignore_patterns(tmp_path)
        assert patterns == ["*.log", "build/"]


class TestBuildIgnoreMatcher:
    def test_ignores_default_patterns(self, tmp_path):
        should_ignore = build_ignore_matcher(tmp_path)
        # .git directory
        git_dir = tmp_path / ".git"
        git_dir.mkdir()
        assert should_ignore(git_dir)

        # node_modules directory
        nm_dir = tmp_path / "node_modules"
        nm_dir.mkdir()
        assert should_ignore(nm_dir)

    def test_ignores_pyc_files(self, tmp_path):
        should_ignore = build_ignore_matcher(tmp_path)
        pyc_file = tmp_path / "module.pyc"
        pyc_file.touch()
        assert should_ignore(pyc_file)

    def test_allows_normal_files(self, tmp_path):
        should_ignore = build_ignore_matcher(tmp_path)
        py_file = tmp_path / "main.py"
        py_file.touch()
        assert not should_ignore(py_file)

    def test_gitignore_integration(self, tmp_path):
        (tmp_path / ".gitignore").write_text("secret/\n*.env\n")
        should_ignore = build_ignore_matcher(tmp_path)

        # Directory matched by gitignore
        secret_dir = tmp_path / "secret"
        secret_dir.mkdir()
        assert should_ignore(secret_dir)

        # File inside ignored directory
        secret_file = tmp_path / "secret" / "key.py"
        secret_file.parent.mkdir(exist_ok=True)
        secret_file.touch()
        assert should_ignore(secret_file)

        # .env file
        env_file = tmp_path / ".env"
        env_file.touch()
        assert should_ignore(env_file)

        # Normal file should pass
        normal = tmp_path / "app.py"
        normal.touch()
        assert not should_ignore(normal)

    def test_extra_patterns(self, tmp_path):
        should_ignore = build_ignore_matcher(tmp_path, extra_patterns=["*.txt"])
        txt_file = tmp_path / "notes.txt"
        txt_file.touch()
        assert should_ignore(txt_file)

        py_file = tmp_path / "main.py"
        py_file.touch()
        assert not should_ignore(py_file)

    def test_negation_patterns(self, tmp_path):
        (tmp_path / ".gitignore").write_text("*.log\n!important.log\n")
        should_ignore = build_ignore_matcher(tmp_path)

        # Regular log file should be ignored
        log_file = tmp_path / "debug.log"
        log_file.touch()
        assert should_ignore(log_file)

        # Negated file should NOT be ignored
        important = tmp_path / "important.log"
        important.touch()
        assert not should_ignore(important)

    def test_paths_outside_root(self, tmp_path):
        should_ignore = build_ignore_matcher(tmp_path)
        outside = Path("/some/other/path/file.py")
        assert should_ignore(outside)

    def test_nested_directory_pattern(self, tmp_path):
        (tmp_path / ".gitignore").write_text("logs/\n")
        should_ignore = build_ignore_matcher(tmp_path)

        # Nested logs directory
        nested = tmp_path / "src" / "logs"
        nested.mkdir(parents=True)
        assert should_ignore(nested)

    def test_wildcard_in_subdirectory(self, tmp_path):
        (tmp_path / ".gitignore").write_text("*.secret\n")
        should_ignore = build_ignore_matcher(tmp_path)

        deep_file = tmp_path / "config" / "db.secret"
        deep_file.parent.mkdir(parents=True)
        deep_file.touch()
        assert should_ignore(deep_file)
