import sys, os

from Qt import QtWidgets,QtGui, QtCore, QtNetwork
import ctypes
import icons

import logging, utils
import logging.handlers
import font

INTERNAL_SENTRY_DSN = "http://a5d00369c34f4334b128be899ab26b04@sentry.burut.net/2"
EXTERNAL_SENTRY_DSN = "https://8c929c19aeac4bd99663ed2c24b1362f@o995141.ingest.sentry.io/5958525"

def my_excepthook(type, value, tback):
    # log the exception here

    # then call the default handler
    sys.__excepthook__(type, value, tback)

sys.excepthook = my_excepthook


class QSingleApplication(QtWidgets.QApplication):
    def __init__(self, argv):
        super(QSingleApplication, self).__init__(argv)
        self.setApplicationName("wizart_desktop")
        self.argv = argv
        self.m_socket = QtNetwork.QLocalSocket()
        self.m_socket.connectToServer(self.applicationName(), QtCore.QIODevice.WriteOnly)
        self.is_running = self.m_socket.waitForConnected()
        if self.is_running:
            self.connectToExistingApp()
            sys.exit(0)

    def connectToExistingApp(self):
        self.m_socket.write(";".join(self.argv) )

    def startApplication(self, main_window):
        self.main_window = main_window
        self.m_server = QtNetwork.QLocalServer()
        if self.m_server.listen(self.applicationName()):
            self.m_server.newConnection.connect(self.getNewConnection)
            self.main_window.handle_cmd_args(self.argv)
            self.main_window.show()

    def getNewConnection(self):
        self.new_socket = self.m_server.nextPendingConnection()
        self.new_socket.readyRead.connect(self.readSocket)

    def readSocket(self):
        f = self.new_socket.readLine()
        should_raise = self.main_window.handle_cmd_args(str(f).split(';'))
        if should_raise is True:
            if self.main_window.isHidden():
                self.main_window.show()
                self.main_window.raise_()
                self.main_window.showNormal()
                self.main_window.activateWindow()
            else:
                # shown and not topmost, just bring to the top
                self.main_window.showNormal()
                self.main_window.raise_()
                self.main_window.activateWindow()


def get_stylesheet_path():
    # if hasattr(sys, "frozen"):
    #     return os.path.join(os.path.dirname( os.path.abspath(sys.executable) ), "style.qss")
    # else:
    return os.path.join(os.path.dirname( os.path.abspath(__file__) ), "style.py")


def set_stylesheet(widget):
    import style
    reload(style)
    widget.setStyleSheet(style.qss)
    #file_path =  get_stylesheet_path()
    # with open(file_path, "r") as f:
    #     widget.setStyleSheet(f.read())


def init_style_sheet(widget):
    set_stylesheet(widget)
    if os.environ.get("QSS_STYLE_WATCH", 0 ) > 0:
        watcher = QtCore.QFileSystemWatcher(widget)
        file_path =  get_stylesheet_path()
        watcher.addPath(file_path)
        watcher.fileChanged.connect(lambda path: set_stylesheet(widget))


class StreamToLogger(object):
   """
   Fake file-like stream object that redirects writes to a logger instance.
   """
   def __init__(self, logger, log_level=logging.INFO):
      self.logger = logger
      self.log_level = log_level
      self.linebuf = ''

   def write(self, buf):
      for line in buf.rstrip().splitlines():
         self.logger.log(self.log_level, line.rstrip())

def filter_sentry_event(event, hint):
    """
    Filtering error events.

    If we don`t need to send an event to the sentry, then we return None.
    """
    exc_info = hint.get("exc_info")

    if exc_info:
        exc_type, exc_value, tb = exc_info
        from wizart.desktop.auth_session import WizartDesktopAuthError

        if isinstance(exc_value, WizartDesktopAuthError):
            return None
    return event

def setup_sentry(sentry_dsn):
    import sentry_sdk
    from sentry_sdk.integrations.logging import LoggingIntegration

    sentry_logging = LoggingIntegration(event_level=logging.ERROR)
    sentry_sdk.init(
        dsn=sentry_dsn,
        integrations=[sentry_logging],
        before_send=filter_sentry_event,
    )
    with sentry_sdk.configure_scope() as scope:
        scope.user = {"username": os.environ.get("USERNAME")}

def main(debug = False):
    from wizart.desktop import main_window
    log_path = os.path.expandvars("$USERPROFILE/wizart_desktop.log")

    formatter = logging.Formatter("%(asctime)s | %(levelname)s :  %(message)s", "%H:%M:%S")

    log = logging.getLogger("wizart_desktop")
    log.setLevel(logging.DEBUG)
    handler = logging.handlers.RotatingFileHandler(log_path, "a", maxBytes=5000000, backupCount=10)
    memory_handler = logging.handlers.MemoryHandler(5000)
    memory_handler.setFormatter(formatter)
    handler.setFormatter(formatter)
    log.addHandler(handler)
    log.addHandler(memory_handler)
    if debug:
        app = QtWidgets.QApplication(sys.argv)
    else:
        app = QSingleApplication(sys.argv)
        sys.stdout = StreamToLogger(log, logging.INFO)
        sys.stderr = StreamToLogger(log, logging.ERROR)
        if hasattr(sys, 'freelance_build'):
            setup_sentry(EXTERNAL_SENTRY_DSN)
        else:
            setup_sentry(INTERNAL_SENTRY_DSN)
    app.setApplicationName("wizart_desktop")
    app.setQuitOnLastWindowClosed(False)
    style = QtWidgets.QStyleFactory.create("fusion")
    app.setStyle(style)
    app.setWindowIcon(QtGui.QIcon(":systray_icon"))
    font_db = QtGui.QFontDatabase()
    font_db.addApplicationFont(font.get("fontawesome/fa-solid-900.ttf"))
    font_db.addApplicationFont(font.get("fontawesome/fa-regular-400.ttf"))
    init_style_sheet(app)

    widget = main_window.DesktopWindow()
    ui_handler = utils.OutputWidgetHandler(widget.log_view)
    ui_handler.setFormatter(formatter)
    log.addHandler(ui_handler)
    if not debug:
        app.startApplication(widget)
        app_id = 'wizart_desktop'
        ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(app_id)
    else:
        widget.show()
    memory_handler.setTarget(ui_handler)
    memory_handler.close()
    app.exec_()
