import json
from typing import Optional
from uuid import UUID

from event_manager_api.shared import EventPublishDetailDto
from event_manager_api.shared.error import (
    NOT_A_UUID,
    INVALID_UTF8_DATA,
)
from event_manager_api.shared.token import TK_EVENT_MANAGER_DEFINITION_NOT_FOUND
from messagebus import (
    AckMessage,
    Message,
    DataType,
    BadRequestMessage,
    InternalErrorMessage,
)
from messageprocessorutil import UuidMessageProcessor
from model.mapper import EventPublishDetailMapper
from model.repository import EventRepository
from .._ParseException import ParseException


class GetDetailsProcessor(UuidMessageProcessor):
    def __init__(self, event_repository: EventRepository):
        super().__init__()
        self.event_repository = event_repository

    def parse_data(self, data):
        try:
            return UUID(data.decode("utf-8"))
        except UnicodeDecodeError:
            raise ParseException(
                error_code=INVALID_UTF8_DATA[0],
                error_message=INVALID_UTF8_DATA[1],
            )
        except ValueError:
            raise ParseException(
                error_code=NOT_A_UUID[0],
                error_message=NOT_A_UUID[1],
            )

    def call_business(self, definition_id: UUID):
        definition = self.event_repository.get_by_id(id=definition_id)
        if definition is None:
            return None
        return EventPublishDetailMapper.map(publish_detail=definition)

    def format_response(
        self,
        message_bus,
        message,
        event,
        input_obj,
        dto: Optional[EventPublishDetailDto],
    ):
        if dto is None:
            message_bus.reply_message(
                message=message,
                reply_message=Message(
                    token=TK_EVENT_MANAGER_DEFINITION_NOT_FOUND,
                    data_type=DataType.empty,
                )
            )
        else:
            message_bus.reply_message(
                message=message,
                reply_message=AckMessage(data=json.dumps(dto.to_dict()).encode("utf-8"))
            )

    def format_exception(
        self,
        message_bus,
        message,
        event,
        input_obj,
        exception
    ):
        message_bus.reply_message(
            message=message,
            reply_message=InternalErrorMessage(ex=exception)
        )

    def format_parse_exception(
        self,
        message_bus,
        message,
        event,
        data,
        exception
    ):
        if isinstance(exception, ParseException):
            message_bus.reply_message(
                message=message,
                reply_message=BadRequestMessage(
                    error_code=exception.error_code,
                    error_message=exception.error_message,
                )
            )
        else:
            self.format_exception(
                message_bus=message_bus,
                message=message,
                event=event,
                input_obj=data,
                exception=exception,
            )
