from lib.db import Steps
from peewee import IntegrityError
from ui.barcodes_step_editor import Barcodes_Step_Editor
from ui.connector_step_editor import Connector_Step_Editor
from ui.count_step_editor import Count_Step_Editor
from ui.editor import Editor
from ui.helpers import replace_widget
from ui.leak_step_editor import Leak_Step_Editor
from ui.print_step_editor import Print_Step_Editor
from ui.resistance_step_editor import Resistance_Step_Editor
from ui.screws_step_editor import Screws_Step_Editor
from ui.vision_step_editor import Vision_Step_Editor


class Recipe_Spec_And_Step_Editor(Editor):
    def __init__(self, action=None, cell_widget=None, unsupported_steps=None):
        super().__init__(action=action, cell_widget=cell_widget)
        self.map = {
            "count": {
                "type": "count",
                "enable": self.count_enabled_cb,
                "widget": "count_editor_w",
                "editor": Count_Step_Editor(),
                "tab": self.count_t,
            },
            "connector": {
                "type": "connector",
                "enable": self.connector_enabled_cb,
                "widget": "connector_editor_w",
                "editor": Connector_Step_Editor(),
                "tab": self.connector_t,
            },
            "barcodes": {
                "type": "barcodes",
                "enable": self.barcode_enabled_cb,
                "widget": "barcode_editor_w",
                "editor": Barcodes_Step_Editor(),
                "tab": self.barcode_t,
            },
            "resistance": {
                "type": "resistance",
                "enable": self.resistance_enabled_cb,
                "widget": "resistance_editor_w",
                "editor": Resistance_Step_Editor(),
                "tab": self.resistance_t,
            },
            "screws": {
                "type": "screws",
                "enable": self.screws_enabled_cb,
                "widget": "screws_editor_w",
                "editor": Screws_Step_Editor(),
                "tab": self.screws_t,
            },
            "leak_1": {
                "type": "leak",
                "enable": self.leak_enabled_1_cb,
                "widget": "leak_editor_1_w",
                "editor": Leak_Step_Editor(),
                "tab": self.leak_1_t,
            },
            "leak_2": {
                "type": "leak",
                "enable": self.leak_enabled_2_cb,
                "widget": "leak_editor_2_w",
                "editor": Leak_Step_Editor(),
                "tab": self.leak_2_t,
                "hidden": True,
            },
            "vision": {
                "type": "vision",
                "enable": self.vision_enabled_cb,
                "widget": "vision_editor_w",
                "editor": Vision_Step_Editor(),
                "tab": self.vision_t,
            },
            "print": {
                "type": "print",
                "enable": self.print_enabled_cb,
                "widget": "print_editor_w",
                "editor": Print_Step_Editor(),
                "tab": self.print_t,
            },
        }
        for step_name in unsupported_steps:
            self.map.get(step_name, {})["hidden"] = True
        self.spec.update({step_name: map["enable"] for step_name, map in self.map.items()})
        for map in self.map.values():
            editor = map.get("editor", None)
            if editor is not None:
                replace_widget(self, map["widget"], editor)
            self.steps_tw.setTabVisible(self.steps_tw.indexOf(map["tab"]), not map.get("hidden", False))
        self.save_steps_b.clicked.connect(self.save_steps)
        self.reset_steps_b.clicked.connect(self.reset_steps)
        self.available_steps = {}

    def set_readonly(self, readonly=True):
        super().set_readonly(readonly=readonly)
        for map in self.map.values():
            editor = map.get("editor", None)
            if editor is not None:
                editor.set_readonly(readonly=readonly)
        self.save_steps_b.setDisabled(readonly)
        self.reset_steps_b.setDisabled(readonly)

    def do_autocomplete(self, autocomplete):
        if autocomplete is None:
            return
        step_editors_autocomplete = autocomplete.get("step_editors", None)
        super().do_autocomplete(autocomplete)
        if step_editors_autocomplete is not None:
            for step_name, map in self.map.items():
                editor = map.get("editor", None)
                if editor is not None:
                    editor.do_autocomplete(step_editors_autocomplete.get(step_name, None))

    def init(self, action=None):
        self.get_steps()
        if action == "add":
            self.save_steps()

    def showing_dialog(self):
        self.reset_steps()

    # def connect_modified(self, check_modified):
    #     super().connect_modified(check_modified)
    #     for map in self.map.values():
    #         editor = map.get("editor", None)
    #         if editor is not None:
    #             editor.connect_modified(check_modified)

    def render(self, data, field_name=None, row_number=None, crud=None):
        super().render(data, field_name=field_name, row_number=row_number, crud=crud)
        self.available_steps = data.get("available_steps", None)
        self.get_steps()
        steps = set(data.get("steps", set()))
        for map in self.map.values():
            step = map.get("step", None)
            if step is not None:
                map["enable"].setChecked(step.name in steps and not map.get("hidden", False))
        self.render_steps()

    def parse(self, action=None, row_number=None, crud=None):
        # if action == "commit":
        #     self.save_steps()
        ret = super().parse(row_number=row_number, crud=crud)
        ret["steps"] = []
        ret["available_steps"] = {}
        for step_name, map in self.map.items():
            ret["available_steps"][step_name] = map["step"].name
            if map["enable"].isChecked() and not map.get("hidden", False):
                ret["steps"].append(map["step"].name)
        return ret

    def get_steps(self):
        for step_name, map in self.map.items():
            if step_name in self.available_steps:
                try:
                    map["step"] = Steps.get_by_id(self.available_steps[step_name])
                    map["step_is_new"] = False
                except Steps.DoesNotExist:
                    map["step"] = Steps(name=self.available_steps[step_name], type=map["type"], spec={})
                    map["step_is_new"] = True
            elif map.get("step", None) is None:
                map["step"] = Steps(type=map["type"], spec={})
                map["step_is_new"] = True

    def render_steps(self):
        for step_name, map in self.map.items():
            step = map.get("step", None)
            if step is not None:
                editor = map.get("editor", None)
                if editor is not None:
                    editor.render(step.spec)

    def reset_steps(self):
        self.get_steps()
        self.render_steps()

    def save_steps(self):
        for map in self.map.values():
            step = map.get("step", None)
            if step is not None:
                editor = map.get("editor", None)
                if editor is not None:
                    step.spec = editor.parse()
                if map["step_is_new"]:
                    step.save(force_insert=True)
                else:
                    step.save()
                map["step_is_new"] = False
        self.reset_steps()
