import json

from PyQt6.QtCore import pyqtSignal, Qt, QSize, QObject, QEvent
from PyQt6.QtGui import QMouseEvent
from PyQt6.QtWidgets import QTreeView, QVBoxLayout, QTabWidget, QStackedWidget, QDialog, QTabBar, QPushButton, QWidget, \
    QToolButton, QLineEdit

from power_qt.json_editor.data_tree import DataTreeWidget
from power_qt.other.json_models import QJsonTreeItem, QJsonModel


class TabBarPlus(QTabBar):
    """Tab bar that has a plus button floating to the right of the tabs."""

    plusClicked = pyqtSignal()

    def __init__(self,parent=None):
        super().__init__(parent)


        self.lineEditor = QLineEdit()

    def mouseDoubleClickEvent(self, event:QMouseEvent):
        print(event.pos())
        self.lineEditor.setText(str(self.tabText(0)))


# end class MyClass

class CustomTabWidget(QTabWidget):
    """Tab Widget that that can have new tabs easily added to it."""

    def __init__(self, parent=None):
        super().__init__(parent)

        # Tab Bar
        self.tab = TabBarPlus(self)
        self.setTabBar(self.tab)

        self.tabButton = QToolButton(self)
        self.tabButton.setText('+')
        font = self.tabButton.font()
        font.setBold(True)
        self.tabButton.setFont(font)
        self.setCornerWidget(self.tabButton)

    # end Constructor


# end class CustomTabWidget

class QDefaultFieldsModel(QJsonModel):

    def __init__(self, parent=None, edit_columns=None):
        super(QDefaultFieldsModel, self).__init__(parent)

        self.editable_cols = [1]  # edit_columns

        self._rootItem = QJsonTreeItem()
        self._headers = ("key", "value")

    def json(self, root=None):
        """Serialise model as JSON-compliant dictionary

        Arguments:
            root (QJsonTreeItem, optional): Serialise from here
                defaults to the top-level item

        Returns:
            model as dict

        """
        root = root or self._rootItem
        return {self.objectName(): self.genJson(root)}  # modification to return from tabs

    def get_data(self):
        return self.json()

    def genJson(self, item):
        nchild = item.childCount()

        if item.type is dict:
            document = {}
            for i in range(nchild):
                ch = item.child(i)
                document[ch.key] = self.genJson(ch)
            return document

        elif item.type == list:
            document = []
            for i in range(nchild):
                ch = item.child(i)
                document.append(self.genJson(ch))
            return document

        else:
            return item.value


class DefaultFieldsWidget(QDialog):
    attributeUpdated = pyqtSignal(dict)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._isnested = False
        self._models_cache = []
        self._path = None
        self._path_loaded_json = None

        self._lay = QVBoxLayout(self)
        self._tab_block = CustomTabWidget(self)

        self._tab_block.tabButton.clicked.connect(self.add_tab)

        # self._tab_block.tabBar().setTabButton(0, QTabBar.ButtonPosition.RightSide, QPushButton('+'))

        self._lay.addWidget(self._tab_block)

        self.setLayout(self._lay)

        self.resize(600, 1000)
        try:
            self.attributeUpdated.connect(self.save_json)
        except AttributeError:
            pass

        if parent is not None:
            self.setWindowTitle(str(parent))

    def add_tab(self):
        self._createModel(f'new_entry_{self._tab_block.tabBar().count() + 1}', {})

    @property
    def path(self):

        return self._path

    @path.setter
    def path(self, value):
        self._path = value
        try:
            with open(self._path, "r+") as fp:
                self._path_loaded_json = json.load(fp)
        except FileNotFoundError:
            self._path_loaded_json = dict()

    def add_pages(self, new_col_dict):

        if self._path_loaded_json:
            trg_dict = self._path_loaded_json
        else:
            trg_dict = new_col_dict

        self.__clearModels()

        self._isnested = self.isNested(trg_dict)

        if self._isnested:
            for tabname, dictionary in trg_dict.items():
                self._createModel(tabname, dictionary)
        else:
            self._createModel('Dictionary', trg_dict)

    def _createModel(self, name: str, _adict: dict):
        _model = QDefaultFieldsModel()
        _model.load(_adict)
        _model.setObjectName(name)

        _view = QTreeView(self._tab_block)
        _view.setModel(_model)
        _view.setObjectName(name)
        _view.expandAll()

        self._models_cache.append(_model)
        # _view.expandRecursively()
        _view.resizeColumnToContents(0)
        _view.resizeColumnToContents(1)
        _model.dataChanged.connect(self.updatedDictionary)

        self._tab_block.addTab(_view, name)

    def __clearModels(self):
        for tab in range(self._tab_block.count()):
            self._tab_block.removeTab(tab)

        for widget in self._tab_block.findChildren(QTreeView):
            widget.deleteLater()

    def updatedDictionary(self):
        if self._isnested:
            result = {}
            for model in self._models_cache:
                result.update(model.get_data())

        else:
            result = self._models_cache[0].get_data()

        self.attributeUpdated.emit(result)

    def getmyDict(self):
        trees = self._tab_block.findChildren(QStackedWidget)[0].findChildren(QTreeView)
        self._tab_block.objectName()
        d = {}

        for tree in trees:
            d[tree.objectName()] = tree.model().json()

        return d

    @staticmethod
    def isNested(_myDict: dict):
        return any(isinstance(i, dict) for i in _myDict.values())

    def save_json(self, data_from_ui):
        try:
            with open(self._path, "w+") as fp:
                json.dump(data_from_ui, fp)
            print("Saved Json to: {}".format(self._path))
        except:
            pass


class DefaultPropertiesWidget(DefaultFieldsWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.default = dict()

    def setModelDefaults(self, _adict: dict):
        self.default = _adict

    def return_default(self):
        pass

    def setModelSource(self, _dict: dict):
        for key, value in _dict.items():
            self._createModel(key, value)

    def _createModel(self, name: str, _adict: dict):
        _view = DataTreeWidget(self._tab_block)
        _view.set_data(_adict)
        _view.setObjectName(name)

        _view.tree_widget.model().dataChanged.connect(self.updatedDictionary)
        _view.tree_widget.sortByColumn(0, Qt.SortOrder.AscendingOrder)
        self._models_cache.append((name, _view))

        self._tab_block.addTab(_view, name)

    def updatedDictionary(self):
        if self._isnested:
            result = {}
            for name, model in self._models_cache:
                result.update({name: model.get_data()})

        else:
            result = self._models_cache[0].get_data()

        self.attributeUpdated.emit(result)
