import unittest
from unittest.mock import MagicMock

from src.vaitty_eventbus import Event, EventChannel, EventHandler


class TestCore(unittest.TestCase):
    def test_event_initialization(self):
        event = Event("test.topic", {"key": "value"})
        self.assertEqual(event.topic, "test.topic")
        self.assertEqual(event.payload, {"key": "value"})

    def test_event_repr(self):
        event = Event("test.topic", {"key": "value"})
        self.assertEqual(repr(event), "Event(topic='test.topic', payload={'key': 'value'})")

    def test_event_invalid_topic_type(self):
        with self.assertRaises(TypeError) as context:
            Event(123, {"key": "value"})
        self.assertEqual(str(context.exception), "Event topic must be a string.")

    def test_event_invalid_payload_type(self):
        with self.assertRaises(TypeError) as context:
            Event("test.topic", ["invalid_payload"])
        self.assertEqual(str(context.exception), "Event payload must be a dictionary.")

    def test_event_handler_emit(self):
        channel = MagicMock(spec=EventChannel)
        handler = EventHandler(channel)
        event_topic = "test.topic"
        event_payload = {"key": "value"}

        handler.emit(event_topic, event_payload)
        channel.send.assert_called_once()
        sent_event = channel.send.call_args[0][0]
        self.assertEqual(sent_event.topic, event_topic)
        self.assertEqual(sent_event.payload, event_payload)

    def test_event_handler_on_and_trigger(self):
        channel = MagicMock(spec=EventChannel)
        handler = EventHandler(channel)

        mock_callback = MagicMock()
        handler.on("test.topic", mock_callback)

        event = Event("test.topic", {"key": "value"})
        handler.trigger(event)

        mock_callback.assert_called_once_with({"key": "value"}, handler)

    def test_event_handler_trigger_with_wildcard(self):
        channel = MagicMock(spec=EventChannel)
        handler = EventHandler(channel)

        mock_callback = MagicMock()
        handler.on("test.*", mock_callback)

        event = Event("test.topic", {"key": "value"})
        handler.trigger(event)

        mock_callback.assert_called_once_with({"key": "value"}, handler)

    def test_event_handler_trigger_no_match(self):
        channel = MagicMock(spec=EventChannel)
        handler = EventHandler(channel)

        mock_callback = MagicMock()
        handler.on("other.topic", mock_callback)

        event = Event("test.topic", {"key": "value"})
        handler.trigger(event)

        mock_callback.assert_not_called()
