import os
import sys

from PyQt6.QtGui import QIcon, QImage, QPixmap
from PyQt6.QtWidgets import QApplication, QMenu, QSystemTrayIcon

from vorta.store.models import BackupProfileModel
from vorta.utils import get_asset


class TrayMenu(QSystemTrayIcon):
    def __init__(self, parent: QApplication = None):
        QSystemTrayIcon.__init__(self, parent)
        self.app = parent
        self.set_tray_icon()
        menu = QMenu()

        # Workaround to get `activated` signal on Unity: https://stackoverflow.com/a/43683895/3983708
        menu.aboutToShow.connect(self.build_menu)

        self.setContextMenu(menu)
        self.build_menu()

        self.activated.connect(self.on_activation)
        self._palette_connection = self.app.paletteChanged.connect(lambda p: self.set_tray_icon())
        self.destroyed.connect(self._on_destroyed)
        self.setVisible(True)
        self.show()

    def on_activation(self, reason):
        """
        XDG-compliant tray behavior: right click to open a context menu, and left click to
        restore the application.

        If XDG_CURRENT_DESKTOP isn't set, always open the tray menu (macOS)
        """
        if reason in [
            QSystemTrayIcon.ActivationReason.Trigger,
            QSystemTrayIcon.ActivationReason.DoubleClick,
        ] and os.environ.get('XDG_CURRENT_DESKTOP'):
            self.app.toggle_main_window_visibility()

    def build_menu(self):
        """Build system tray menu based on current state."""

        menu = self.contextMenu()
        menu.clear()

        open_action = menu.addAction(self.tr('Vorta for Borg Backup'))
        open_action.triggered.connect(self.app.open_main_window_action)

        menu.addSeparator()

        next_task_time = self.app.scheduler.next_job()
        status = menu.addAction(next_task_time)
        status.setEnabled(False)

        if self.app.jobs_manager.is_worker_running():
            status.setText(self.tr('Task in progress'))
            cancel_action = menu.addAction(self.tr('Cancel Backup'))
            cancel_action.triggered.connect(self.app.backup_cancelled_event.emit)
        else:
            status.setText(self.tr('Next Task: %s') % next_task_time)
            profiles = BackupProfileModel.select()
            if profiles.count() > 1:
                profile_menu = menu.addMenu(self.tr('Backup Now'))
                for profile in sorted(profiles, key=lambda p: (p.name.casefold(), p.name)):
                    new_item = profile_menu.addAction(profile.name)
                    new_item.triggered.connect(lambda state, i=profile.id: self.app.create_backup_action(i))
            else:
                profile = profiles.first()
                profile_menu = menu.addAction(self.tr('Backup Now'))
                profile_menu.triggered.connect(lambda state, i=profile.id: self.app.create_backup_action(i))

        menu.addSeparator()

        exit_action = menu.addAction(self.tr('Quit'))
        exit_action.triggered.connect(self.app.quit)

    def set_tray_icon(self, active=False):
        """
        Use white tray icon, when on Gnome or in dark mode.
        Use mask tray icon when on macOS.
        Otherwise use dark icon.
        """
        if sys.platform == 'darwin':
            icon_name = f"icons/hdd-o{'-active' if active else ''}-mask.svg"
            icon = QIcon(QPixmap(QImage.fromData(open(get_asset(icon_name), 'rb').read()).scaledToHeight(128)))
            icon.setIsMask(True)
        else:
            icon_name = f"icons/hdd-o{'-active' if active else ''}.png"
            icon = QIcon(get_asset(icon_name))
        self.setIcon(icon)

    def _on_destroyed(self):
        try:
            self.app.paletteChanged.disconnect(self._palette_connection)
        except (TypeError, RuntimeError):
            pass
