"""Off-app-safe versions of the Qt helpers the app injects into plugin modules.

Inside the running app, ``_fa``, ``_EDITOR_COMBO_STYLE``, and
``_style_combo_view`` are injected into every plugin module's namespace before
it's executed (see the ``module._EDITOR_COMBO_STYLE = _EDITOR_COMBO_STYLE``
lines around ``PC Software/mixlar_mini.py:3960``), which is why example plugins
reference them without importing anything — and why they don't resolve in an
editor or under plain ``python -c``. Import them from here instead::

    from mixlar.qt import _fa, _EDITOR_COMBO_STYLE, _style_combo_view

Off-app this module only needs PyQt5/qtawesome if you actually build Qt
widgets with it; both are optional and imported lazily, so ``import
mixlar.qt`` always succeeds even with neither installed — you just get inert
stand-ins. If the live app is already imported in-process, its real
implementations are re-exported instead (same pattern as ``colors.py``), so a
plugin authored against this module gets the exact runtime behaviour.
"""
from __future__ import annotations

import sys as _sys
from typing import Any, Optional

from .colors import ACCENT, CARD, CARD2, SEP, WHITE

try:
    import qtawesome as _qta
    _HAS_QTA = True
except Exception:  # pragma: no cover - optional dependency
    _qta = None
    _HAS_QTA = False

try:
    from PyQt5.QtGui import QIcon as _QIcon
    _HAS_QT = True
except Exception:  # pragma: no cover - optional dependency
    _QIcon = None
    _HAS_QT = False


class _NullIcon:
    """Harmless stand-in for a ``QIcon`` when Qt/qtawesome are unavailable.

    Safe to pass around and hold as an attribute; any attribute access or call
    is a no-op rather than an ``AttributeError``, so plugin code that stores
    icons off-app doesn't need its own availability checks.
    """

    def __getattr__(self, _name: str) -> Any:
        return lambda *a, **k: None

    def __repr__(self) -> str:  # pragma: no cover - cosmetic
        return "<NullIcon>"


def _fa(name: str, color: Optional[str] = None) -> Any:
    """Return a ``qtawesome`` icon for ``name``, or a harmless stub.

    Mirrors the app's own ``_fa`` (``PC Software/mixlar_mini.py:84``): never
    raises, defaults to white when qtawesome is available but no color is
    given. Off-app without qtawesome/PyQt5 installed, returns a
    :class:`_NullIcon` instead of ``None`` so callers can still assign it to a
    widget property without an availability check.
    """
    if not _HAS_QTA:
        return _NullIcon()
    try:
        return _qta.icon(name, color=color or "#ffffff")
    except Exception:
        return _NullIcon()


def _EDITOR_COMBO_STYLE() -> str:
    """A reasonable dark ``QComboBox`` stylesheet matching the app's palette.

    Uses :data:`mixlar.colors.CARD2`/``SEP``/``WHITE``/``ACCENT`` so it looks
    at home next to the real app styling even off-app.
    """
    return f"""
    QComboBox {{
        background: {CARD2}; color: {WHITE};
        border: 1.5px solid {SEP}; border-radius: 12px;
        padding: 9px 30px 9px 13px; font-size: 14px;
    }}
    QComboBox:focus, QComboBox:on {{ border-color: {ACCENT}; background: {CARD2}; }}
    QComboBox::drop-down {{ border: none; width: 28px; }}
    QComboBox::down-arrow {{ image: none; width: 0; height: 0; }}
    """


def _style_combo_view(combo: Optional[Any]) -> None:
    """Best-effort themed styling of a ``QComboBox``'s popup view.

    No-op if PyQt5 is unavailable, ``combo`` is ``None``, or anything about
    ``combo`` doesn't look like a real ``QComboBox`` (missing ``.view()``,
    detached popup, etc.). Never raises.
    """
    if not _HAS_QT or combo is None:
        return
    try:
        view = combo.view()
        parent = view.parentWidget()
        if parent is not None:
            parent.setStyleSheet(f"background: {CARD}; border: 1px solid {SEP};")
        view.setStyleSheet(
            f"QAbstractItemView {{ background: {CARD}; color: {WHITE};"
            f" border: none; selection-background-color: {ACCENT}; padding: 4px; }}"
        )
    except Exception:
        pass


# If running inside the live app, re-export its real implementations so a
# plugin gets identical behaviour (and identical QIcon caching) at runtime.
_app = _sys.modules.get("mixlar_mini")
if _app is not None:  # pragma: no cover - only true inside the desktop app
    _g = getattr(_app, "__dict__", {})
    if "_fa" in _g:
        _fa = _g["_fa"]  # type: ignore[assignment]
    if "_EDITOR_COMBO_STYLE" in _g:
        _EDITOR_COMBO_STYLE = _g["_EDITOR_COMBO_STYLE"]  # type: ignore[assignment]
    if "_style_combo_view" in _g:
        _style_combo_view = _g["_style_combo_view"]  # type: ignore[assignment]


__all__ = ["_fa", "_EDITOR_COMBO_STYLE", "_style_combo_view"]
