# Copyright (C) 2026 Henrik Wilhelmsen
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
import logging
from collections.abc import Callable
from dataclasses import dataclass, field

import maya.OpenMayaUI as omui  # noqa: N813
from maya import cmds
from PySide6.QtCore import Qt
from PySide6.QtWidgets import (
    QMainWindow,
    QPushButton,
    QSizePolicy,
    QToolBox,
    QVBoxLayout,
    QWidget,
)
from shiboken6 import wrapInstance

from hw_maya_toolbox.core import (
    buffer_selection,
    center_pivot_for_selection,
    create_circle_at_selected_objects,
    create_locator_at_selected_objects,
    delete_unknown_nodes,
    freeze_del_history_for_selection,
    insert_roll_joint_for_selection,
    match_translation_and_rotation,
    orient_selected_joint_to_parent,
    print_name_and_type_for_selection,
    print_selection,
    reload_modules,
    reset_draw_style_on_selected_joints,
    reset_trs_for_selection,
    start_debugpy,
    toggle_selected_joints_local_axis_vis_off,
    toggle_selected_joints_local_axis_vis_on,
    warn_if_joint_hierarchy_has_rotation,
    zero_pivot_for_selection,
    zero_scale_orient_on_selected_joints,
)

logger = logging.getLogger(__name__)

MAIN_WIDGET_NAME = "hw_toolbox_main_widget"
TOOL_TITLE = "HW Toolbox"


@dataclass
class Button:
    label: str = field(default_factory=str)
    icon: str = field(default_factory=str)
    cmd: Callable[[], None] = lambda: logger.info(
        "Button clicked, but no cmd implemented",
    )


UI_SECTIONS: dict[str, list[Button]] = {
    "General": [
        Button(
            label="Circle",
            cmd=create_circle_at_selected_objects,
        ),
        Button(
            label="Locator",
            cmd=create_locator_at_selected_objects,
        ),
        Button(
            label="Buffer",
            cmd=buffer_selection,
        ),
        Button(
            label="Match TR",
            cmd=match_translation_and_rotation,
        ),
        Button(
            label="Reset TRS",
            cmd=reset_trs_for_selection,
        ),
        Button(
            label="Freeze and Del History",
            cmd=freeze_del_history_for_selection,
        ),
        Button(
            label="Zero Pivot",
            cmd=zero_pivot_for_selection,
        ),
        Button(
            label="Center Pivot",
            cmd=center_pivot_for_selection,
        ),
    ],
    "Joint": [
        Button(
            label="Show LRA",
            cmd=toggle_selected_joints_local_axis_vis_on,
        ),
        Button(
            label="Hide LRA",
            cmd=toggle_selected_joints_local_axis_vis_off,
        ),
        Button(
            label="Reset Draw Style",
            cmd=reset_draw_style_on_selected_joints,
        ),
        Button(
            label="Orient to Parent",
            cmd=orient_selected_joint_to_parent,
        ),
        Button(
            label="Zero Scale Orient",
            cmd=zero_scale_orient_on_selected_joints,
        ),
        Button(
            label="Insert Roll",
            cmd=insert_roll_joint_for_selection,
        ),
        Button(
            label="Check Hierarchy",
            cmd=warn_if_joint_hierarchy_has_rotation,
        ),
    ],
    "Dev": [
        Button(
            label="Start Debugpy",
            cmd=start_debugpy,
        ),
        Button(
            label="Reload Modules",
            cmd=reload_modules,
        ),
        Button(
            label="Delete Unknown Nodes",
            cmd=delete_unknown_nodes,
        ),
        Button(
            label="Print Names",
            cmd=print_selection,
        ),
        Button(
            label="Print Types",
            cmd=print_name_and_type_for_selection,
        ),
    ],
}


def get_maya_main_window() -> QWidget:
    """Get the Maya main window widget."""
    maya_main_window_ptr = omui.MQtUtil.mainWindow()
    maya_main_window: QMainWindow = wrapInstance(int(maya_main_window_ptr), QMainWindow)  # ty: ignore[invalid-assignment]
    return maya_main_window


def get_widget_by_object_name(object_name: str) -> QWidget | None:
    """Find a widget by its object name."""
    widget_ptr = omui.MQtUtil.findControl(object_name)
    if widget_ptr is None:
        return None

    widget: QWidget = wrapInstance(int(widget_ptr), QWidget)  # ty: ignore[invalid-assignment]
    return widget


# https://www.tech-artists.org/t/dockable-pyside-widgets-in-maya-dock-windows/17918
def create_dockable_window(widget: QWidget, title: str) -> None:
    workspace_control_name = widget.objectName() + "_WorkspaceControl"

    if cmds.workspaceControl(workspace_control_name, query=True, exists=True):
        cmds.deleteUI(workspace_control_name)

    # Create the dock with Maya's workspace control system
    _ = cmds.workspaceControl(
        workspace_control_name,
        label=title,
        floating=True,
        resizeHeight=500,
        resizeWidth=300,
        # ttc=["AttributeEditor", -1],  # Target tab (optional, removes float behavior)  # noqa: E501, ERA001
        retain=True,  # <-- makes it persistent across sessions
        # uiScript="import MyModule; MyModule.MyFunction()"  # noqa: ERA001
    )

    # Parent the widget under the workspace control
    control_widget = get_widget_by_object_name(workspace_control_name)
    if control_widget is None:
        raise RuntimeError

    layout = control_widget.layout()
    if layout is not None:
        layout.addWidget(widget)


class HWMayaRigUI(QWidget):
    BUTTON_STYLE = """
        QPushButton {
            background-color: #3a3a3a;
            border: 1px solid #555555;
            border-radius: 4px;
            padding: 0.5em;
            color: #e0e0e0;
            font-size: 1em;
        }
        QPushButton:hover {
            background-color: #4a4a4a;
            border: 1px solid #666666;
        }
        QPushButton:pressed {
            background-color: #2a2a2a;
            border: 1px solid #444444;
        }
    """

    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent=parent)

        # Set up layout and toolbox widget
        self._main_layout: QVBoxLayout = QVBoxLayout(self)
        self._toolbox_widget = QToolBox(parent=self)
        self._main_layout.addWidget(self._toolbox_widget)
        self.setLayout(self._main_layout)

        # Configure widget
        self.setObjectName(MAIN_WIDGET_NAME)
        self.setWindowFlag(Qt.WindowType.Window, on=True)
        self.setWindowFlag(Qt.WindowType.WindowStaysOnTopHint, on=True)

        # Create toolbox sections
        self._create_sections()

    def _get_dpi_scale(self) -> float:
        """Get the DPI scale factor for the current screen."""
        screen = self.screen()
        if screen is None:
            return 1.0

        return screen.logicalDotsPerInch() / 96.0  # 96 DPI is standard

    def _style_button(self, button: QPushButton) -> None:
        """Apply styling and size policy to a button."""
        scale = self._get_dpi_scale()
        button.setStyleSheet(self.BUTTON_STYLE)
        button.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
        button.setMinimumHeight(int(30 * scale))

    def _create_sections(self) -> None:
        for section, buttons in UI_SECTIONS.items():
            section_widget = QWidget(self)
            section_layout = QVBoxLayout(section_widget)
            section_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
            section_widget.setLayout(section_layout)

            for button in buttons:
                button_widget = QPushButton(parent=self, text=button.label)
                self._style_button(button_widget)
                section_layout.addWidget(button_widget)
                button_widget.clicked.connect(button.cmd)

            self._toolbox_widget.addItem(section_widget, section)


def show_ui() -> None:
    existing_widget = get_widget_by_object_name(MAIN_WIDGET_NAME)
    if existing_widget is not None:
        cmds.deleteUI(MAIN_WIDGET_NAME)

    maya_main_window = get_maya_main_window()
    main_window = HWMayaRigUI(parent=maya_main_window)
    create_dockable_window(main_window, TOOL_TITLE)
