import sys
from typing import Optional

import wx
from wx.lib.agw.hyperlink import HyperLinkCtrl

from clarabot_nano.control.client import WxCoreInterface
from clarabot_nano.control.utility import Slots, change_font_to_bold, change_foreground_color_to_dimmed


class UpdateWidget(wx.Window):
    def __init__(self, parent, text):
        wx.Window.__init__(self, parent)

        upd_c = wx.Colour(243, 198, 15)

        self.SetBackgroundColour(upd_c)

        layout = wx.BoxSizer(wx.VERTICAL)
        self.SetSizer(layout)

        self._update_hyperlink = HyperLinkCtrl(
            self, wx.ID_ANY, text, style=wx.ALIGN_CENTER_VERTICAL, URL="https://www.clarabot.com/download"
        )
        self._update_hyperlink.SetToolTip("")
        upd_c_t_def = wx.Colour(0, 0, 0)
        upd_c_t_dis = upd_c_t_def.MakeDisabled(104)
        upd_c_t_def = wx.Colour(0, 0, 0)
        self._update_hyperlink.SetColours(upd_c_t_dis, upd_c_t_dis, upd_c_t_def)
        self._update_hyperlink.SetBackgroundColour(upd_c)
        self._update_hyperlink.DoPopup(False)  # menu is not localised, shall make a custom one if needed
        self._update_hyperlink.EnableRollover(True)
        self._update_hyperlink.UpdateLink()
        layout.AddStretchSpacer(1)
        layout.Add(self._update_hyperlink, 3, wx.EXPAND)
        layout.AddStretchSpacer(1)

    def update_text(self, text):
        self._update_hyperlink.SetLabelText(text)

    def get_update_text(self):
        return self._update_hyperlink.GetLabelText()


class ControlStatus(wx.Panel, Slots):

    """
    gateway not logged in -> login page
    after login start wizard for initial setup
    """

    def __init__(self, core_interface: WxCoreInterface, parent):
        wx.Panel.__init__(self, parent)
        Slots.__init__(self)
        # core_interface
        self._update_widget = None

        layout = wx.BoxSizer(wx.VERTICAL)
        if sys.platform.startswith("darwin"):
            layout.AddSpacer(18)  # Compensate for missing menubar on the window.
        self._title_label = wx.StaticText(self, wx.ID_ANY, gettext("Status summary"), style=wx.ALIGN_CENTER_HORIZONTAL)
        change_foreground_color_to_dimmed(self._title_label)
        change_font_to_bold(self._title_label)
        layout.Add(self._title_label, 0, wx.ALL | wx.EXPAND, 6)
        layout.Add(-1, 16, 0)

        _body_layout_border = 8
        _title_center_gap = 24
        _stats_center_gap = 8

        # gateway title/status
        gateway_state_layout = wx.BoxSizer(wx.HORIZONTAL)
        layout.Add(gateway_state_layout, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, _body_layout_border)
        gateway_status_title = wx.StaticText(self, wx.ID_ANY, gettext("Gateway"), style=wx.ALIGN_RIGHT)
        change_foreground_color_to_dimmed(gateway_status_title)  # dim the color
        change_font_to_bold(gateway_status_title, 1.2)
        gateway_state_layout.Add(gateway_status_title, 1, wx.EXPAND)
        gateway_state_layout.Add(_title_center_gap, -1, 0)
        self._gateway_status_label = wx.StaticText(self, wx.ID_ANY, style=wx.ALIGN_LEFT)
        change_font_to_bold(self._gateway_status_label, 1.2)
        gateway_state_layout.Add(self._gateway_status_label, 1, wx.EXPAND)

        layout.Add(-1, 6, 0)
        # gateway stats
        gateway_stats_layout = wx.BoxSizer(wx.HORIZONTAL)
        layout.Add(gateway_stats_layout, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, _body_layout_border)
        self._request_stats_label = wx.StaticText(self, wx.ID_ANY, style=wx.ALIGN_RIGHT)
        gateway_stats_layout.Add(self._request_stats_label, 1, wx.EXPAND)
        gateway_stats_layout.Add(_stats_center_gap, -1, 0)
        requests_label = wx.StaticText(self, wx.ID_ANY, gettext("requests/second"), style=wx.ALIGN_LEFT)
        change_foreground_color_to_dimmed(requests_label)  # dim the color
        gateway_stats_layout.Add(requests_label, 1, wx.EXPAND)

        layout.Add(-1, 20, 0)
        # indexer title/status
        indexer_state_layout = wx.BoxSizer(wx.HORIZONTAL)
        layout.Add(indexer_state_layout, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, _body_layout_border)
        indexer_status_title = wx.StaticText(self, wx.ID_ANY, gettext("Indexer"), style=wx.ALIGN_RIGHT)
        change_foreground_color_to_dimmed(indexer_status_title)  # dim the color
        change_font_to_bold(indexer_status_title, 1.2)
        indexer_state_layout.Add(indexer_status_title, 1, wx.EXPAND)
        indexer_state_layout.Add(_title_center_gap, -1, 0)
        self._indexer_status_label = wx.StaticText(self, wx.ID_ANY, style=wx.ALIGN_LEFT)
        change_font_to_bold(self._indexer_status_label, 1.2)
        indexer_state_layout.Add(self._indexer_status_label, 1, wx.EXPAND)

        layout.Add(-1, 6, 0)
        # indexer stats
        indexer_work_layout = wx.BoxSizer(wx.HORIZONTAL)
        layout.Add(indexer_work_layout, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, _body_layout_border)
        self._indexer_work_label = wx.StaticText(
            self, wx.ID_ANY, style=wx.ALIGN_CENTER_HORIZONTAL | wx.ST_NO_AUTORESIZE | wx.ST_ELLIPSIZE_END
        )
        indexer_work_layout.Add(self._indexer_work_label, 1, wx.EXPAND)

        layout.Add(-1, 12, 0)
        # open webapp link
        webapp_link_layout = wx.BoxSizer(wx.HORIZONTAL)
        layout.Add(webapp_link_layout, 0, wx.LEFT | wx.RIGHT | wx.EXPAND, _body_layout_border)
        self._open_webapp_hyperlink = HyperLinkCtrl(
            self,
            wx.ID_ANY,
            gettext("Open Web Application"),
            style=wx.ALIGN_CENTER_HORIZONTAL,
            URL="https://nano.clarabot.com/",
        )
        self._open_webapp_hyperlink.SetToolTip("")
        self._open_webapp_hyperlink.SetColours(
            requests_label.GetForegroundColour(),
            requests_label.GetForegroundColour(),
            self._request_stats_label.GetForegroundColour(),
        )
        self._open_webapp_hyperlink.DoPopup(False)  # menu is not localised, shall make a custom one if needed
        self._open_webapp_hyperlink.EnableRollover(True)
        self._open_webapp_hyperlink.UpdateLink()
        webapp_link_layout.AddStretchSpacer(1)
        webapp_link_layout.Add(self._open_webapp_hyperlink, 0, wx.EXPAND)
        webapp_link_layout.AddStretchSpacer(1)

        self.SetSizer(layout)

        self._indexer_idle_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self._on_indexer_idle_timeout, self._indexer_idle_timer)

        # bind for updates then init the ui
        self.bind_signal(core_interface.request_stat_signal, self._on_request_stat)
        self.bind_signal(core_interface.indexer_work_signal, self._on_indexer_work)
        self.bind_signal(core_interface.config_changed, self._on_config_changed)
        self._on_config_changed(core_interface.get_config())

    def _on_config_changed(self, config):
        self._update_gateway_status(config["state"].get("gateway_status"))
        self._update_indexer_status(config["state"].get("indexer_status"))
        self.Layout()

    def _update_gateway_status(self, gateway_status):
        if not gateway_status:
            gateway_status = "???"
            self._on_request_stat({"reqs": 0.0})
        elif gateway_status != "active":
            self._on_request_stat({"reqs": 0.0})
        if gateway_status == "active":
            self._gateway_status_label.SetLabelText(gettext("Active"))
            self._gateway_status_label.SetToolTip(gettext("Online, serving requests"))
        elif gateway_status == "connected":
            self._gateway_status_label.SetLabelText(gettext("Connected"))
            self._gateway_status_label.SetToolTip(gettext("Waiting for license"))
        elif gateway_status == "connecting":
            self._gateway_status_label.SetLabelText(gettext("Connecting"))
            self._gateway_status_label.SetToolTip(gettext("Logging in to the server"))
        elif gateway_status == "disconnected":
            self._gateway_status_label.SetLabelText(gettext("Disconnected"))
            self._gateway_status_label.SetToolTip(gettext("Login or network failure, reconnecting automatically"))
        else:
            self._gateway_status_label.SetLabelText(str(gateway_status))
            self._gateway_status_label.SetToolTip("")

    def _update_indexer_status(self, indexer_status):
        if not indexer_status:
            indexer_status = "starting"
        if indexer_status == "ready":
            self._indexer_status_label.SetLabelText(gettext("Ready"))
            self._indexer_status_label.SetToolTip(gettext("Observing drives for change events"))
        elif indexer_status == "scanning":
            self._indexer_status_label.SetLabelText(gettext("Scanning"))
            self._indexer_status_label.SetToolTip(gettext("Scanning drives for changes"))
        elif indexer_status == "starting":
            self._indexer_status_label.SetLabelText(gettext("Starting"))
            self._indexer_status_label.SetToolTip(gettext("Initialising config and databases"))
            self._indexer_work_label.SetLabelText("")  # clear for now
        else:
            self._indexer_status_label.SetLabelText(str(indexer_status))
            self._indexer_status_label.SetToolTip("")

    def _on_request_stat(self, req_stat):
        req_per_s = req_stat.get("reqs")
        if not req_per_s:
            req_per_s = 0.0
        self._request_stats_label.SetLabelText("%.01f" % (req_per_s,))
        self.Layout()

    def _on_indexer_work(self, idx_work):
        work = idx_work.get("work")
        if not work:
            self._indexer_work_label.SetLabelText(gettext("idle"))
            change_foreground_color_to_dimmed(self._indexer_work_label, self.GetForegroundColour())  # dim
        else:
            self._indexer_work_label.SetLabelText(str(work))
            self._indexer_work_label.SetForegroundColour(self.GetForegroundColour())
            self._indexer_idle_timer.StartOnce(5000)
        self.Layout()

    def _on_indexer_idle_timeout(self, *args):
        self._on_indexer_work({})

    def display_update_link(self, text: Optional[str]):
        if text:
            # NOTE: Update state shall never "go away" so we're not implementing that.
            if self._update_widget is None:
                self._update_widget = UpdateWidget(self, text)
                self.GetSizer().Insert(0, self._update_widget, 0, wx.EXPAND)
            else:
                self._update_widget.update_text(text)
