from PyQt5.QtWidgets import QTreeWidget, QTreeWidgetItem, QAction
from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal

from OCP.AIS import AIS_ColoredShape
from OCP.gp import gp_Ax3

from cadquery import Vector

from ..mixins import ComponentMixin
from ..icons import icon


class CQChildItem(QTreeWidgetItem):

    def __init__(self, cq_item, **kwargs):

        super(CQChildItem, self).__init__(
            [type(cq_item).__name__, str(cq_item)], **kwargs
        )

        self.cq_item = cq_item


class CQStackItem(QTreeWidgetItem):

    def __init__(self, name, workplane=None, **kwargs):

        super(CQStackItem, self).__init__([name, ""], **kwargs)

        self.workplane = workplane


class CQObjectInspector(QTreeWidget, ComponentMixin):

    name = "CQ Object Inspector"

    sigRemoveObjects = pyqtSignal(list)
    sigDisplayObjects = pyqtSignal(list, bool)
    sigShowPlane = pyqtSignal([bool], [bool, float])
    sigChangePlane = pyqtSignal(gp_Ax3)

    def __init__(self, parent):

        super(CQObjectInspector, self).__init__(parent)
        self.setHeaderHidden(False)
        self.setRootIsDecorated(True)
        self.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.setColumnCount(2)
        self.setHeaderLabels(["Type", "Value"])

        self.root = self.invisibleRootItem()
        self.inspected_items = []

        self._toolbar_actions = [
            QAction(
                icon("inspect"),
                "Inspect CQ object",
                self,
                toggled=self.inspect,
                checkable=True,
            )
        ]

        self.addActions(self._toolbar_actions)

    def menuActions(self):

        return {"Tools": self._toolbar_actions}

    def toolbarActions(self):

        return self._toolbar_actions

    @pyqtSlot(bool)
    def inspect(self, value):

        if value:
            self.itemSelectionChanged.connect(self.handleSelection)
            self.itemSelectionChanged.emit()
        else:
            self.itemSelectionChanged.disconnect(self.handleSelection)
            self.sigRemoveObjects.emit(self.inspected_items)
            self.sigShowPlane.emit(False)

    @pyqtSlot()
    def handleSelection(self):

        inspected_items = self.inspected_items
        self.sigRemoveObjects.emit(inspected_items)
        inspected_items.clear()

        items = self.selectedItems()
        if len(items) == 0:
            return

        item = items[-1]
        if type(item) is CQStackItem:
            cq_plane = item.workplane.plane
            dim = item.workplane.largestDimension()
            plane = gp_Ax3(
                cq_plane.origin.toPnt(), cq_plane.zDir.toDir(), cq_plane.xDir.toDir()
            )
            self.sigChangePlane.emit(plane)
            self.sigShowPlane[bool, float].emit(True, dim)

            for child in (item.child(i) for i in range(item.childCount())):
                obj = child.cq_item
                if hasattr(obj, "wrapped") and type(obj) != Vector:
                    ais = AIS_ColoredShape(obj.wrapped)
                    inspected_items.append(ais)

        else:
            self.sigShowPlane.emit(False)
            obj = item.cq_item
            if hasattr(obj, "wrapped") and type(obj) != Vector:
                ais = AIS_ColoredShape(obj.wrapped)
                inspected_items.append(ais)

        self.sigDisplayObjects.emit(inspected_items, False)

    @pyqtSlot(object)
    def setObject(self, cq_obj):

        self.root.takeChildren()

        # iterate through parent objects if they exist
        while getattr(cq_obj, "parent", None):
            current_frame = CQStackItem(str(cq_obj.plane.origin), workplane=cq_obj)
            self.root.addChild(current_frame)

            for obj in cq_obj.objects:
                current_frame.addChild(CQChildItem(obj))

            cq_obj = cq_obj.parent
