import base64
from datetime import datetime
from typing import (
    Dict,
    Optional,
    List,
)
from uuid import UUID

from messagebus import Event
from ._PublicationHistoryDto import PublicationHistoryDto


class EventPublishDetailDto(object):

    def __init__(
        self,                           # type: EventPublishDetailDto
        id,                             # type: UUID
        external_code,                  # type: str
        event,                          # type: Event
        acked_at,                       # type: Optional[datetime]
        next_retry_at,                  # type: Optional[datetime]
        abandoned_at,                   # type: Optional[datetime]
        publication_history=None,       # type: Optional[List[PublicationHistoryDto]]
        fifo=False,                     # type: bool
        target=None,                    # type: Optional[str]
    ):

        self.id = id
        self.external_code = external_code
        self.event = event
        self.acked_at = acked_at
        self.next_retry_at = next_retry_at
        self.abandoned_at = abandoned_at
        self.publication_history = publication_history or []  # type: List[PublicationHistoryDto]
        self.fifo = fifo
        self.target = target

    def to_dict(
        self,       # type: EventPublishDetailDto
    ):
        # type: (...) -> Dict[str, str]

        history_list = []
        for history in self.publication_history:
            history_list.append(history.to_dict())

        return {
            "id": str(self.id),
            "externalCode": self.external_code,
            "event": self._build_event_dict(),
            "ackedAt": self.acked_at.isoformat() if self.acked_at is not None else None,
            "nextRetryAt": self.next_retry_at.isoformat() if self.next_retry_at is not None else None,
            "abandonedAt": self.abandoned_at.isoformat() if self.abandoned_at is not None else None,
            "publicationHistory": history_list,
            "fifo": self.fifo,
            "target": self.target,
        }

    def _build_event_dict(
        self,       # type: EventPublishDetailDto
    ):
        # type: (...) -> Dict[str, str]

        event_dict = {
            "subject": self.event.subject,
            "headers": str(self.event.headers),
        }

        if self.event.event_type is not None:
            event_dict["eventType"] = self.event.event_type

        if self.event.data is not None:
            event_dict["data"] = base64.b64encode(self.event.data).decode("utf-8")

        return event_dict
