import time
from logging import Logger
from threading import Thread

from mw_helper import ensure_list
from production.model import (
    ProductionOrder,
    InvalidOrderToPrint,
)
from production.service import PrinterService
from production.util import parse_constants
from production.view import ProductionView
from production.view._OrderXml import OrderXml
from production.view.printerviewservices.reportgenerator import PickListReportGenerator
from production.view.printerviewservices.reportprinter import PickListPrinter
from typing import List


class PrinterView(ProductionView):
    """ class PrinterView(ProductionView)
    Production view used that formats a report (or slip) and prints it.
    """

    def __init__(
        self,
        name,                   # type: str
        message_bus,            # type: MessageBus
        report,                 # type: str
        printer,                # type: str
        picklist_name,          # type: str
        timeout,                # type: int
        production_manager,     # type: ProductionManager
        report_generator,       # type: PickListReportGenerator
        picklist_printer,       # type: PickListPrinter
        tags_on_print=None,     # type: List[str]
        logger=None,            # type: Logger
    ):
        # type: (...) -> None

        super(PrinterView, self).__init__(name, logger)
        self.report_generator = report_generator
        self.picklist_printer = picklist_printer

        self.message_bus = message_bus
        self.report = report
        self.printer = printer
        self.picklist_name = picklist_name
        self.timeout = timeout
        self.tags_on_print = ensure_list(tags_on_print)
        self.logger = logger
        self.order_xml = OrderXml()
        self.production_manager = production_manager
        self.printer_service = PrinterService(
            message_bus=self.message_bus,
            timeout=self.timeout,
        )

    def handle_order(self, order, synch=False):
        # type: (ProductionOrder, bool) -> Thread

        t = Thread(target=self.generate_and_print_report, args=[order])
        t.daemon = True
        t.start()
        return t

    def clear_printer_cache(
        self,   # type: PrinterView
    ):
        # type: (...) -> None

        self.picklist_printer.clear_printer_cache()

    def generate_and_print_report(
        self,   # type: PrinterView
        order,  # type: ProductionOrder
    ):
        # type: (...) -> None

        report = None
        is_reprint = self.production_manager.get_picklist_id(order=order) is not None
        for _ in range(1, 5):
            try:
                report = self.report_generator.production_pick_list(
                    production_order=order,
                    is_reprint=is_reprint,
                )
                break
            except InvalidOrderToPrint:
                break
            except (Exception, ):
                self.exception("Exception trying to generate picklist for Order {}", order.order_id)
                time.sleep(1)

        if report is None or report == "":
            return

        parsed_report = parse_constants(
            printer_text=report,
            pos_id=int(order.originator[-2:]),
            is_reprint=is_reprint,
        )
        print_ok = self.picklist_printer.print_report(text=parsed_report)
        self.production_manager.save_pick_list_order(
            order=order,
            receipt=report,
            status=print_ok,
        )

    def get_view_tags(self):
        return self.tags_on_print
