import datetime
from dataclasses import dataclass
from typing import Any

from pydantic import BaseModel

from kurier.core.basekurier import BaseKurier
from kurier.core.kurier_message import KurierMessage
from kurier.hermes import Hermes

Hermes.is_enabled = False


class _StubLine(BaseKurier):
    """Minimal concrete BaseKurier for testing serialization."""

    bus_type = None

    def __init__(self, name: str = "stub_line", **kwargs):
        super().__init__(name, **kwargs)
        self._register()

    def _publish_to_bus(self, json_message: str, meta_data: dict[str, Any]):
        pass

    def _run_consumer_loop(self):
        pass

    def close(self):
        pass

    @classmethod
    def start_consumer(cls, name: str) -> bool:
        return True


@dataclass
class TestDataClass:
    name: str
    age: int
    created_at: datetime.datetime


class TestPydanticModel(BaseModel):
    name: str
    age: int
    created_at: datetime.datetime


class TestKurierSerialization:
    def setup_method(self):
        BaseKurier._registry.clear()
        _StubLine._registry.clear()

    def test_serialize_string_message(self):
        """Test serializing a simple string message."""
        line = _StubLine("test_str_line")
        message = "test_string"
        metadata = {"source": "test"}

        envelope = line._serialize_to_envelope(message, metadata)

        assert isinstance(envelope, KurierMessage)
        assert envelope.object_type_name == "str"
        assert envelope.metadata == metadata

    def test_serialize_integer_message(self):
        """Test serializing an integer message."""
        line = _StubLine("test_int_line")
        message = 42
        metadata = {}

        envelope = line._serialize_to_envelope(message, metadata)

        assert envelope.object_type_name == "int"
        assert envelope.metadata == metadata

    def test_serialize_dataclass_message(self):
        """Test serializing a dataclass message."""
        line = _StubLine("test_dc_line")
        now = datetime.datetime.now()
        message = TestDataClass(name="John", age=30, created_at=now)
        metadata = {"type": "dataclass"}

        envelope = line._serialize_to_envelope(message, metadata)

        assert envelope.object_type_name == "TestDataClass"
        assert envelope.metadata == metadata
        # Verify datetime is serialized as ISO format
        assert now.isoformat() in envelope.message_payload

    def test_serialize_pydantic_message(self):
        """Test serializing a Pydantic model message."""
        line = _StubLine("test_pydantic_line")
        now = datetime.datetime.now()
        message = TestPydanticModel(name="Jane", age=25, created_at=now)
        metadata = {"type": "pydantic"}

        envelope = line._serialize_to_envelope(message, metadata)

        assert envelope.object_type_name == "TestPydanticModel"
        assert envelope.metadata == metadata

    def test_serialize_with_correlation_id(self):
        """Test serializing with correlation ID."""
        line = _StubLine("test_cid_line")
        message = "test"
        metadata = {}
        correlation_id = "test-correlation-123"

        envelope = line._serialize_to_envelope(message, metadata, correlation_id)

        assert envelope.correlation_id == correlation_id

    def test_chunk_messages(self):
        """Test message chunking functionality."""
        messages = list(range(10))
        chunks = list(BaseKurier.chunk_messages(messages, 3))

        assert len(chunks) == 4
        assert chunks[0] == [0, 1, 2]
        assert chunks[1] == [3, 4, 5]
        assert chunks[2] == [6, 7, 8]
        assert chunks[3] == [9]
