# License: MIT
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH

"""Exception classes."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any, Generic, TypeVar

if TYPE_CHECKING:
    from . import _base_classes

T = TypeVar("T")


class Error(RuntimeError):
    """Base error.

    All exceptions generated by this library inherit from this exception.
    """

    def __init__(self, message: Any):
        """Create a ChannelError instance.

        Args:
            message: An error message.
        """
        super().__init__(message)


class ChannelError(Error):
    """An error produced in a channel.

    All exceptions generated by channels inherit from this exception.
    """

    def __init__(self, message: Any, channel: Any):
        """Create a ChannelError instance.

        Args:
            message: An error message.
            channel: A reference to the channel that encountered the error.
        """
        super().__init__(message)
        self.channel: Any = channel


class ChannelClosedError(ChannelError):
    """Error raised when trying to operate on a closed channel."""

    def __init__(self, channel: Any):
        """Create a `ChannelClosedError` instance.

        Args:
            channel: A reference to the channel that was closed.
        """
        super().__init__(f"Channel {channel} was closed", channel)


class SenderError(Error, Generic[T]):
    """An error produced in a [Sender][frequenz.channels.Sender].

    All exceptions generated by senders inherit from this exception.
    """

    def __init__(self, message: Any, sender: _base_classes.Sender[T]):
        """Create an instance.

        Args:
            message: An error message.
            sender: The [Sender][frequenz.channels.Sender] where the error
                happened.
        """
        super().__init__(message)
        self.sender: _base_classes.Sender[T] = sender


class ReceiverError(Error, Generic[T]):
    """An error produced in a [Receiver][frequenz.channels.Receiver].

    All exceptions generated by receivers inherit from this exception.
    """

    def __init__(self, message: Any, receiver: _base_classes.Receiver[T]):
        """Create an instance.

        Args:
            message: An error message.
            receiver: The [Receiver][frequenz.channels.Receiver] where the
                error happened.
        """
        super().__init__(message)
        self.receiver: _base_classes.Receiver[T] = receiver


class ReceiverStoppedError(ReceiverError[T]):
    """The [Receiver][frequenz.channels.Receiver] stopped producing messages."""

    def __init__(self, receiver: _base_classes.Receiver[T]):
        """Create an instance.

        Args:
            receiver: The [Receiver][frequenz.channels.Receiver] where the
                error happened.
        """
        super().__init__(f"Receiver {receiver} was stopped", receiver)


class ReceiverInvalidatedError(ReceiverError[T]):
    """The [Receiver][frequenz.channels.Receiver] was invalidated.

    This happens when the Receiver is converted
    [into][frequenz.channels.Receiver.into_peekable]
    a [Peekable][frequenz.channels.Peekable].
    """
