"""Tests for _editor_state ambient context in bridge responses."""

from __future__ import annotations

from godotiq.tools.output_limit import apply_output_limit


class TestEditorStateStructure:
    """Verify _editor_state dict shape and constraints."""

    def test_editor_state_has_required_keys(self) -> None:
        """_editor_state dict must contain open_scene, game_running, recent_errors."""
        state = {
            "open_scene": "res://Main.tscn",
            "game_running": False,
            "recent_errors": [],
        }
        assert "open_scene" in state
        assert "game_running" in state
        assert "recent_errors" in state

    def test_open_scene_is_string(self) -> None:
        """open_scene must be a string (res:// path or empty)."""
        for value in ["res://Main.tscn", ""]:
            state = {"open_scene": value, "game_running": False, "recent_errors": []}
            assert isinstance(state["open_scene"], str)

    def test_game_running_is_bool(self) -> None:
        """game_running must be a boolean."""
        for value in [True, False]:
            state = {"open_scene": "", "game_running": value, "recent_errors": []}
            assert isinstance(state["game_running"], bool)

    def test_recent_errors_is_list_of_strings(self) -> None:
        """recent_errors must be a list of strings."""
        errors = ["Error at tower.gd:40: Invalid node path", "Null reference"]
        state = {"open_scene": "", "game_running": False, "recent_errors": errors}
        assert isinstance(state["recent_errors"], list)
        assert all(isinstance(e, str) for e in state["recent_errors"])

    def test_recent_errors_max_three_entries(self) -> None:
        """recent_errors contains at most 3 entries even if the ring buffer has 10."""
        full_buffer = [f"error_{i}" for i in range(10)]
        sliced = full_buffer[-3:]
        assert len(sliced) == 3


class TestEditorStateBackwardCompat:
    """Python-side handling of missing _editor_state (older addon)."""

    def test_defaults_to_empty_dict_when_missing(self) -> None:
        """Bridge response without _editor_state should default to {}."""
        response = {"nodes_created": 5, "status": "ok"}
        editor_state = response.get("_editor_state", {})
        assert editor_state == {}

    def test_present_when_addon_provides_it(self) -> None:
        """Bridge response with _editor_state preserves it."""
        response = {
            "nodes_created": 5,
            "_editor_state": {
                "open_scene": "res://Level.tscn",
                "game_running": True,
                "recent_errors": ["some error"],
            },
        }
        editor_state = response.get("_editor_state", {})
        assert editor_state["open_scene"] == "res://Level.tscn"
        assert editor_state["game_running"] is True
        assert len(editor_state["recent_errors"]) == 1


class TestEditorStateOutputLimit:
    """Verify _editor_state survives apply_output_limit."""

    def test_editor_state_preserved_during_truncation(self) -> None:
        """_editor_state is preserved intact when output limit is applied."""
        big_list = [{"name": f"item_{i}", "data": "x" * 200} for i in range(100)]
        editor_state = {
            "open_scene": "res://Main.tscn",
            "game_running": False,
            "recent_errors": ["Error at line 40"],
        }
        result = {"items": big_list, "count": 100, "_editor_state": editor_state}
        out = apply_output_limit(result, "brief", list_keys=["items"])
        assert "_editor_state" in out
        assert out["_editor_state"] == editor_state
        assert out["_editor_state"]["open_scene"] == "res://Main.tscn"
        assert out["_editor_state"]["recent_errors"] == ["Error at line 40"]

    def test_other_keys_still_truncated_with_editor_state_present(self) -> None:
        """Other list keys are still truncated normally when _editor_state is present."""
        big_list = [{"name": f"item_{i}", "data": "x" * 200} for i in range(100)]
        result = {
            "items": big_list,
            "count": 100,
            "_editor_state": {"open_scene": "", "game_running": False, "recent_errors": []},
        }
        out = apply_output_limit(result, "brief", list_keys=["items"])
        assert len(out["items"]) < 100
        assert out.get("output_truncated") is True
