import re
import sys

from lib.helpers import timing
from PyQt5.QtCore import QTimer
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QShortcut
from ui.test_test import Test_Test


class Test_Barcodes(Test_Test):
    def __init__(self, components=None, recipe=None, step=None, pieces=None, run_once=False, reset_on_start=True, enable_override=False):
        super().__init__(components=components, recipe=recipe, step=step, pieces=pieces, run_once=run_once, reset_on_start=reset_on_start, enable_override=enable_override)
        self.current_step_barcode_name = None
        self.start_counter = 0
        self.barcodes_spec = {
            "serial": self.check_serial_barcode,
            "barcode_input_2": self.check_serial_barcode,
            "barcode_input_3": self.check_serial_barcode,
            "barcode_input_4": self.check_serial_barcode,
            "barcode_input_5": self.check_serial_barcode,

        }
        QShortcut(QKeySequence("Return"), self).activated.connect(self.get)
        QShortcut(QKeySequence("Enter"), self).activated.connect(self.get)
        self.barcodes_le.setFocus()
        self.focus_timer = QTimer()
        self.focus_timer.setSingleShot(True)
        self.focus_timer.timeout.connect(self.set_focus)

    def start(self, recipe=None, step=None, pieces=None):
        show = super().start(recipe=recipe, step=step, pieces=pieces)
        self.start_counter += 1
        npieces = self.step.spec.get("n_pieces")
        npieces = int(npieces) if npieces is not None else 0
        display_str = "PEZZI RIMANENTI {}".format(npieces)
        self.counter_l.setText(display_str)
        if show is False:
            return show
        self.current_step_barcode_name = self.step.spec.get('barcode_name')
        self.expected_barcode.setText(self.step.spec.get(self.current_step_barcode_name))
        self.visualize()
        self.barcodes_le.setPalette(self.status_palettes[None])
        self.barcodes_le.setText("")
        self.barcodes_le.setFocus()
        self.focus_timer.start(500)

        # TESTING
        if "--test-barcodes" in sys.argv or "--test" in sys.argv:
            self.barcodes_le.setText("-----TEST_BARCODE-----")
            self.test_timer = QTimer()
            self.test_timer.setSingleShot(True)
            self.test_timer.timeout.connect(self.get)
            self.test_timer.start(500)
        # /TESTING
        return show

    # def stop(self):
    #     super().stop()

    def reset(self):
        super().reset()
        self.barcodes = {}

    def get(self, data=None, override=False):
        if self.done:  # avoid proccessing if completed
            return
        if data is None:
            data = self.barcodes_le.text()
        if not len(data):
            data = None
        if data is None:
            super().get(None, override=override)
            return
        barcode_ok = False
        self.current_step_barcode_name = self.step.spec.get('barcode_name')  # get current step's barcode name
        barcode_check = self.barcodes_spec.get(self.current_step_barcode_name)

        # If the current step's barcode type exists in barcodes_spec and it's valid, store it
        if barcode_check and barcode_check(data):
            self.barcodes[self.current_step_barcode_name] = data
            barcode_ok = True
            self.barcodes_le.setPalette(self.status_palettes[True])
            if self.current_step_barcode_name in self.barcodes:  # if the barcode for the current step is stored in self.barcodes
                result = self.barcodes
                ok = True
            else:
                result = None
                ok = None
            super().get([{
                "time": timing(),
                "results": {
                    "ok": ok,
                    "result": result,
                    "data": self.barcodes,
                },
            }], override=override, fail=ok is False)
        else:
            self.barcodes_le.setPalette(self.status_palettes[False])
        self.barcodes_le.setText("")
        self.barcodes_le.setFocus()

    def visualize(self, data=None):
        if data is None:
            data = {}
        d = data.get("results", {}).get("data", {})
        for k, l in {
            "serial": self.serial_l,
            "barcode_input_2": self.serial_l,
            "barcode_input_3": self.serial_l,
            "barcode_input_4": self.serial_l,
            "barcode_input_5": self.serial_l,
        }.items():
            l.setText(str(d.get(k, "-")))
        super().visualize(data)

    def check_serial_barcode(self, barcode=None):
        if not isinstance(barcode, str) or len(barcode) == 0:
            return False
        barcode_regex = self.step.spec.get(self.current_step_barcode_name, ".*")
        barcode_regex = barcode_regex.replace("{RECIPE}", self.recipe.name)
        for n in range(32):
            barcode_regex = barcode_regex.replace(f"{{N{n}}}", f"[0-9]{{{n}}}")
        return re.fullmatch(barcode_regex, barcode) is not None

    def set_focus(self):
        self.barcodes_le.setFocus()
