import weakref

from PyQt5.QtCore import QObject
from PyQt5.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QLineEdit,
                             QListWidget, QPlainTextEdit, QRadioButton,
                             QSpinBox)
from ui.widget import Widget


class Editor(Widget):
    def __init__(self, action=None, cell_widget=None):
        super().__init__()
        if cell_widget is None:
            self.cell_widget = None
        elif type(cell_widget) is weakref.ReferenceType:
            self.cell_widget = cell_widget
        else:
            self.cell_widget = weakref.ref(cell_widget)
        self.spec = {}

    def set_readonly(self, readonly=True):
        for w in self.spec.values():
            if isinstance(w, QComboBox):
                w.setDisabled(readonly)
            elif isinstance(w, QListWidget):
                w.setDisabled(readonly)
            elif isinstance(w, QCheckBox):
                w.setDisabled(readonly)
            elif isinstance(w, QObject):
                w.setReadOnly(readonly)

    def do_autocomplete(self, autocomplete):
        if autocomplete is None:
            return
        for k, v in autocomplete.items():
            if k not in self.spec:
                continue
            w = self.spec[k]
            if isinstance(w, QCheckBox):
                w.setChecked(bool(v))
            elif isinstance(w, QComboBox):
                # while w.count() > 0:
                #     w.removeItem(0)
                w.clear()
                w.addItems(list(map(str, v)))
            elif isinstance(w, QDoubleSpinBox):
                w.setValue(float(v))
            elif isinstance(w, QLineEdit):
                w.setText(str(v))
            elif isinstance(w, QListWidget):
                # while w.count() > 0:
                #     w.takeItem(0)
                w.clear()
                w.addItems(list(map(str, v)))
            elif isinstance(w, QRadioButton):
                w.setChecked(bool(v))
            elif isinstance(w, QSpinBox):
                w.setValue(int(v))
            elif isinstance(w, QPlainTextEdit):
                w.setPlainText(str(v))
            elif isinstance(w, QObject):
                raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
            else:
                # ignore default values
                pass

    def connect_modified(self, check_modified):
        for k, w in self.spec.items():
            if isinstance(w, QCheckBox):
                w.toggled.connect(check_modified)
            elif isinstance(w, QComboBox):
                w.currentTextChanged.connect(check_modified)
            elif isinstance(w, QDoubleSpinBox):
                w.valueChanged.connect(check_modified)
            elif isinstance(w, QLineEdit):
                w.textChanged.connect(check_modified)
            elif isinstance(w, QListWidget):
                w.currentItemChanged.connect(check_modified)
            elif isinstance(w, QRadioButton):
                w.toggled.connect(check_modified)
            elif isinstance(w, QSpinBox):
                w.valueChanged.connect(check_modified)
            elif isinstance(w, QPlainTextEdit):
                w.textChanged.connect(check_modified)
            elif isinstance(w, QObject):
                raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
            else:
                # ignore default values
                pass

    def render(self, data, field_name=None, row_number=None, crud=None):
        for k, v in data.items():
            if k not in self.spec:
                continue
            w = self.spec[k]
            if isinstance(w, QCheckBox):
                w.setChecked(bool(v))
            elif isinstance(w, QComboBox):
                w.setCurrentText(str(v))
            elif isinstance(w, QDoubleSpinBox):
                w.setValue(float(v))
            elif isinstance(w, QLineEdit):
                w.setText(str(v))
            elif isinstance(w, QListWidget):
                w.clear()
                w.addItems(list(map(str, v)))
            elif isinstance(w, QRadioButton):
                w.setChecked(bool(v))
            elif isinstance(w, QSpinBox):
                w.setValue(0 if v == "" else int(v))
            elif isinstance(w, QPlainTextEdit):
                w.setPlainText(str(v))
            elif isinstance(w, QObject):
                raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
            else:
                # ignore default values
                pass

    def parse(self, action=None, row_number=None, crud=None):
        ret = {}
        for k, w in self.spec.items():
            if isinstance(w, QCheckBox):
                ret[k] = w.isChecked()
            elif isinstance(w, QComboBox):
                ret[k] = w.currentText()
            elif isinstance(w, QDoubleSpinBox):
                ret[k] = w.value()
            elif isinstance(w, QLineEdit):
                ret[k] = w.text()
            elif isinstance(w, QListWidget):
                ret[k] = [w.item(i).data(0) for i in range(w.count())]
            elif isinstance(w, QRadioButton):
                ret[k] = w.isChecked()
            elif isinstance(w, QSpinBox):
                ret[k] = w.value()
            elif isinstance(w, QPlainTextEdit):
                ret[k] = w.toPlainText()
            elif isinstance(w, QObject):
                raise NotImplementedError(f"widget of type {type(w)!r} not implemented")
            else:
                # pass through default values
                ret[k] = w
        return ret
