"""Tests for output size limiting across tools.

Verifies that detail="brief" and detail="normal" enforce character limits,
and that path_filter / max_results work correctly on asset_registry.
"""

from __future__ import annotations

import json

from godotiq.session import GodotIQSession
from godotiq.tools.assets import _build_asset_registry
from godotiq.tools.spatial import _build_scene_map
from godotiq.tools.output_limit import apply_output_limit


class TestOutputLimitUtility:
    """Tests for the shared apply_output_limit function."""

    def test_brief_under_limit_unchanged(self) -> None:
        """Small output under brief limit is returned unchanged."""
        result = {"count": 5, "items": [1, 2, 3]}
        out = apply_output_limit(result, "brief")
        assert out == result

    def test_full_never_truncated(self) -> None:
        """detail='full' is never truncated regardless of size."""
        big_list = [{"name": f"item_{i}", "data": "x" * 200} for i in range(100)]
        result = {"items": big_list, "count": 100}
        out = apply_output_limit(result, "full")
        assert len(out["items"]) == 100

    def test_brief_truncates_large_list(self) -> None:
        """Large output with detail='brief' is truncated to fit limit."""
        big_list = [{"name": f"item_{i}", "data": "x" * 100} for i in range(50)]
        result = {"items": big_list, "count": 50}
        out = apply_output_limit(result, "brief", list_keys=["items"])
        serialized = json.dumps(out, default=str)
        assert len(serialized) <= 2000
        assert out.get("output_truncated") is True
        assert out["items_total"] == 50

    def test_normal_truncates_large_list(self) -> None:
        """Large output with detail='normal' is truncated to fit limit."""
        big_list = [{"name": f"item_{i}", "data": "x" * 200} for i in range(100)]
        result = {"items": big_list, "count": 100}
        out = apply_output_limit(result, "normal", list_keys=["items"])
        serialized = json.dumps(out, default=str)
        assert len(serialized) <= 8000
        assert out.get("output_truncated") is True


class TestAssetRegistryDetailLevels:
    """Tests for asset_registry detail parameter."""

    def test_brief_under_3000_chars(self, session: GodotIQSession) -> None:
        """asset_registry(detail='brief') output < 3000 chars."""
        result = _build_asset_registry(session, detail="brief")
        serialized = json.dumps(result, default=str)
        assert len(serialized) < 3000
        # Brief should have counts but not full asset list
        assert "total_assets" in result
        assert "by_category" in result
        assert "assets" not in result
        assert "by_directory" not in result

    def test_normal_under_8000_chars(self, session: GodotIQSession) -> None:
        """asset_registry(detail='normal') output < 8000 chars."""
        result = _build_asset_registry(session, detail="normal")
        serialized = json.dumps(result, default=str)
        assert len(serialized) < 8000
        # Normal has counts + unused_list but not full assets list
        assert "total_assets" in result
        assert "unused_list" in result
        assert "assets" not in result

    def test_full_has_all_keys(self, session: GodotIQSession) -> None:
        """asset_registry(detail='full') has assets and by_directory."""
        result = _build_asset_registry(session, detail="full")
        assert "assets" in result
        assert "by_directory" in result
        assert "by_category" in result


class TestAssetRegistryPathFilter:
    """Tests for asset_registry path_filter parameter."""

    def test_path_filter_returns_subset(self, session: GodotIQSession) -> None:
        """path_filter limits results to matching paths."""
        # Get all models first
        all_result = _build_asset_registry(session, category="models", detail="full")
        total_all = all_result["total_assets"]

        # Filter to a specific path
        filtered = _build_asset_registry(
            session, category="models", path_filter="printers", detail="full"
        )
        assert filtered["total_assets"] <= total_all
        # All returned assets should contain "printers" in path
        for asset in filtered["assets"]:
            assert "printers" in asset["path"]

    def test_path_filter_no_match(self, session: GodotIQSession) -> None:
        """path_filter with no matches returns zero assets."""
        result = _build_asset_registry(
            session, path_filter="nonexistent_folder_xyz", detail="full"
        )
        assert result["total_assets"] == 0


class TestAssetRegistryMaxResults:
    """Tests for asset_registry max_results parameter."""

    def test_max_results_caps_output(self, session: GodotIQSession) -> None:
        """max_results limits the number of assets returned."""
        result = _build_asset_registry(session, max_results=1, detail="full")
        assert len(result["assets"]) <= 1


class TestSceneMapDetailLevels:
    """Tests for scene_map output limiting."""

    def test_brief_under_3000_chars(self, session: GodotIQSession) -> None:
        """scene_map(detail='brief') output < 3000 chars."""
        # Use the main scene from fixture
        scenes = list(session._index.scenes.keys())
        if not scenes:
            return  # Skip if no scenes in fixture
        result = _build_scene_map(session, scenes[0], detail="brief")
        if "error" in result:
            return  # Skip if scene can't be resolved
        serialized = json.dumps(result, default=str)
        assert len(serialized) < 3000


class TestAnimationAuditDetail:
    """Tests for animation_audit detail parameter."""

    def test_audit_brief_has_no_issues_list(self) -> None:
        """animation_audit(detail='brief') returns counts without issues list."""
        from godotiq.tools.animation import _build_animation_audit
        # We need an anim_session for this, but we can test the brief structure
        # by checking the function exists and accepts detail param
        import inspect
        sig = inspect.signature(_build_animation_audit)
        assert "detail" in sig.parameters
