import logging
import time
from logging import Logger
from typing import Optional

from messagebus import (
    DataType,
    DefaultToken,
    Message,
    MessageBus,
    TokenCreator,
    TokenPriority
)
from production.view import ProductionView
from production.model import ProductionOrder

PERIPHERALS_GROUP = "6"
TK_PRN_PRINT = TokenCreator.create_token(TokenPriority.high, PERIPHERALS_GROUP, "101")

MAX_RETRY = 10

printer_logger = logging.getLogger("ProductionPrinter")


class PickListPrinter(ProductionView):
    def __init__(
        self,
        message_bus,    # type: MessageBus
        timeout,        # type: int
        printer,        # type: str
        name,           # type: str
        logger          # type: Logger
    ):
        # type: (...) -> None

        super(PickListPrinter, self).__init__(name, logger)
        self.message_bus = message_bus
        self.timeout = timeout
        self.printer = printer

    def print_report(
        self,
        text    # type: str
    ):
        # type: (...) -> bool

        for attempt in range(1, MAX_RETRY):
            try:
                printer_logger.info("Sending to printer: {} - Attempt: {}".format(self.printer, attempt))

                if attempt == 1:
                    printer_logger.info("Printer: {} - \nPrinting:\n {}".format(self.printer, text))

                message = Message(
                    token=TK_PRN_PRINT,
                    data_type=DataType.string,
                    data=text,
                    timeout=self.timeout
                )
                reply = self.message_bus.send_message(
                    component=self.printer,
                    message=message
                )
                if reply.token != DefaultToken.TK_SYS_ACK:
                    log_message = "Invalid response from Printer: {} / {} - {}"
                    printer_logger.warning(log_message.format(self.printer, reply.token, reply.data))
                else:
                    printer_logger.info("Successfully printed on Printer: {}".format(self.printer))
                    return True
            except BaseException as ex:
                message_name = type(ex).__name__
                if attempt >= MAX_RETRY - 1:
                    log_message = "Printer {} unavailable - Failed to Print Report - {}"
                    printer_logger.warning(log_message.format(self.printer, message_name))
                else:
                    log_message = "Error when trying to print on Printer {} in attempt {} - {}"
                    printer_logger.info(log_message.format(self.printer, attempt, message_name))

            time.sleep(2 * attempt)

        return False

    def handle_order(
        self,
        order,          # type: ProductionOrder
        synch=False     # type: Optional[bool]
    ):
        # type: (...) -> None

        raise NotImplementedError()

    def get_view_tags(self):
        # type: (...) -> None
        raise NotImplementedError()
