# SPDX-License-Identifier: GPL-3.0-or-later
"""ais_qt_compat.py — one-shot Qt5/Qt6 compatibility layer (QGIS 3 and QGIS 4).

QGIS 4 is built on Qt6/PyQt6, where enum members are only reachable through their
scoped enum class (``Qt.DockWidgetArea.LeftDockWidgetArea``); the Qt5-era unscoped
spelling (``Qt.LeftDockWidgetArea``) raises AttributeError. Rather than rewrite
every enum reference — and risk missing one in a rarely-exercised GUI path — this
module *promotes* every enum member of every class in qgis.PyQt's QtCore / QtGui /
QtWidgets back onto its owning class, restoring the unscoped spelling. (The scoped
spelling always works too, in both Qt versions.)

It also restores the classes Qt6 moved between modules (``QAction`` et al.,
QtWidgets → QtGui), so legacy imports keep resolving.

On Qt5 (QGIS 3) this module is a NO-OP, so QGIS 3 behaviour is untouched. Importing
it more than once is harmless. QGIS's own enums (Qgis.*, Qgs*) are not touched:
QGIS exposes those both scoped and unscoped in its Qt6 builds.

Applied from classFactory (before any GUI module imports), never at package import.
"""
import enum

_applied = False


def _promote(klass):
    """Copy every member of every Enum nested in ``klass`` onto ``klass``."""
    for name in dir(klass):
        try:
            attr = getattr(klass, name)
        except Exception:                               # noqa: BLE001  # nosec B112
            continue
        if isinstance(attr, type) and issubclass(attr, enum.Enum):
            for member in attr:
                if not hasattr(klass, member.name):
                    try:
                        setattr(klass, member.name, member)
                    except Exception:                   # noqa: BLE001  # nosec B110
                        pass


def apply():
    """Apply the compatibility layer (idempotent; no-op on Qt5 / headless)."""
    global _applied
    if _applied:
        return
    try:
        from qgis.PyQt import QtCore
    except Exception:                                   # noqa: BLE001
        return                                          # headless / no Qt: no-op
    if not QtCore.QT_VERSION_STR.startswith("6"):
        _applied = True                                 # Qt5: nothing to do
        return
    try:
        from qgis.PyQt import QtGui, QtWidgets
    except Exception:                                   # noqa: BLE001
        return
    for mod in (QtCore, QtGui, QtWidgets):
        for name in dir(mod):
            obj = getattr(mod, name, None)
            if isinstance(obj, type):
                _promote(obj)
    # Qt6 moved these from QtWidgets to QtGui; alias them back so Qt5-era
    # ``from qgis.PyQt.QtWidgets import QAction`` keeps working.
    for name in ("QAction", "QActionGroup", "QShortcut", "QFileSystemModel",
                 "QUndoCommand", "QUndoStack", "QUndoGroup"):
        if not hasattr(QtWidgets, name) and hasattr(QtGui, name):
            setattr(QtWidgets, name, getattr(QtGui, name))
    _applied = True


apply()
