#!/usr/bin/env python3

from Qt import QtWidgets, QtGui
from OdenGraphQt import BaseNode
from OdenGraphQt.constants import NodePropWidgetEnum
from OdenGraphQt.qgraphics.node_backdrop import BackdropNodeItem


class BackdropNode(BaseNode):
    """
    Backdrop Node:
      - Allows grouping or annotating other nodes by resizing a large rectangle.
      - Provides a custom context menu for renaming and recoloring (via on_context_menu).
    """

    __identifier__ = 'bunny-lab.io.backdrop'
    NODE_NAME = 'Backdrop'

    def __init__(self):
        # Use BackdropNodeItem for the specialized QGraphicsItem.
        super(BackdropNode, self).__init__(qgraphics_item=BackdropNodeItem)

        # Default color (teal).
        self.model.color = (5, 129, 138, 255)

        # Multi-line text property for storing the backdrop text.
        self.create_property(
            'backdrop_text',
            '',
            widget_type=NodePropWidgetEnum.QTEXT_EDIT.value,
            tab='Backdrop'
        )

    # --------------------------------------------------------------------------
    # Resizing / Geometry
    # --------------------------------------------------------------------------
    def on_backdrop_updated(self, update_prop, value=None):
        """
        Triggered when the user resizes or double-clicks the backdrop sizer handle.
        """
        if not self.graph:
            return

        if update_prop == 'sizer_mouse_release':
            # User finished dragging the resize handle
            self.view.prepareGeometryChange()
            self.graph.begin_undo(f'resized "{self.name()}"')
            self.set_property('width', value['width'])
            self.set_property('height', value['height'])
            self.set_pos(*value['pos'])
            self.graph.end_undo()
            self.view.update()

        elif update_prop == 'sizer_double_clicked':
            # User double-clicked the resize handle (auto-resize)
            self.view.prepareGeometryChange()
            self.graph.begin_undo(f'"{self.name()}" auto resize')
            self.set_property('width', value['width'])
            self.set_property('height', value['height'])
            self.set_pos(*value['pos'])
            self.graph.end_undo()
            self.view.update()

    def auto_size(self):
        """
        Auto-resize the backdrop to fit around intersecting nodes.
        """
        if not self.graph:
            return
        self.view.prepareGeometryChange()
        self.graph.begin_undo(f'"{self.name()}" auto resize')
        size = self.view.calc_backdrop_size()
        self.set_property('width', size['width'])
        self.set_property('height', size['height'])
        self.set_pos(*size['pos'])
        self.graph.end_undo()
        self.view.update()

    def wrap_nodes(self, nodes):
        """
        Fit the backdrop around the specified nodes.
        """
        if not self.graph or not nodes:
            return
        self.view.prepareGeometryChange()
        self.graph.begin_undo(f'"{self.name()}" wrap nodes')
        size = self.view.calc_backdrop_size([n.view for n in nodes])
        self.set_property('width', size['width'])
        self.set_property('height', size['height'])
        self.set_pos(*size['pos'])
        self.graph.end_undo()
        self.view.update()

    def nodes(self):
        """
        Return a list of nodes wrapped by this backdrop.
        """
        node_ids = [n.id for n in self.view.get_nodes()]
        return [self.graph.get_node_by_id(nid) for nid in node_ids]

    def set_text(self, text=''):
        """
        Set the multi-line text in the backdrop.
        """
        self.set_property('backdrop_text', text)

    def text(self):
        """
        Return the text content in the backdrop.
        """
        return self.get_property('backdrop_text')

    def set_size(self, width, height):
        """
        Manually set the backdrop size.
        """
        if self.graph:
            self.view.prepareGeometryChange()
            self.graph.begin_undo('backdrop size')
            self.set_property('width', width)
            self.set_property('height', height)
            self.graph.end_undo()
            self.view.update()
        else:
            self.view.width, self.view.height = width, height
            self.model.width, self.model.height = width, height

    def size(self):
        """
        Return (width, height) of the backdrop.
        """
        self.model.width = self.view.width
        self.model.height = self.view.height
        return self.model.width, self.model.height

    # No ports for a backdrop:
    def inputs(self):
        return

    def outputs(self):
        return

    # --------------------------------------------------------------------------
    # Custom Context Menu
    # --------------------------------------------------------------------------
    def on_context_menu(self, menu):
        """
        Called manually by the node context menu callback in older NodeGraphQt versions.
        """
        rename_action = menu.addAction("Set Title...")
        rename_action.triggered.connect(self._change_title)

        color_action = menu.addAction("Set Color...")
        color_action.triggered.connect(self._change_color)

    def _change_title(self):
        """
        Prompt for a new backdrop title (header).
        """
        new_title, ok = QtWidgets.QInputDialog.getText(
            None, "Backdrop Title", "Enter new backdrop title:"
        )
        if ok and new_title:
            self.set_name(new_title)

    def _change_color(self):
        """
        Prompt for a new backdrop color via QColorDialog.
        """
        current_color = QtGui.QColor(*self.model.color)
        color = QtWidgets.QColorDialog.getColor(
            current_color, None, "Select Backdrop Color"
        )
        if color.isValid():
            self.model.color = (color.red(), color.green(), color.blue(), color.alpha())
            self.view.update()