import os
from pathlib import Path
from loguru import logger

from qtpy import QtGui, QtWidgets, QtCore, PYSIDE6
from qtpy.QtCore import Qt
from qtpy.QtGui import QFontDatabase

from activity_browser.static import fonts, icons


class ABApplication(QtWidgets.QApplication):
    _main_window = None
    _instance = None

    windows = []
        
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance

    def __init__(self, *args, **kwargs):
        if self._initialized:
            return

        QtCore.QCoreApplication.setAttribute(Qt.AA_ShareOpenGLContexts, True)
        QtCore.QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)

        super().__init__(*args, **kwargs)
        self.set_icon()  # needs to be called right after super().__init__

        QtGui.QGuiApplication.setAttribute(Qt.AA_DontShowIconsInMenus, True)

        self.add_fonts()

        if PYSIDE6:
            self.pyside6_setup()
        
        self._initialized = True

    def add_fonts(self):
        QFontDatabase.addApplicationFont(fonts.__path__[0] + "/mono.ttf")
        QFontDatabase.addApplicationFont(fonts.__path__[0] + "/ptsans.ttf")
        QFontDatabase.addApplicationFont(fonts.__path__[0] + "/notosans.ttf")

    def set_icon(self):
        app_icon = QtGui.QIcon(str(Path(icons.__path__[0]).joinpath("main", "ab-small.png")))
        self.setWindowIcon(app_icon)

    def pyside6_setup(self):
        from qtpy.QtWebEngineQuick import QtWebEngineQuick
        QtWebEngineQuick.initialize()

        style = QtWidgets.QStyleFactory().create("fusion")
        self.setStyle(style)

        self.styleHints().colorSchemeChanged.connect(self.check_palette)
        self.check_palette(self.styleHints().colorScheme())

    def check_palette(self, color_scheme):
        import matplotlib.pyplot as plt

        if color_scheme == Qt.ColorScheme.Dark:
            palette = self.style().standardPalette()
            palette.setColor(QtGui.QPalette.AlternateBase, QtGui.QColor(53, 53, 53))

            plt.style.use("dark_background")

            os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--force-dark-mode"
        else:
            palette = self.style().standardPalette()

            plt.style.use("default")

            os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = ""
        self.setPalette(palette)

    @property
    def main_window(self) -> QtWidgets.QMainWindow:
        """Returns the main_window widget of the Activity Browser"""
        if self._main_window:
            return self._main_window
        raise Exception(
            "main_window not yet initialized, did you try to access it during startup?"
        )

    @main_window.setter
    def main_window(self, widget: QtWidgets.QMainWindow):
        self._main_window = widget

        # connect global keyboard shortcuts to their respective functions
        for seq, func in _global_shortcuts.items():
            shortcut = QtWidgets.QShortcut(QtGui.QKeySequence(seq), widget)
            shortcut.activated.connect(func)

    def show(self):
        self.main_window.showMaximized()

    def close(self):
        for child in self.children():
            if hasattr(child, "close"):
                child.close()

    def deleteLater(self):
        self.main_window.deleteLater()


def global_shortcut(key_sequence):
    """
    Decorator to register a global keyboard shortcut for the main window. Decorate a function with e.g.
    @global_shortcut("Ctrl+S") to register it as a shortcut. Also works on the run method of actions as long as the
    parameters of said action are taken care of.
    """
    def decorator(func):
        _global_shortcuts[key_sequence] = func
        return func
    return decorator

_global_shortcuts = {}
