import logging
import os
from contextlib import contextmanager

import wx
from clarabot_nano_common.ui.app import AbstractWxApplication

from clarabot_nano.control.client import WxCoreInterface, WxCoreBuffer
from clarabot_nano.control.window import ControlWindow

NANO_INFO_LOGGER = logging.getLogger("nano/info")


class ControlApplication(AbstractWxApplication):
    """
    This object form a small framework for the setup of the control application. It's primary reason for
    existing is to provide a customization interface for testing.
    """

    @classmethod
    @contextmanager
    def core_buffer(cls):
        """
        The core interface is special because it has to be created and started before most of the application.
        At shutdown it is also the last object that is alive.
        """
        core_buffer = WxCoreBuffer()
        NANO_INFO_LOGGER.info("Joined Core Instance, starting... (parent: %s)", os.getppid())
        try:
            yield core_buffer
        finally:
            core_buffer.close()

    def _create_window(self, *args, **kwargs) -> ControlWindow:
        return ControlWindow(self._core_interface, *args, **kwargs)

    def __init__(self, core_buffer: WxCoreBuffer):
        AbstractWxApplication.__init__(self, "clarabot-nano", "Clarabot Nano")
        self.__core_buffer = core_buffer
        self._core_interface = None

    def _before_session_end_exit(self):
        # NOTE: The core may have been notified about the shutdown by the OS as well.
        core_interface = self._core_interface
        if core_interface:
            try:
                core_interface.request_shutdown(explicit_user_request=False)
            except Exception:
                pass  # Assuming that the core is shutting down as well.
        # Weill exit even if the core has not requested that yet.

    def OnRun(self):
        self._core_interface = WxCoreInterface(self.__core_buffer)
        try:
            with self._setup() as w:
                self.SetTopWindow(w)
                # Run application/main event loop.
                return wx.App.OnRun(self)
        finally:
            self._core_interface.close()
            self._core_interface = None
