"""Type safety tests for async protocols.

These tests demonstrate that separate async protocols provide better type safety
by ensuring type checkers can enforce await on async methods.
"""

from __future__ import annotations

import inspect

from pinecone.__interface__.client import AsyncPineconeProtocol, PineconeProtocol
from pinecone.__interface__.inference import (
    AsyncInferenceNamespaceProtocol,
    InferenceNamespaceProtocol,
)


class TestProtocolTypeSafety:
    """Test that protocols have correct type annotations."""

    def test_sync_client_has_sync_inference_protocol(self):
        """Test PineconeProtocol.inference returns sync InferenceNamespaceProtocol."""
        # Get the return type annotation
        sig = inspect.signature(PineconeProtocol.inference.fget)  # type: ignore[attr-defined]
        return_annotation = sig.return_annotation

        # Should be InferenceNamespaceProtocol
        assert "InferenceNamespaceProtocol" in str(return_annotation)
        assert "AsyncInferenceNamespaceProtocol" not in str(return_annotation)

    def test_async_client_has_async_inference_protocol(self):
        """Test AsyncPineconeProtocol.inference returns async AsyncInferenceNamespaceProtocol."""
        # Get the return type annotation
        sig = inspect.signature(AsyncPineconeProtocol.inference.fget)  # type: ignore[attr-defined]
        return_annotation = sig.return_annotation

        # Should be AsyncInferenceNamespaceProtocol
        assert "AsyncInferenceNamespaceProtocol" in str(return_annotation)

    def test_sync_protocol_methods_are_not_async(self):
        """Test InferenceNamespaceProtocol methods are regular def, not async def."""
        # embed should be a regular function (not a coroutine function)
        assert not inspect.iscoroutinefunction(InferenceNamespaceProtocol.embed)

        # rerank should be a regular function (not a coroutine function)
        assert not inspect.iscoroutinefunction(InferenceNamespaceProtocol.rerank)

    def test_async_protocol_methods_are_async(self):
        """Test AsyncInferenceNamespaceProtocol methods are async def."""
        # embed should be a coroutine function
        assert inspect.iscoroutinefunction(AsyncInferenceNamespaceProtocol.embed)

        # rerank should be a coroutine function
        assert inspect.iscoroutinefunction(AsyncInferenceNamespaceProtocol.rerank)

    def test_sync_and_async_protocols_are_different(self):
        """Test that sync and async inference protocols are distinct types."""
        # They should be different classes
        assert InferenceNamespaceProtocol is not AsyncInferenceNamespaceProtocol

        # They should have different method signatures
        sync_embed_sig = inspect.signature(InferenceNamespaceProtocol.embed)
        async_embed_sig = inspect.signature(AsyncInferenceNamespaceProtocol.embed)

        # Return annotations should differ (sync returns directly, async is coroutine)
        assert sync_embed_sig.return_annotation == async_embed_sig.return_annotation
        # But the functions themselves differ (one is async def, one is def)
        assert inspect.iscoroutinefunction(
            AsyncInferenceNamespaceProtocol.embed
        ) != inspect.iscoroutinefunction(InferenceNamespaceProtocol.embed)
