"""tests/test_features_step_normalizer.py — Unit tests for StepNormalizer / normalize_steps."""
import pytest
import warnings

pytestmark = pytest.mark.unit

REACT_STEPS = [
    {"thought": "thinking", "action_type": "Search", "action_arg": "query", "observation": "result"},
    {"thought": "done", "action_type": "Finish", "action_arg": "answer", "observation": ""},
]
OPENAI_STEPS = [
    {"role": "assistant", "content": "Let me search", "tool_calls": [
        {"function": {"name": "search", "arguments": '{"query": "France capital"}'}}
    ]},
    {"role": "tool", "content": "Paris is the capital of France"},
]


class TestImport:
    def test_import_normalize_steps(self):
        from llm_guard.features.step_normalizer import normalize_steps
        assert normalize_steps is not None

    def test_import_validate_coverage(self):
        from llm_guard.features.step_normalizer import validate_step_coverage
        assert validate_step_coverage is not None


class TestNormalizeReact:
    def test_passthrough(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(REACT_STEPS, agent_format="react")
        assert len(result) == 2
        assert result[0]["thought"] == "thinking"
        assert result[0]["action_type"] == "Search"

    def test_empty_returns_empty(self):
        from llm_guard.features.step_normalizer import normalize_steps
        assert normalize_steps([], agent_format="react") == []

    def test_canonical_keys_present(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(REACT_STEPS)
        for step in result:
            for key in ("thought", "action_type", "action_arg", "observation"):
                assert key in step


class TestNormalizeOpenAI:
    def test_openai_format(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(OPENAI_STEPS, agent_format="openai")
        assert len(result) >= 1
        assert result[0]["action_type"] == "search"

    def test_observation_captured(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(OPENAI_STEPS, agent_format="openai")
        assert "Paris" in result[0]["observation"]


class TestNormalizeLangChain:
    def test_langchain_dict_format(self):
        from llm_guard.features.step_normalizer import normalize_steps
        steps = [{"tool": "search", "tool_input": "France capital", "log": "thinking", "observation": "Paris"}]
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(steps, agent_format="langchain")
        assert result[0]["action_type"] == "search"
        assert result[0]["observation"] == "Paris"


class TestNormalizeBrowser:
    def test_browser_click(self):
        from llm_guard.features.step_normalizer import normalize_steps
        steps = [
            {"type": "navigate", "url": "http://example.com", "result": "page loaded"},
            {"type": "click", "selector": "#btn", "result": "clicked successfully"},
        ]
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(steps, agent_format="browser")
        # First step should be Search, last becomes Finish
        assert result[0]["action_type"] == "Search"

    def test_browser_finish_added_if_missing(self):
        from llm_guard.features.step_normalizer import normalize_steps
        steps = [{"type": "navigate", "url": "http://example.com", "result": "loaded"}]
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(steps, agent_format="browser")
        # Last step should be Finish
        assert result[-1]["action_type"] == "Finish"


class TestAutoDetect:
    def test_auto_detects_openai(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(OPENAI_STEPS, agent_format="auto")
        assert len(result) >= 1

    def test_auto_detects_react(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            result = normalize_steps(REACT_STEPS, agent_format="auto")
        assert len(result) == 2

    def test_unknown_format_raises(self):
        from llm_guard.features.step_normalizer import normalize_steps
        with pytest.raises(ValueError):
            normalize_steps(REACT_STEPS, agent_format="unknown_format")


class TestValidateCoverage:
    def test_basic_coverage(self):
        from llm_guard.features.step_normalizer import normalize_steps, validate_step_coverage
        with warnings.catch_warnings(record=True):
            warnings.simplefilter("always")
            steps = normalize_steps(REACT_STEPS)
        report = validate_step_coverage(steps)
        assert "n_steps" in report
        assert report["n_steps"] == 2

    def test_empty_steps_report(self):
        from llm_guard.features.step_normalizer import validate_step_coverage
        report = validate_step_coverage([])
        assert report["n_steps"] == 0
