"""Tests for glob artifact pattern edge cases in OpenSpecService.

Task 6.3: Verifies glob handling for artifact reads, including empty results,
deeply nested directories, and path containment enforcement.
"""

from pathlib import Path

import pytest

from hangar.services.openspec import OpenSpecService


@pytest.fixture
def service_with_nested(tmp_path: Path) -> OpenSpecService:
    """Create service with deeply nested artifact files."""
    changes_dir = tmp_path / "openspec" / "changes" / "test-change"
    changes_dir.mkdir(parents=True)

    # Create deeply nested specs structure
    deep_dir = changes_dir / "specs" / "domain" / "auth" / "v2"
    deep_dir.mkdir(parents=True)

    (deep_dir / "login.md").write_text("# Login Spec\n\nDeep nested content.")
    (deep_dir / "oauth.md").write_text("# OAuth Spec\n\nOAuth content.")

    # Create a top-level spec too
    specs_dir = changes_dir / "specs"
    (specs_dir / "overview.md").write_text("# Overview\n\nTop-level spec.")

    return OpenSpecService(project_path=tmp_path)


@pytest.fixture
def service_empty(tmp_path: Path) -> OpenSpecService:
    """Create service with change dir but no matching files."""
    changes_dir = tmp_path / "openspec" / "changes" / "test-change"
    changes_dir.mkdir(parents=True)

    # Create a specs dir but with no .md files
    specs_dir = changes_dir / "specs"
    specs_dir.mkdir()
    (specs_dir / "readme.txt").write_text("Not a markdown file")

    return OpenSpecService(project_path=tmp_path)


class TestGlobArtifactEdgeCases:
    """Test glob pattern matching in read_artifact."""

    @pytest.mark.asyncio
    async def test_empty_glob_results(self, service_empty: OpenSpecService) -> None:
        """Glob with no matching files should return empty content."""
        result = await service_empty.read_artifact("test-change", "specs/**/*.md")
        assert result.content == ""
        assert result.status == "missing"

    @pytest.mark.asyncio
    async def test_deeply_nested_glob(self, service_with_nested: OpenSpecService) -> None:
        """Glob should match files in deeply nested directories."""
        result = await service_with_nested.read_artifact("test-change", "specs/**/*.md")
        assert result.status == "done"
        assert "# Login Spec" in result.content
        assert "# OAuth Spec" in result.content
        assert "# Overview" in result.content

    @pytest.mark.asyncio
    async def test_glob_includes_all_matches(self, service_with_nested: OpenSpecService) -> None:
        """Glob should include all matched files, not just the first."""
        result = await service_with_nested.read_artifact("test-change", "specs/**/*.md")
        # Should contain all 3 files
        assert result.content.count("<!-- ") == 3  # Each file gets a comment header

    @pytest.mark.asyncio
    async def test_specific_glob_pattern(self, service_with_nested: OpenSpecService) -> None:
        """More specific glob pattern should narrow results."""
        result = await service_with_nested.read_artifact("test-change", "specs/domain/auth/v2/*.md")
        assert result.status == "done"
        assert "# Login Spec" in result.content
        assert "# OAuth Spec" in result.content
        assert "# Overview" not in result.content

    @pytest.mark.asyncio
    async def test_path_containment_enforced(self, service_with_nested: OpenSpecService) -> None:
        """Glob with path traversal attempt should be rejected."""
        with pytest.raises(ValueError, match="escapes the allowed"):
            await service_with_nested.read_artifact("test-change", "../../../etc/passwd")

    @pytest.mark.asyncio
    async def test_non_glob_missing_file(self, service_empty: OpenSpecService) -> None:
        """Non-glob path to missing file should return empty/missing."""
        result = await service_empty.read_artifact("test-change", "nonexistent.md")
        assert result.content == ""
        assert result.status == "missing"

    @pytest.mark.asyncio
    async def test_glob_with_single_star(self, service_with_nested: OpenSpecService) -> None:
        """Single-star glob should only match one directory level."""
        result = await service_with_nested.read_artifact("test-change", "specs/*.md")
        assert result.status == "done"
        assert "# Overview" in result.content
        # Should NOT include deeply nested files
        assert "# Login Spec" not in result.content
