"""Tests for ContextBuilder class."""

import tempfile
from pathlib import Path

import pytest

from scry_run.context import ContextBuilder


class TestContextBuilder:
    """Tests for ContextBuilder class."""

    @pytest.fixture
    def temp_project(self, tmp_path):
        """Create a temporary project structure."""
        # Create some Python files
        (tmp_path / "main.py").write_text("# Main file\nclass App:\n    pass\n")
        (tmp_path / "utils.py").write_text("# Utils\ndef helper(): pass\n")
        
        # Create a subdirectory with files
        sub = tmp_path / "lib"
        sub.mkdir()
        (sub / "core.py").write_text("# Core module\nclass Core:\n    pass\n")
        (sub / "__init__.py").write_text("from .core import Core\n")
        
        return tmp_path

    def test_init_default_root(self):
        """Test init with default root directory."""
        builder = ContextBuilder()
        
        assert builder.root_dir == Path.cwd()

    def test_init_custom_root(self, tmp_path):
        """Test init with custom root directory."""
        builder = ContextBuilder(tmp_path)
        
        assert builder.root_dir == tmp_path

    def test_collect_python_files(self, temp_project):
        """Test collecting Python files from project."""
        builder = ContextBuilder(temp_project)
        
        files = builder.collect_python_files()
        
        assert len(files) == 4
        names = {f.name for f in files}
        assert names == {"main.py", "utils.py", "core.py", "__init__.py"}

    def test_collect_skips_pycache(self, temp_project):
        """Test that __pycache__ directories are skipped."""
        pycache = temp_project / "__pycache__"
        pycache.mkdir()
        (pycache / "main.cpython-311.pyc").write_bytes(b"")
        
        builder = ContextBuilder(temp_project)
        files = builder.collect_python_files()
        
        # Should not include any files from __pycache__
        for f in files:
            assert "__pycache__" not in str(f)

    def test_collect_skips_venv(self, temp_project):
        """Test that venv directories are skipped."""
        venv = temp_project / ".venv"
        venv.mkdir()
        (venv / "lib").mkdir()
        (venv / "lib" / "something.py").write_text("# venv file")
        
        builder = ContextBuilder(temp_project)
        files = builder.collect_python_files()
        
        # Should not include any files from .venv
        for f in files:
            assert ".venv" not in str(f)

    def test_collect_skips_hidden_dirs(self, temp_project):
        """Test that hidden directories are skipped."""
        hidden = temp_project / ".hidden"
        hidden.mkdir()
        (hidden / "secret.py").write_text("# hidden file")
        
        builder = ContextBuilder(temp_project)
        files = builder.collect_python_files()
        
        for f in files:
            assert ".hidden" not in str(f)

    def test_read_file_content(self, temp_project):
        """Test reading file content."""
        builder = ContextBuilder(temp_project)
        
        content = builder.read_file_content(temp_project / "main.py")
        
        assert "# Main file" in content
        assert "class App:" in content

    def test_read_file_content_nonexistent(self, temp_project):
        """Test reading nonexistent file returns empty string."""
        builder = ContextBuilder(temp_project)
        
        content = builder.read_file_content(temp_project / "nonexistent.py")
        
        assert content == ""

    def test_build_context_includes_files(self, temp_project):
        """Test that build_context includes all Python files."""
        builder = ContextBuilder(temp_project)
        
        context = builder.build_context(
            class_name="MyClass",
            attr_name="my_method",
        )
        
        # Should include file contents
        assert "# Main file" in context
        assert "class App:" in context
        assert "# Utils" in context
        assert "def helper():" in context
        assert "# Core module" in context

    def test_build_context_includes_hole_marker(self, temp_project):
        """Test that build_context includes hole marker."""
        builder = ContextBuilder(temp_project)
        
        context = builder.build_context(
            class_name="MyClass",
            attr_name="my_method",
        )
        
        assert "MISSING CODE" in context
        assert "Class: MyClass" in context
        assert "Missing attribute: my_method" in context

    def test_build_context_includes_class_source(self, temp_project):
        """Test that build_context includes class source when provided."""
        builder = ContextBuilder(temp_project)
        
        class_source = "class MyClass:\n    '''My class docstring.'''\n    pass"
        
        context = builder.build_context(
            class_name="MyClass",
            attr_name="my_method",
            class_source=class_source,
        )
        
        assert "class MyClass:" in context
        assert "My class docstring" in context

    def test_build_minimal_context(self, temp_project):
        """Test build_minimal_context with just class source."""
        builder = ContextBuilder(temp_project)
        
        class_source = "class Foo:\n    '''A foo.'''\n    pass"
        
        context = builder.build_minimal_context(
            class_source=class_source,
            class_name="Foo",
            attr_name="bar",
        )
        
        assert "class Foo:" in context
        assert "MISSING CODE" in context
        assert "Class: Foo" in context
        assert "Missing attribute: bar" in context
        
        # Should NOT include other files
        assert "# Main file" not in context

    def test_build_minimal_context_with_additional(self, temp_project):
        """Test build_minimal_context with additional context."""
        builder = ContextBuilder(temp_project)
        
        context = builder.build_minimal_context(
            class_source="class Foo: pass",
            class_name="Foo",
            attr_name="bar",
            additional_context="The bar method should return 42.",
        )
        
        assert "Additional context:" in context
        assert "bar method should return 42" in context

    def test_build_context_includes_project_name(self, temp_project):
        """Test that build_context includes project name in header."""
        builder = ContextBuilder(temp_project)
        
        context = builder.build_context(
            class_name="MyClass",
            attr_name="method",
        )
        
        assert f"# Project: {temp_project.name}" in context

    def test_collect_sorts_files(self, temp_project):
        """Test that collected files are sorted."""
        builder = ContextBuilder(temp_project)
        
        files = builder.collect_python_files()
        
        # Files should be sorted by path
        names = [f.name for f in files]
        assert names == sorted(names)
