"""Protocol compliance tests.

These tests verify that classes properly implement their defined protocols.
"""

from __future__ import annotations

from typing import Protocol

from pinecone.__interface__.backups import BackupNamespaceProtocol
from pinecone.__interface__.client import AsyncPineconeProtocol, PineconeProtocol
from pinecone.__interface__.collections import CollectionNamespaceProtocol
from pinecone.__interface__.index import AsyncIndexProtocol, IndexProtocol
from pinecone.__interface__.indexes import IndexNamespaceProtocol
from pinecone.__interface__.inference import (
    AsyncInferenceNamespaceProtocol,
    InferenceNamespaceProtocol,
)


class TestProtocolDefinitions:
    """Test that protocols are properly defined."""

    def test_pinecone_protocol_is_runtime_checkable(self):
        """Test PineconeProtocol can be used with isinstance."""
        # Protocol should be runtime_checkable
        assert hasattr(PineconeProtocol, "__protocol_attrs__") or hasattr(
            PineconeProtocol, "_is_runtime_protocol"
        )

    def test_async_pinecone_protocol_is_runtime_checkable(self):
        """Test AsyncPineconeProtocol can be used with isinstance."""
        assert hasattr(AsyncPineconeProtocol, "__protocol_attrs__") or hasattr(
            AsyncPineconeProtocol, "_is_runtime_protocol"
        )

    def test_index_protocol_is_runtime_checkable(self):
        """Test IndexProtocol can be used with isinstance."""
        assert hasattr(IndexProtocol, "__protocol_attrs__") or hasattr(
            IndexProtocol, "_is_runtime_protocol"
        )

    def test_async_index_protocol_is_runtime_checkable(self):
        """Test AsyncIndexProtocol can be used with isinstance."""
        assert hasattr(AsyncIndexProtocol, "__protocol_attrs__") or hasattr(
            AsyncIndexProtocol, "_is_runtime_protocol"
        )

    def test_inference_namespace_protocol_is_runtime_checkable(self):
        """Test InferenceNamespaceProtocol can be used with isinstance."""
        assert hasattr(InferenceNamespaceProtocol, "__protocol_attrs__") or hasattr(
            InferenceNamespaceProtocol, "_is_runtime_protocol"
        )

    def test_async_inference_namespace_protocol_is_runtime_checkable(self):
        """Test AsyncInferenceNamespaceProtocol can be used with isinstance."""
        assert hasattr(AsyncInferenceNamespaceProtocol, "__protocol_attrs__") or hasattr(
            AsyncInferenceNamespaceProtocol, "_is_runtime_protocol"
        )

    def test_backup_namespace_protocol_is_runtime_checkable(self):
        """Test BackupNamespaceProtocol can be used with isinstance."""
        assert hasattr(BackupNamespaceProtocol, "__protocol_attrs__") or hasattr(
            BackupNamespaceProtocol, "_is_runtime_protocol"
        )


class TestPineconeProtocolRequirements:
    """Test PineconeProtocol defines expected members."""

    def test_protocol_has_indexes_property(self):
        """Test PineconeProtocol requires indexes property."""
        assert "indexes" in dir(PineconeProtocol)

    def test_protocol_has_collections_property(self):
        """Test PineconeProtocol requires collections property."""
        assert "collections" in dir(PineconeProtocol)

    def test_protocol_has_backups_property(self):
        """Test PineconeProtocol requires backups property."""
        assert "backups" in dir(PineconeProtocol)

    def test_protocol_has_inference_property(self):
        """Test PineconeProtocol requires inference property."""
        assert "inference" in dir(PineconeProtocol)

    def test_protocol_has_index_method(self):
        """Test PineconeProtocol requires Index method."""
        assert "Index" in dir(PineconeProtocol)
        assert callable(getattr(PineconeProtocol, "Index", None))


class TestIndexProtocolRequirements:
    """Test IndexProtocol defines expected members."""

    def test_protocol_has_upsert(self):
        """Test IndexProtocol requires upsert method."""
        assert "upsert" in dir(IndexProtocol)

    def test_protocol_has_query(self):
        """Test IndexProtocol requires query method."""
        assert "query" in dir(IndexProtocol)

    def test_protocol_has_fetch(self):
        """Test IndexProtocol requires fetch method."""
        assert "fetch" in dir(IndexProtocol)

    def test_protocol_has_delete(self):
        """Test IndexProtocol requires delete method."""
        assert "delete" in dir(IndexProtocol)

    def test_protocol_has_describe_index_stats(self):
        """Test IndexProtocol requires describe_index_stats method."""
        assert "describe_index_stats" in dir(IndexProtocol)


class TestNamespaceProtocolRequirements:
    """Test namespace protocols define expected members."""

    def test_index_namespace_has_list(self):
        """Test IndexNamespaceProtocol requires list method."""
        assert "list" in dir(IndexNamespaceProtocol)

    def test_index_namespace_has_create(self):
        """Test IndexNamespaceProtocol requires create method."""
        assert "create" in dir(IndexNamespaceProtocol)

    def test_index_namespace_has_delete(self):
        """Test IndexNamespaceProtocol requires delete method."""
        assert "delete" in dir(IndexNamespaceProtocol)

    def test_index_namespace_has_describe(self):
        """Test IndexNamespaceProtocol requires describe method."""
        assert "describe" in dir(IndexNamespaceProtocol)


class TestIndexNamespaceImplementation:
    """Test IndexNamespace implementation satisfies protocol."""

    def test_index_namespace_satisfies_protocol(self):
        """Test IndexNamespace satisfies IndexNamespaceProtocol."""
        from pinecone._internal.http import HTTPClient
        from pinecone.client.indexes_old import IndexNamespaceOld as IndexNamespace

        client = HTTPClient(api_key="test-key")
        instance = IndexNamespace(client)

        # Verify protocol satisfaction
        assert isinstance(instance, IndexNamespaceProtocol)

        # Verify all required methods exist and are callable
        assert hasattr(instance, "list")
        assert callable(instance.list)
        assert hasattr(instance, "create")
        assert callable(instance.create)
        assert hasattr(instance, "delete")
        assert callable(instance.delete)
        assert hasattr(instance, "describe")
        assert callable(instance.describe)

    def test_inference_namespace_has_embed(self):
        """Test InferenceNamespaceProtocol requires embed method."""
        assert "embed" in dir(InferenceNamespaceProtocol)

    def test_inference_namespace_has_rerank(self):
        """Test InferenceNamespaceProtocol requires rerank method."""
        assert "rerank" in dir(InferenceNamespaceProtocol)

    def test_async_inference_namespace_has_embed(self):
        """Test AsyncInferenceNamespaceProtocol requires embed method."""
        assert "embed" in dir(AsyncInferenceNamespaceProtocol)

    def test_async_inference_namespace_has_rerank(self):
        """Test AsyncInferenceNamespaceProtocol requires rerank method."""
        assert "rerank" in dir(AsyncInferenceNamespaceProtocol)


class TestProtocolIsAbstract:
    """Test protocols are abstract and not instantiatable directly."""

    def test_pinecone_protocol_cannot_instantiate(self):
        """Test PineconeProtocol cannot be instantiated."""
        # Protocols cannot be instantiated directly
        assert issubclass(PineconeProtocol, Protocol) or hasattr(PineconeProtocol, "_is_protocol")

    def test_index_protocol_cannot_instantiate(self):
        """Test IndexProtocol cannot be instantiated."""
        assert issubclass(IndexProtocol, Protocol) or hasattr(IndexProtocol, "_is_protocol")


class TestBackupsImplementation:
    """Test Backups implementation satisfies protocol."""

    def test_backups_satisfies_protocol(self):
        """Test Backups satisfies BackupNamespaceProtocol."""
        from pinecone._internal.http import HTTPClient
        from pinecone.client.backups import Backups

        client = HTTPClient(api_key="test-key")
        instance = Backups(client)

        # Verify protocol satisfaction
        assert isinstance(instance, BackupNamespaceProtocol)

        # Verify all required methods exist and are callable
        assert hasattr(instance, "list")
        assert callable(instance.list)
        assert hasattr(instance, "create")
        assert callable(instance.create)
        assert hasattr(instance, "delete")
        assert callable(instance.delete)
        assert hasattr(instance, "describe")
        assert callable(instance.describe)

    def test_async_backups_has_required_methods(self):
        """Test AsyncBackups has all required methods.

        Note: AsyncBackups does not implement BackupNamespaceProtocol
        because async methods have incompatible return types (Coroutine vs direct types).
        We verify methods exist and are callable instead.
        """
        from pinecone._internal.http import AsyncHTTPClient
        from pinecone.async_client.backups import AsyncBackups

        client = AsyncHTTPClient(api_key="test-key")
        instance = AsyncBackups(client)

        # Verify all required methods exist and are callable
        assert hasattr(instance, "list")
        assert callable(instance.list)
        assert hasattr(instance, "create")
        assert callable(instance.create)
        assert hasattr(instance, "delete")
        assert callable(instance.delete)
        assert hasattr(instance, "describe")
        assert callable(instance.describe)


class TestCollectionsImplementation:
    """Test Collections implementation satisfies protocol."""

    def test_collections_satisfies_protocol(self):
        """Test Collections satisfies CollectionNamespaceProtocol."""
        from pinecone._internal.http import HTTPClient
        from pinecone.client.collections import Collections

        client = HTTPClient(api_key="test-key")
        instance = Collections(client)

        # Verify protocol satisfaction
        assert isinstance(instance, CollectionNamespaceProtocol)

        # Verify all required methods exist and are callable
        assert hasattr(instance, "list")
        assert callable(instance.list)
        assert hasattr(instance, "create")
        assert callable(instance.create)
        assert hasattr(instance, "delete")
        assert callable(instance.delete)
        assert hasattr(instance, "describe")
        assert callable(instance.describe)

    def test_async_collections_has_required_methods(self):
        """Test AsyncCollections has all required methods.

        Note: AsyncCollections does not implement CollectionNamespaceProtocol
        because async methods have incompatible return types (Coroutine vs direct types).
        We verify methods exist and are callable instead.
        """
        from pinecone._internal.http import AsyncHTTPClient
        from pinecone.async_client.collections import AsyncCollections

        client = AsyncHTTPClient(api_key="test-key")
        instance = AsyncCollections(client)

        # Verify all required methods exist and are callable
        assert hasattr(instance, "list")
        assert callable(instance.list)
        assert hasattr(instance, "create")
        assert callable(instance.create)
        assert hasattr(instance, "delete")
        assert callable(instance.delete)
        assert hasattr(instance, "describe")
        assert callable(instance.describe)
