"""Regression: skill-extraction JSON parsing must tolerate a stray brace in prose.

maybe_extract_skill() sliced the LLM response from the first '{' to the last
'}'. When a model emits a stray brace in prose before the real object
(e.g. "uses {placeholder} then {...}"), that slice starts at the prose brace and
json.loads fails, so a perfectly good skill is silently dropped. Extraction now
tries each '{' start position and returns the first candidate that parses to a
JSON object.
"""
from services.memory import skill_extractor


def test_stray_brace_before_real_json_is_recovered():
    resp = (
        'The user mentioned {placeholder} before the actual JSON '
        '{"title": "Restart the service", "steps": ["a", "b"]}'
    )
    data = skill_extractor._extract_json_object(resp)
    assert isinstance(data, dict)
    assert data["title"] == "Restart the service"


def test_clean_json_object():
    data = skill_extractor._extract_json_object('{"title": "Y", "steps": []}')
    assert data["title"] == "Y"


def test_code_fenced_json():
    data = skill_extractor._extract_json_object('```json\n{"title": "Z"}\n```')
    assert data["title"] == "Z"


def test_no_json_object_returns_none():
    assert skill_extractor._extract_json_object("just prose, no object here") is None


def test_non_object_json_returns_none():
    # A bare array is valid JSON but not a skill object.
    assert skill_extractor._extract_json_object("[1, 2, 3]") is None


def test_empty_input_returns_none():
    assert skill_extractor._extract_json_object("") is None


def test_multiple_objects_returns_none():
    # Two complete valid non-overlapping JSON objects should return None (fail closed).
    resp = '{"title": "Restart", "steps": []} and {"title": "Stop", "steps": []}'
    assert skill_extractor._extract_json_object(resp) is None


def test_trailing_stray_brace_is_recovered():
    # A single valid JSON object followed by trailing text containing a stray brace should be recovered.
    resp = '{"title": "Restart the service", "steps": ["a"]} }'
    data = skill_extractor._extract_json_object(resp)
    assert isinstance(data, dict)
    assert data["title"] == "Restart the service"

