from dataclasses import is_dataclass
from typing import Type, TypeVar, cast

T = TypeVar("T", bound=Type)


def poll_event(cls: T) -> T:
    """
    Decorator for dataclasses that represent poll event structures.

    This decorator marks a dataclass as a poll event type, which can be used
    as the yielded type in AsyncIterator[T] or AsyncGenerator[T, None].

    The fields of the dataclass will be extracted and used to populate the
    'event' field in the BookPollDescriptor.

    Example:
        @poll_event
        @dataclass
        class EmailEvent:
            subject: str
            sender: str
            received_at: int
            message: str

        @poll(name="for new emails")
        async def poll_emails(self, folder: str = "INBOX") -> AsyncIterator[EmailEvent]:
            '''Poll for new emails'''
            while self._polling:
                email = await self.get_next_email()
                yield EmailEvent(...)

    Args:
        cls: The dataclass to decorate

    Returns:
        The decorated class with __poll_event__ marker

    Raises:
        TypeError: If the decorator is not applied to a dataclass
    """
    if not is_dataclass(cls):
        raise TypeError(
            f"The @poll_event decorator can only be applied to dataclasses. " f"'{cls.__name__}' is not a dataclass. " f"Make sure to apply @dataclass before @poll_event."
        )

    # Mark this class as a poll event
    cls.__poll_event__ = True

    return cast(T, cls)
