"""Tests for protocol definitions and compliance."""

from typing import Any, Dict, Optional, Sequence
from unittest.mock import MagicMock


class TestStreamManagerProtocol:
    """Test StreamManagerProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockStreamManager:
            async def publish_status(self, status: str) -> None:
                pass

            async def publish_error(self, message: str, code: int = 500) -> None:
                pass

            async def publish_message(self, content: Any, **kwargs: Any) -> None:
                pass

        manager = MockStreamManager()
        # Protocol compliance is checked at runtime via duck typing
        assert hasattr(manager, "publish_status")
        assert hasattr(manager, "publish_error")
        assert hasattr(manager, "publish_message")


class TestMetricsCollectorProtocol:
    """Test MetricsCollectorProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockMetricsCollector:
            def record_stage_transition(
                self,
                stage: str,
                status: str = "success",
                message_id: Optional[str] = None,
            ) -> None:
                pass

        collector = MockMetricsCollector()
        assert hasattr(collector, "record_stage_transition")


class TestWorkflowInstanceProtocol:
    """Test WorkflowInstanceProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockWorkflowInstance:
            @property
            def id(self) -> str:
                return "instance-123"

            @property
            def workflow_id(self) -> str:
                return "workflow-456"

            @property
            def state(self) -> str:
                return "running"

            def is_completed(self) -> bool:
                return self.state == "completed"

            def is_terminal(self) -> bool:
                return self.state in ["completed", "failed", "cancelled"]

        instance = MockWorkflowInstance()
        assert instance.id == "instance-123"
        assert instance.workflow_id == "workflow-456"
        assert instance.is_completed() is False
        assert instance.is_terminal() is False

    def test_completed_instance(self):
        """Test completed instance behavior."""

        class CompletedInstance:
            @property
            def id(self) -> str:
                return "instance-123"

            @property
            def workflow_id(self) -> str:
                return "workflow-456"

            @property
            def state(self) -> str:
                return "completed"

            def is_completed(self) -> bool:
                return True

            def is_terminal(self) -> bool:
                return True

        instance = CompletedInstance()
        assert instance.is_completed() is True
        assert instance.is_terminal() is True


class TestNodeInstanceProtocol:
    """Test NodeInstanceProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockNodeInstance:
            @property
            def id(self) -> str:
                return "node-123"

            @property
            def node_id(self) -> str:
                return "dialogue-1"

            @property
            def state(self) -> str:
                return "pending"

            @property
            def node_type(self) -> str:
                return "dialogue"

            @property
            def configuration(self) -> Optional[Dict[str, Any]]:
                return {"capability": "discovery"}

            @property
            def metadata(self) -> Optional[Dict[str, Any]]:
                return {}

            def is_terminal(self) -> bool:
                return self.state in [
                    "completed",
                    "failed",
                    "skipped",
                    "timed_out",
                    "cancelled",
                ]

            def is_running(self) -> bool:
                return self.state == "running"

        node = MockNodeInstance()
        assert node.id == "node-123"
        assert node.node_type == "dialogue"
        assert node.is_terminal() is False
        assert node.is_running() is False

    def test_running_node(self):
        """Test running node behavior."""

        class RunningNode:
            @property
            def id(self) -> str:
                return "node-123"

            @property
            def node_id(self) -> str:
                return "compute-1"

            @property
            def state(self) -> str:
                return "running"

            @property
            def node_type(self) -> str:
                return "compute"

            @property
            def configuration(self) -> Optional[Dict[str, Any]]:
                return {}

            @property
            def metadata(self) -> Optional[Dict[str, Any]]:
                return {}

            def is_terminal(self) -> bool:
                return False

            def is_running(self) -> bool:
                return True

        node = RunningNode()
        assert node.is_running() is True
        assert node.is_terminal() is False


class TestRetryPolicyProtocol:
    """Test RetryPolicyProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockRetryPolicy:
            @property
            def max_retries(self) -> int:
                return 3

            @property
            def backoff(self) -> str:
                return "exponential"

            @property
            def base_seconds(self) -> int:
                return 5

            @property
            def jitter(self) -> bool:
                return True

            @property
            def retry_on(self) -> Sequence[str]:
                return ["timeout", "transient_error"]

        policy = MockRetryPolicy()
        assert policy.max_retries == 3
        assert policy.backoff == "exponential"
        assert policy.base_seconds == 5
        assert policy.jitter is True
        assert "timeout" in policy.retry_on


class TestTaskBackendProtocol:
    """Test TaskBackendProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockTaskBackend:
            async def enqueue(
                self,
                task_name: str,
                payload: Dict[str, Any],
            ) -> str:
                return f"task-{task_name}-123"

        backend = MockTaskBackend()
        assert hasattr(backend, "enqueue")


class TestWorkflowServiceProtocol:
    """Test WorkflowServiceProtocol compliance."""

    def test_mock_implements_protocol(self):
        """Test that a mock can satisfy the protocol."""

        class MockWorkflowService:
            def __init__(self):
                self.instance_service = MagicMock()
                self.node_instance_service = MagicMock()

            async def get(self, workflow_id: str) -> Any:
                return {"id": workflow_id}

            async def capture_workflow_snapshot(
                self,
                instance_id: str,
                trigger: str,
                description: Optional[str] = None,
            ) -> Any:
                return None

            async def update_instance_state_with_snapshot(
                self,
                instance_id: str,
                state: Any,
                capture_snapshot: bool = True,
            ) -> Any:
                return None

        service = MockWorkflowService()
        assert hasattr(service, "instance_service")
        assert hasattr(service, "node_instance_service")
        assert hasattr(service, "get")
        assert hasattr(service, "capture_workflow_snapshot")
        assert hasattr(service, "update_instance_state_with_snapshot")
