import json

from tests.fixtures.spans import get_span_json
from verse_sdk import OtelGenAISpecCheck


class TestSpecCheckMetadata:
    def test_metadata_structure(self):
        span = get_span_json("valid_chat_complete")
        checker = OtelGenAISpecCheck(span)
        metadata = checker.extract_metadata()
        assert metadata["environment"] == "dev"
        assert metadata["model_provider"] == "anthropic"
        assert metadata["model"] == "claude-3-5-sonnet-20241022"
        assert metadata["project_id"] == "proj_1234567890"
        assert metadata["session_id"] == "sess_1234567890"
        assert metadata["start_time"] is not None
        assert metadata["end_time"] is not None
        assert metadata["span_id"] is not None
        assert metadata["span_parent_id"] is not None
        assert metadata["trace_id"] is not None
        assert metadata["user_id"] == "user_1234567890"


class TestValidSpans:
    def test_valid_chat_complete_has_all_common_fields(self):
        span = get_span_json("valid_chat_complete")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is False
        assert checker.is_attribute_valid("gen_ai.operation.name") is True

    def test_embeddings_complete_has_dimension_count(self):
        span = get_span_json("embeddings_complete")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_deprecations is False
        assert checker.is_attribute_valid("gen_ai.embeddings.dimension.count") is True

    def test_tool_execution_has_tool_fields(self):
        span = get_span_json("tool_execution")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_deprecations is False
        assert checker.is_attribute_valid("gen_ai.tool.name") is True
        assert checker.is_attribute_valid("gen_ai.tool.type") is True
        assert checker.is_attribute_valid("gen_ai.tool.description") is True


class TestMissingRequiredFields:
    def test_missing_operation_and_provider(self):
        span = get_span_json("missing_required_fields")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.operation.name") is True
        assert checker.is_attribute_invalid("gen_ai.provider.name") is True


class TestMissingRecommendedFields:
    def test_missing_recommended_fields_shows_warnings(self):
        span = get_span_json("missing_recommended_fields")
        checker = OtelGenAISpecCheck(span)

        assert checker.could_improve is True
        assert checker.is_attribute_missing("gen_ai.response.model") is True
        assert checker.is_attribute_missing("gen_ai.usage.input_tokens") is True


class TestInvalidEnumValues:
    def test_invalid_operation_name(self):
        span = get_span_json("invalid_enum_values")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.operation.name") is True

    def test_invalid_provider_name(self):
        span = get_span_json("invalid_enum_values")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.provider.name") is True

    def test_invalid_finish_reason(self):
        span = get_span_json("invalid_enum_values")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.response.finish_reasons") is True

    def test_invalid_output_type(self):
        span = get_span_json("invalid_enum_values")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.output.type") is True


class TestDeprecatedAttributes:
    def test_deprecated(self):
        span = get_span_json("deprecated_attributes")
        checker = OtelGenAISpecCheck(span)
        assert checker.is_attribute_deprecated("gen_ai.system") is True
        assert checker.is_attribute_deprecated("gen_ai.prompt") is True
        assert checker.is_attribute_deprecated("gen_ai.completion") is True


class TestInvalidInput:
    def test_invalid_json_string(self):
        with open("tests/fixtures/spans/invalid_json.txt") as f:
            invalid_json = f.read()

        checker = OtelGenAISpecCheck(invalid_json)
        assert checker.has_errors is True

    def test_dict_input(self):
        span_dict = json.loads(get_span_json("valid_chat_complete"))
        checker = OtelGenAISpecCheck(span_dict)
        assert checker.has_errors is False


class TestInvalidTypes:
    def test_invalid_string_type(self):
        span = get_span_json("invalid_types")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.operation.name") is True

    def test_invalid_int_type(self):
        span = get_span_json("invalid_types")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.request.max_tokens") is True
        assert checker.is_attribute_invalid("gen_ai.usage.input_tokens") is True
        assert checker.is_attribute_invalid("server.port") is True

    def test_invalid_double_type(self):
        span = get_span_json("invalid_types")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.request.temperature") is True

    def test_invalid_string_array_type(self):
        span = get_span_json("invalid_types")
        checker = OtelGenAISpecCheck(span)

        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.response.finish_reasons") is True

    def test_valid_attributes_are_still_valid(self):
        span = get_span_json("invalid_types")
        checker = OtelGenAISpecCheck(span)

        # These attributes have correct types and should be valid
        assert checker.is_attribute_valid("gen_ai.provider.name") is True
        assert checker.is_attribute_valid("gen_ai.request.top_p") is True
        assert checker.is_attribute_valid("gen_ai.usage.output_tokens") is True


class TestValidationDetails:
    def test_validation_details_structure(self):
        span = get_span_json("missing_required_fields")
        checker = OtelGenAISpecCheck(span)
        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.operation.name") is True
        assert checker.is_attribute_invalid("gen_ai.provider.name") is True

    def test_error_count_matches_errors(self):
        span = get_span_json("invalid_enum_values")
        checker = OtelGenAISpecCheck(span)
        assert checker.has_errors is True
        assert checker.is_attribute_invalid("gen_ai.operation.name") is True
        assert checker.is_attribute_invalid("gen_ai.provider.name") is True
