import json

from verse_sdk import OtelGenAISpecCheck
from verse_sdk.spec.utils import is_valid_type


class TestExtractMessages:
    def test_extract_messages_from_json_arrays(self):
        """Test extracting messages from gen_ai.input.messages and gen_ai.output.messages."""
        span = {
            "context": {"trace_id": "123", "span_id": "456"},
            "attributes": {
                "gen_ai.input.messages": json.dumps(
                    [
                        {
                            "role": "user",
                            "parts": [
                                {"type": "text", "content": "Hello, how are you?"}
                            ],
                        },
                        {
                            "role": "assistant",
                            "parts": [
                                {"type": "text", "content": "I'll help you."},
                                {
                                    "type": "tool_call",
                                    "name": "search",
                                    "id": "call_123",
                                    "arguments": "{}",
                                },
                            ],
                        },
                    ]
                ),
                "gen_ai.output.messages": json.dumps(
                    [
                        {
                            "role": "assistant",
                            "parts": [
                                {"type": "text", "content": "I'm doing great, thanks!"}
                            ],
                            "finish_reason": "stop",
                        }
                    ]
                ),
            },
        }

        checker = OtelGenAISpecCheck(span)
        messages = checker.extract_messages()

        assert len(messages) == 3
        assert messages[0]["role"] == "user"
        assert messages[0]["parts"][0]["content"] == "Hello, how are you?"
        assert messages[1]["role"] == "assistant"
        assert messages[1]["parts"][1]["type"] == "tool_call"
        assert messages[2]["role"] == "assistant"
        assert messages[2]["finish_reason"] == "stop"

    def test_extract_messages_empty_when_no_messages(self):
        """Test that extract_messages returns empty list when no messages are present."""
        span = {
            "context": {"trace_id": "123", "span_id": "456"},
            "attributes": {},
        }

        checker = OtelGenAISpecCheck(span)
        messages = checker.extract_messages()

        assert messages == []

    def test_extract_messages_handles_malformed_json(self):
        """Test that extract_messages handles malformed JSON gracefully."""
        span = {
            "context": {"trace_id": "123", "span_id": "456"},
            "attributes": {
                "gen_ai.input.messages": "not valid json",
            },
        }

        checker = OtelGenAISpecCheck(span)
        messages = checker.extract_messages()

        assert messages == []


class TestIsValidType:
    def test_string_type_valid(self):
        assert is_valid_type("hello", "string") is True
        assert is_valid_type("", "string") is True

    def test_string_type_invalid(self):
        assert is_valid_type(123, "string") is False
        assert is_valid_type(12.5, "string") is False
        assert is_valid_type(True, "string") is False
        assert is_valid_type(["hello"], "string") is False

    def test_int_type_valid(self):
        assert is_valid_type(123, "int") is True
        assert is_valid_type(0, "int") is True
        assert is_valid_type(-456, "int") is True

    def test_int_type_invalid(self):
        assert is_valid_type("123", "int") is False
        assert is_valid_type(12.5, "int") is False
        assert is_valid_type(True, "int") is False
        assert is_valid_type(False, "int") is False

    def test_double_type_valid(self):
        assert is_valid_type(12.5, "double") is True
        assert is_valid_type(123, "double") is True
        assert is_valid_type(0.0, "double") is True
        assert is_valid_type(-45.67, "double") is True

    def test_double_type_invalid(self):
        assert is_valid_type("12.5", "double") is False
        assert is_valid_type(True, "double") is False
        assert is_valid_type(False, "double") is False

    def test_boolean_type_valid(self):
        assert is_valid_type(True, "boolean") is True
        assert is_valid_type(False, "boolean") is True

    def test_boolean_type_invalid(self):
        assert is_valid_type(1, "boolean") is False
        assert is_valid_type(0, "boolean") is False
        assert is_valid_type("true", "boolean") is False

    def test_string_array_type_valid(self):
        assert is_valid_type(["hello", "world"], "string[]") is True
        assert is_valid_type([], "string[]") is True
        assert is_valid_type(["single"], "string[]") is True

    def test_string_array_type_invalid(self):
        assert is_valid_type("hello", "string[]") is False
        assert is_valid_type([1, 2, 3], "string[]") is False
        assert is_valid_type(["hello", 123], "string[]") is False
        assert is_valid_type([True, False], "string[]") is False

    def test_any_type_accepts_all(self):
        assert is_valid_type("hello", "any") is True
        assert is_valid_type(123, "any") is True
        assert is_valid_type(12.5, "any") is True
        assert is_valid_type(True, "any") is True
        assert is_valid_type(["hello"], "any") is True
        assert is_valid_type({"key": "value"}, "any") is True
        assert is_valid_type(None, "any") is True

    def test_unknown_type_returns_false(self):
        assert is_valid_type("hello", "unknown_type") is False
        assert is_valid_type(123, "custom") is False
