# -*- coding: utf-8 -*-
#!/usr/bin/env python3

from Qt import QtWidgets, QtCore, QtGui
import sys
import pkgutil
import importlib
import inspect

# Patch QGraphicsScene.setSelectionArea to handle selection arguments
_original_setSelectionArea = QtWidgets.QGraphicsScene.setSelectionArea

def _patched_setSelectionArea(self, painterPath, second_arg, *args, **kwargs):
    try:
        # Try calling the original method with the provided arguments.
        return _original_setSelectionArea(self, painterPath, second_arg, *args, **kwargs)
    except TypeError:
        # If a TypeError is raised, assume the call was made with only a QPainterPath
        # and an ItemSelectionMode, and patch it by supplying defaults.
        # Default operation: ReplaceSelection, default transform: QTransform()
        return _original_setSelectionArea(
            self,
            painterPath,
            QtCore.Qt.ReplaceSelection,
            second_arg,
            QtGui.QTransform()
        )

QtWidgets.QGraphicsScene.setSelectionArea = _patched_setSelectionArea

from OdenGraphQt import NodeGraph, BaseNode

def import_nodes_from_folder(package_name):
    """
    Dynamically import all modules from the given package
    and return a list of classes that subclass BaseNode.
    """
    imported_nodes = []
    package = importlib.import_module(package_name)
    for loader, module_name, is_pkg in pkgutil.walk_packages(package.__path__, package.__name__ + "."):
        module = importlib.import_module(module_name)
        for name, obj in inspect.getmembers(module, inspect.isclass):
            if issubclass(obj, BaseNode) and obj.__module__ == module.__name__:
                imported_nodes.append(obj)
    return imported_nodes

def make_node_command(graph, node_type_str):
    """
    Return a function that creates a node of the given type at the current cursor position.
    """
    def command():
        try:
            pos = graph.cursor_pos()
            graph.create_node(node_type_str, pos=pos)
        except Exception as e:
            print("Error creating node of type {}: {}".format(node_type_str, e))
    return command

if __name__ == "__main__":
    app = QtWidgets.QApplication([])

    # Create the NodeGraph controller.
    graph = NodeGraph()
    graph.widget.setWindowTitle("Project Borealis - Flyff Information Overlay")

    # Dynamically import custom node classes from the 'Nodes' package.
    custom_nodes = import_nodes_from_folder("Nodes")
    for node_class in custom_nodes:
        graph.register_node(node_class)

    # Add context menu commands for dynamic node creation.
    graph_context_menu = graph.get_context_menu("graph")
    for node_class in custom_nodes:
        node_type = "{}.{}".format(node_class.__identifier__, node_class.__name__)
        node_name = node_class.NODE_NAME
        graph_context_menu.add_command(
            "Add {}".format(node_name),
            make_node_command(graph, node_type)
        )

    # Add a "Remove Selected Node" command to the graph context menu.
    graph_context_menu.add_command(
        "Remove Selected Node",
        lambda: [graph.remove_node(node) for node in graph.selected_nodes()] if graph.selected_nodes() else None
    )

    # Grid styling changes
    # 1) Dark background color
    graph.set_background_color(20, 20, 20)  # Dark gray
    # 2) Subdued grid color
    graph.set_grid_color(60, 60, 60)        # Gray grid lines

    # Optionally, create a subtle gradient in the scene:
    scene = graph.scene()

    # A QLinearGradient that uses ObjectBoundingMode so it stretches to fill the scene.
    gradient = QtGui.QLinearGradient(0, 0, 0, 1)
    gradient.setCoordinateMode(QtGui.QGradient.ObjectBoundingMode)
    gradient.setColorAt(0.0, QtGui.QColor(9, 44, 68)) # Very Top Gradient
    gradient.setColorAt(0.3, QtGui.QColor(30, 30, 30)) # Middle Gradient
    gradient.setColorAt(0.7, QtGui.QColor(30, 30, 30)) # Middle Gradient
    gradient.setColorAt(1.0, QtGui.QColor(9, 44, 68)) # Very Bottom Gradient
    scene.setBackgroundBrush(QtGui.QBrush(gradient))

    # Resize and show the graph widget.
    graph.widget.resize(1600, 900)
    graph.widget.show()

    def global_update():
        for node in graph.all_nodes():
            if hasattr(node, "process_input"):
                try:
                    node.process_input()
                except Exception as e:
                    print("Error updating node", node, e)

    timer = QtCore.QTimer()
    timer.timeout.connect(global_update)
    timer.start(500)

    sys.exit(app.exec_())