import unittest
from unittest.mock import patch, mock_open, MagicMock

from src.vaitty_eventbus import ConsoleEventChannel, Event, FileEventChannel, HttpEventChannel, EventBusError


class TestChannels(unittest.TestCase):
    def test_console_event_channel(self):
        channel = ConsoleEventChannel()
        with patch('builtins.print') as mocked_print:
            event = Event("test.topic", {"key": "value"})
            channel.send(event)
            mocked_print.assert_called_once_with(
                "[ConsoleChannel] Event sent: Event(topic='test.topic', payload={'key': 'value'})")

    def test_file_event_channel(self):
        channel = FileEventChannel("test.log")
        event = Event("test.topic", {"key": "value"})
        with patch("builtins.open", mock_open()) as mocked_file:
            channel.send(event)
            mocked_file.assert_called_once_with("test.log", "a")
            mocked_file().write.assert_called_once_with("Event(topic='test.topic', payload={'key': 'value'})\n")

    def test_http_event_channel(self):
        channel = HttpEventChannel("http://example.com/events")
        event = Event("test.topic", {"key": "value"})

        with patch('requests.post') as mocked_post:
            # Simulate a successful response
            mocked_response = MagicMock()
            mocked_response.raise_for_status.return_value = None
            mocked_post.return_value = mocked_response

            channel.send(event)

            mocked_post.assert_called_once_with(
                "http://example.com/events",
                json={"topic": "test.topic", "payload": {"key": "value"}},
                headers={}
            )

            mocked_response.raise_for_status.assert_called_once()

    def test_http_event_channel_failure(self):
        channel = HttpEventChannel("http://example.com/events")
        event = Event("test.topic", {"key": "value"})

        with patch('requests.post') as mocked_post:
            # Simulate a failed response
            mocked_post.side_effect = Exception("Failed to send request")

            try:
                channel.send(event)
            except EventBusError as e:
                self.assertEqual(str(e), "Failed to send event: Failed to send request")
