from time import time
from gi.repository import Gio
from gi.repository import GObject
from gi.repository import Gtk
from gi.repository import Adw
from gi.repository import Notify

from . import local
from . import models
from .settings import Settings
from .openwindow import OpenWindow
from .config import APP_NAME, APP_ID, APP_VERSION
from .networkconnectionmonitor import NetworkConnectionMonitor
from .widgets import LoaderPage
from .widgets import SideBar
from .widgets import PageHeaderBar
from .pages import PageInfo
from .pages import PageList
from .pages import PageDetails
from .utils import clean_markup

@Gtk.Template(resource_path="/net/kirgroup/confy/mainwindow.ui")
class MainWindow(Adw.ApplicationWindow):
    __gtype_name__ = "ConfyMainWindow"

    @GObject.Signal
    def conf_updated(self):
        pass

    overlay = Gtk.Template.Child()
    loader_stack = Gtk.Template.Child()
    loader = Gtk.Template.Child()
    leaflet = Gtk.Template.Child()
    subpage_leaflet = Gtk.Template.Child()
    sidebar_box = Gtk.Template.Child()
    sidebar = Gtk.Template.Child()
    main_box = Gtk.Template.Child()
    pageheaderbar = Gtk.Template.Child()
    main_stack = Gtk.Template.Child()

    subpage_events = Gtk.Template.Child()
    subpage_search_all = Gtk.Template.Child()
    subpage_details = Gtk.Template.Child()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        size = Settings.instance().get_size()
        self.set_default_size(*size)

        self._add_action("show-subpage-events",None, lambda *_: self.show_subpage_events())
        self._add_action("show-subpage-details",None, lambda *_: self.show_subpage_details())
        self._add_action("subpage-back",None, lambda *_: self.subpage_navigate_back())

        self._add_action("show-sidebar", None, lambda *_: self.show_sidebar())
        self._add_action("show-page", None, lambda *_: self.show_stack())
        self._add_action("open-conference", None, self.open_conference)
        self._add_action("search", None, lambda *_: self.show_search_all())

        self._add_action("copy", None, lambda *_: self.copy_details_to_clipboard())

        self.nm = NetworkConnectionMonitor()
        self.nm.connect("notify",self._on_networkconnectionmonitor_notify)

    def load_conf(self, conf):
        self.conf = conf

        self.show_main()
        self.show_stack()
        self.main_stack.set_visible_child_name('info')

        self._init_pages()
        self.subpage_leaflet.get_page(self.subpage_search_all).set_navigatable(False)
        self.set_pageheader_title()
        self.show_loader()

        self.connect('conf-updated', self._on_conf_updated)
        try:
            fetcher = local.openconf(conf, is_online=self.nm.props.isconnected)
        except Exception as e:
            self.show_error(e)
            return
        else:
            if fetcher is not None:
                fetcher.connect("done", self._on_fetcher_done)
                fetcher.connect("error", self._on_fetcher_error)
                self.loader.set_fetcher(fetcher)
            else:
                self.emit("conf-updated")
                self.show_main()

        self.notifications = {}
        # Check if there are notifications to send
        Gio.Application.get_default().connect(
            'tick', self.check_event_notification
        )
        self.check_event_notification()

    def _init_pages(self):
        for p in self.main_stack.get_pages():
            child = p.get_child()
            if hasattr(child, "init"):
                child.init(self, self.conf)

        self.connect("conf-updated", self.subpage_events.update)

    def _on_conf_updated(self, *_):
        # hide empty pages
        for p in self.main_stack.get_pages():
            child = p.get_child()
            if p.get_name() in ('days', 'tracks', 'rooms',):
                p.set_visible(len(list(child.get_objects())) > 0)

    def _add_action(self, name, parameter_type, activate_cbk):
        action = Gio.SimpleAction.new(name, parameter_type)
        action.connect("activate", activate_cbk)
        self.add_action(action)
        return action

    def _on_networkconnectionmonitor_notify(self, *_):
        ...

    def _on_fetcher_done(self, *_):
        self.emit("conf_updated")
        self.show_main()

    def _on_fetcher_error(self, fetcher, error):
        self.show_error(error)

    def check_event_notification(self, *args):
        nextup = list(models.Event.nextup(5))
        for e in nextup:
            # fast and stupid clean html
            #cleanr = re.compile('<.*?>|&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-f]{1,6});')
            #title = re.sub(cleanr, '', e.title)
            title = clean_markup(e.title)
            self._send_desktop_notification(
                _("Next up: {}").format(title),
                _("at {} in {}").format(
                    e.start_in_tz().strftime("%H:%M"),
                    e.room
                ),
                f"nextup-{e.id}")
            e.set_notified(True)

    def _send_desktop_notification(self, title, body, nid=None):
        n = Notify.Notification.new(title, body, APP_ID)
        n.set_timeout(Notify.EXPIRES_NEVER)
        n.add_action("view", "View", self.on_notification_action, nid)
        n.show()
        self.notifications[nid] = n

    def on_notification_action(self, notification, action, data):
        print(notification, action, data)
        if action == "view" and data.startswith("nextup-"):
            self.present_with_time(time())
            eventid = int(data.split("-")[1])
            event = models.Event.by_id(eventid)
            # if we are not on "events" subpage, force it as non navigatable,
            # we want to be back to where we were
            print(self.subpage_leaflet.get_visible_child(), self.subpage_events)
            can_we_go_back_to_events = self.subpage_leaflet.get_visible_child() == self.subpage_events
            self.show_details(event, can_we_go_back_to_events)


    def show_start(self):
        self.loader_stack.set_visible_child_name("start")

    def show_loader(self):
        self.loader_stack.set_visible_child_name("loader")

    def open_conference(self, *_):
        app = self.get_application()
        win = OpenWindow(modal=True, transient_for=self, application=app)
        win.show()

    def show_error(self, error = None):
        msg = Adw.MessageDialog(
            transient_for = self,
            modal = True,
            heading = _("Error loading event"),
            body = str(error) if error else "",
        )
        msg.add_response("ok", _("Ok"))
        msg.connect("response", self.open_conference)
        msg.present()

    def show_main(self):
        self.loader_stack.set_visible_child_name("main")

    @Gtk.Template.Callback()
    def _on_page_changed(self, *_):
        self.set_pageheader_title()
        self.show_stack()

    def set_pageheader_title(self):
        title = self.main_stack.get_page(self.main_stack.get_visible_child()).get_title()
        self.pageheaderbar.props.title = title

    def show_main_leaflet(self):
        self.subpage_leaflet.set_visible_child(self.leaflet)

    def show_stack(self):
        self.leaflet.set_visible_child(self.main_box)

    def show_sidebar(self):
        self.leaflet.set_visible_child(self.sidebar_box)

    def show_subpage_events(self):
        self.subpage_leaflet.set_visible_child(self.subpage_events)

    def show_subpage_details(self):
        self.subpage_leaflet.set_visible_child(self.subpage_details)

    def subpage_navigate_back(self):
        self.subpage_leaflet.navigate(Adw.NavigationDirection.BACK)

    def show_search_all(self):
        self.subpage_leaflet.get_page(self.subpage_events).set_navigatable(False)
        self.subpage_search_all.set_value(None)
        self.subpage_leaflet.set_visible_child(self.subpage_search_all)

    def show_details(self, event, is_events_navigatable=None):
        # Se sono sulla pagina "starred"
        # imposto "subpage_events" come non "navigatable"
        # così quando l'utente sceglie un evento preferito, viene mandato a
        # "subpage_details", e quando naviga indietro torna a "leaflet".
        #
        # A meno che non ci sia impostato 'is_events_navigatable' come paramentro,
        # nel qual caso, vince lui.
        from_starred =  self.main_stack.get_visible_child_name() == "starred"
        from_search_all = self.subpage_leaflet.get_visible_child() == self.subpage_search_all
        if is_events_navigatable is None:
            is_events_navigatable = not (from_starred or from_search_all)
        self.subpage_leaflet.get_page(self.subpage_events).set_navigatable(is_events_navigatable)

        is_search_all_navigatable = from_search_all
        self.subpage_leaflet.get_page(self.subpage_search_all).set_navigatable(is_search_all_navigatable)

        print("subpage event is navigatable", self.subpage_leaflet.get_page(self.subpage_events).get_navigatable())
        print("subpage search all is navigatable", self.subpage_leaflet.get_page(self.subpage_search_all).get_navigatable())

        self.subpage_details.set_obj(event)
        self.show_subpage_details()

    def copy_details_to_clipboard(self):
        if self.subpage_leaflet.get_visible_child() == self.subpage_details:
            self.subpage_details.copy_to_clipboard()
            self.notification_show(_("Event details copied to the clipboard"))

    @Gtk.Template.Callback()
    def _on_pagelist_row_activated(self, page):
        self.subpage_events.set_model(page.get_model())
        self.subpage_events.set_value(page.get_value())
        self.show_subpage_events()

    @Gtk.Template.Callback()
    def _on_event_row_activated(self, page):
        self.show_details(page.get_value())

    @Gtk.Template.Callback()
    def _on_close_requested(self, *_):
        size = self.get_default_size()
        Settings.instance().set_size(size)

    def notification_show(self, text):
        t = Adw.Toast()
        t.set_title(text)
        self.overlay.add_toast(t)

