"""
Here we define the types of tasks
We are using Abstract Base Classes,
like this we can define types of tasks ( text, images, ... )
that all work with the same basic options

The tasks are going to be injected into a Queue.
It's a usefull way of storing information in our
program, while making sure that things are indeed printed.
It's also a way to prevent two concurrent connexions creating
a access conflict on a single printer, like two people wanting
to print at the same time.

We can also delay and store printing tasks until a printer becomes
available if none is online.
"""

from abc import ABC, abstractmethod

## See https://docs.python.org/3/library/abc.html to learn more about this

from enum import Enum
import uuid


## You can expand this if you want to take other types of tasks into account
class TaskType(Enum):
    """
    The different tasks supported by the printers
    """

    TEXT = "text"
    IMAGE = "image"
    CUT = "cut"
    QR = "qr"


class PrintTask(ABC):
    """
    A print task holds information about what we are looking to print.
    """

    def __init__(self, task_type: TaskType):
        self.task_id = self._generate_id()
        self.task_type = task_type
        self.status = "pending"  # pending, processing, completed, failed

    @abstractmethod
    def get_print_data(self):
        """Return data formatted for printer"""

    def _generate_id(self):
        # Generate unique task ID
        return str(uuid.uuid4())


class TextTask(PrintTask):
    """
    This tasks represents a texte content, and it's signature.
    """

    def __init__(self, content, signature):
        super().__init__(TaskType.TEXT)
        self.content = content
        self.signature = signature

    def get_print_data(self):
        return {"txt": self.content, "sign": self.signature}


class QRTask(TextTask):
    """This task prints a QR-Code, the signature is ignore and is always the content itself"""

    def __init__(self, content):
        super().__init__(content, signature="")
        self.content = content
        self.signature = content

    def get_print_data(self):
        return {"txt": self.content, "sign": self.signature}


class ImageTask(PrintTask):
    """
    This tasks represents a image content ( in the form of it's path ), and it's signature.
    """

    def __init__(self, image_path, signature, process):
        super().__init__(TaskType.IMAGE)
        self.image_path = image_path
        self.signature = signature
        self.process = process

    def get_print_data(self):
        # Return image data in printer-compatible format
        return {"img": self.image_path, "sign": self.signature, "process": self.process}


class CutTask(PrintTask):
    """
    This class activates the cutter on the printer if it exists
    """

    def __init__(self):
        super().__init__(TaskType.CUT)

    # There is no print data,
    # the task existence in itself is indication of what to do
    def get_print_data(self):
        return None
