from typing import Dict

import requests

from .core import EventChannel, Event, EventBusError


class ConsoleEventChannel(EventChannel):
    """
    Provides a channel for sending events to the console.

    This class is a specific implementation of the EventChannel base class
    and is designed to handle events by outputting them to the standard
    console. It is useful for debugging or simple event logging where
    persistent storage or advanced handling of events is not required.
    """

    @classmethod
    def from_config(cls, config: Dict[str, str]):
        return cls()

    def send(self, event: Event) -> None:
        print(f"[ConsoleChannel] Event sent: {event}")


class FileEventChannel(EventChannel):
    """
    Handles event logging to a specified file.

    This class inherits from EventChannel and is used to log events to a
    file. It appends the event data to the specified file in text format.
    Useful for persistent logging or debugging purposes.

    :ivar filename: Path to the file where events are logged.
    :type filename: str
    """

    def __init__(self, filename: str = "events.log"):
        self.filename = filename

    @classmethod
    def from_config(cls, config: Dict[str, str]):
        filename = config.get("EVENTBUS_FILE", "events.log")
        return cls(filename)

    def send(self, event: Event) -> None:
        with open(self.filename, 'a') as f:
            f.write(f"{event}\n")


class HttpEventChannel(EventChannel):
    """
    Implements an HTTP-based event channel.

    Sends events as HTTP POST requests to a configured endpoint. This class
    is useful when working with systems that accept event ingestion via HTTP
    APIs.

    :ivar endpoint: The HTTP endpoint URI to send events to.
    :type endpoint: str
    :ivar headers: Optional HTTP headers to send with the requests.
    :type headers: dict
    """

    def __init__(self, endpoint: str, headers: dict = None):
        """
        Initializes the HTTP event channel.

        :param endpoint: The target URL endpoint for event ingestion.
        :type endpoint: str
        :param headers: Additional HTTP headers to include in the request.
        :type headers: dict, optional
        """
        self.endpoint = endpoint
        self.headers = headers or {}

    @classmethod
    def from_config(cls, config: Dict[str, str]):
        endpoint = config.get("EVENTBUS_HTTP_ENDPOINT", "http://example.com/events")
        return cls(endpoint=endpoint, headers={})

    def send(self, event: Event) -> None:
        """
        Sends an event as an HTTP POST request.

        :param event: The event to send.
        :type event: Event
        :raises EventBusError: If the request fails.
        """
        try:
            response = requests.post(
                self.endpoint,
                json=event.to_dict(),
                headers=self.headers
            )
            response.raise_for_status()
        except Exception as error:
            raise EventBusError(f"Failed to send event: {error}")
