"""
P1-7: IntentResolver Box Index Clamping

TDD RED: These tests enforce that:
1. VLM responses with string box indices are correctly parsed as integers.
2. Hallucinated indices (OOB) are gracefully rejected without crashing.
3. Common VLM hallucination patterns (e.g. {"box": "Box 5"}) are handled.
"""

from GramAddict.core.perception.intent_resolver import IntentResolver
from GramAddict.core.perception.spatial_parser import SpatialNode


class TestIntentResolverHardening:
    def test_parse_box_index_variants(self):
        """RED: Resolver should handle various VLM JSON formats and types."""
        resolver = IntentResolver()

        # Test basic int
        assert resolver._parse_box_index({"box": 5}) == 5

        # Test string int
        assert resolver._parse_box_index({"box": "5"}) == 5

        # Test prefixed string
        assert resolver._parse_box_index({"box": "Box 5"}) == 5

        # Test alternate keys
        assert resolver._parse_box_index({"selected_index": 3}) == 3
        assert resolver._parse_box_index({"box_index": "7"}) == 7

        # Test invalid
        assert resolver._parse_box_index({"box": "none"}) is None
        assert resolver._parse_box_index({"box": "null"}) is None

    def test_box_clamping_rejection(self):
        """RED: Reject indices that are not in the box_map."""
        resolver = IntentResolver()
        box_map = {0: SpatialNode(0, 0, 10, 10), 1: SpatialNode(10, 10, 20, 20)}

        # Index 99 is OOB
        assert resolver._validate_and_get_node(99, box_map) is None

        # Index 1 is valid
        assert resolver._validate_and_get_node(1, box_map) is not None
