import traceback
from functools import wraps
from typing import Callable, Any, cast

import PySide2.QtWidgets as QtW


def try_except_silent(func: Callable) -> Callable:
    @wraps(func)
    def wrapper(*args, **kwargs) -> Any:
        try:
            return func(*args, **kwargs)
        except (Exception,):
            return None

    return wrapper


def try_except_result(func: Callable) -> Callable:
    """
    Decorated function returns result. True if no exceptions, False if exception occured.
    Function return value is lost, so it's only useful, if function returns None.
    """

    @wraps(func)
    def wrapper(*args, **kwargs) -> bool:
        try:
            func(*args, **kwargs)
            return True
        except (Exception,):
            self = args[0]
            mbox = QtW.QMessageBox(self.dialog)
            mbox.setWindowTitle(self.dialog.title)
            mbox.setText(self.tr(f"Не удалось загрузить файл с наборами."))
            mbox.setDetailedText(traceback.format_exc())
            mbox.open()
            return False

    return wrapper


def try_except_mbox(
        parent_name: str,
        text: str,
) -> Callable:
    """
    :param parent_name: QWidget parent name for QMessageBox.
    :param text: Text property for QMessageBox.
    """

    def decorate(func: Callable) -> Callable:
        @wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            try:
                return func(*args, **kwargs)
            except (Exception,) as e:
                try:
                    self = args[0]
                    parent = getattr(self, parent_name)

                    mbox = QtW.QMessageBox(parent)
                    mbox.setWindowTitle(parent.title)
                    mbox.setText(parent.tr(text))
                    mbox.setInformativeText(f"{str(e)}")
                    mbox.setDetailedText(traceback.format_exc())
                    mbox.setIcon(QtW.QMessageBox.Critical)

                    grid: QtW.QGridLayout = cast(QtW.QGridLayout, mbox.layout())
                    horizontal_spacer = QtW.QSpacerItem(500, 0,
                                                        QtW.QSizePolicy.Minimum, QtW.QSizePolicy.Expanding)
                    grid.addItem(horizontal_spacer, grid.rowCount(), 0, 1, grid.columnCount())

                    te: QtW.QTextEdit = mbox.findChild(QtW.QTextEdit)
                    te.setFixedHeight(250)

                    mbox.open()
                except (Exception,) as e2:
                    raise e from e2

        return wrapper

    return decorate


class StrEnumMeta(type):

    def __setattr__(self, key: str, value: Any) -> None:
        raise TypeError("Invalid operation.")
