#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# pylint: disable=expression-not-assigned

"""Defines Mainwindow - a non application specific, platform independent MainWindow with
some common features
"""

import logging
from typing import Any, Dict, List, Set
import signal
import threading

from PyQt5 import QtCore, QtGui, QtWidgets, uic

from .. import application_root_dir

from ..core.util import (
    log,
    open_in_directory_of,
)


class MainWindow(QtWidgets.QMainWindow):
    class QPlainTextEditLogger(logging.Handler):
        """Invokes main thread to write to log window"""
        def __init__(self, receiver) -> None:
            super().__init__()
            self.log_receiver = receiver
            self.initial_thread = threading.get_ident()

        def emit(self, record: logging.LogRecord) -> None:
            msg = self.format(record)
            if self.initial_thread == threading.get_ident():
                self.log_receiver.write_log(msg)
            else:
                QtCore.QMetaObject.invokeMethod(
                    self.log_receiver, 'write_log', QtCore.Qt.QueuedConnection, QtCore.Q_ARG(str, msg))

    def __init__(self, _args=None) -> None:
        super().__init__()
        self.windowTitleChanged.connect(self.on_windowTitleChanged)
        with open_in_directory_of(__file__, "mainwindow.ui") as file:
            uic.loadUi(file, self, package="application.ui")

        for sig in (signal.SIGABRT, signal.SIGINT, signal.SIGSEGV, signal.SIGTERM):
            signal.signal(sig, lambda signal, frame: self.handle_signal(signal))

        # catch the interpreter every now and then to be able to catch signals
        self.idle_timer = QtCore.QTimer()
        self.idle_timer.timeout.connect(lambda: None)
        self.idle_timer.start(200)

        log().info("app dir: %r", application_root_dir())

        self.setMouseTracking(True)

    def setup_common_widgets(self):
        self.log_view.setReadOnly(True)
        self.log_view.setLineWrapMode(0)
        font = QtGui.QFont("unexistent")
        font.setStyleHint(QtGui.QFont.Monospace)
        font.setPointSize(10)
        self.log_view.setFont(font)
        logTextBox = self.QPlainTextEditLogger(self)
        logTextBox.setFormatter(logging.Formatter(
            "%(levelname)s %(asctime)s %(name)s: %(message)s", datefmt='%H:%M:%S'))
        logging.getLogger().addHandler(logTextBox)
        # self.pb_quit.clicked.connect(self.close)
        # self.pb_log.toggled.connect(self.toggle_log)
        # self.pb_log.setChecked(True)
        # self.pb_fullscreen.clicked.connect(self.toggle_fullscreen)

    def _initialize_tray_icon(self) -> QtWidgets.QSystemTrayIcon:
        def restore_window(reason: QtWidgets.QSystemTrayIcon.ActivationReason) -> None:
            if reason == QtWidgets.QSystemTrayIcon.DoubleClick:
                self.tray_icon.hide()
                self.showNormal()

        tray_icon = QtWidgets.QSystemTrayIcon(self)
        tray_icon.setIcon(self.windowIcon())
        tray_icon.activated.connect(restore_window)
        return tray_icon

    def on_windowTitleChanged(self, title: str) -> None:
        QtCore.QCoreApplication.setApplicationName(title)
        self.setWindowIconText(title)

    @QtCore.pyqtSlot(str)
    def write_log(self, message):
        self.log_view.appendPlainText(message)
        self.log_view.verticalScrollBar().setValue(self.log_view.verticalScrollBar().maximum())

    def toggle_log(self):
        self.log_view.setVisible(self.pb_log.isChecked())

    def toggle_fullscreen(self):
        (self.showNormal if self.isFullScreen() else
         self.showFullScreen)()

    def keyPressEvent(self, event):
        if event.key() == QtCore.Qt.Key_F11:
            self.toggle_fullscreen()
        return super().keyPressEvent(event)

    def event(self, e):
        if not isinstance(e, (
                QtCore.QEvent,
                QtCore.QChildEvent,
                QtCore.QDynamicPropertyChangeEvent,
                QtGui.QPaintEvent,
                QtGui.QHoverEvent,
                QtGui.QMoveEvent,
                QtGui.QEnterEvent,
                QtGui.QResizeEvent,
                QtGui.QShowEvent,
                QtGui.QPlatformSurfaceEvent,
                QtGui.QWindowStateChangeEvent,
                QtGui.QKeyEvent,
                QtGui.QWheelEvent,
                QtGui.QMouseEvent,
                QtGui.QFocusEvent,
                QtGui.QHelpEvent,
                QtGui.QHideEvent,
                QtGui.QCloseEvent,
                QtGui.QInputMethodQueryEvent,
                QtGui.QContextMenuEvent,
                )):
            log().warning("unknown event: %r %r", e.type(), e)
        return super().event(e)

    def closeEvent(self, event):
        for handler in logging.getLogger().handlers:
            if isinstance(handler, self.QPlainTextEditLogger):
                logging.getLogger().removeHandler(handler)
                break
        return super().closeEvent(event)

    def handle_signal(self, sig: int) -> None:
        """Handle posix signals, i.e. shut down on CTRL-C"""
        log().info(
            "got signal %s(%d)",
            dict((k, v) for v, k in reversed(sorted(signal.__dict__.items()))
                 if v.startswith('SIG') and not v.startswith('SIG_')).get(sig, "unknown"),
            sig)
        if sig == signal.SIGINT:
            self.close()