import os

import gi

import stillCenter.AppGridView as AppGridView
import stillCenter.AppStore as AppStore
import stillCenter.AppListView as AppListView
import stillCenter.constants as constants

gi.require_version("Gtk", "4.0")
gi.require_version("Adw", "1")
from gi.repository import Gtk, Adw, GLib, Gio


category_pages = []


@Gtk.Template(filename=os.path.join(constants.UI_DIR, "CategoryPage.ui"))
class CategoryPage(Adw.NavigationPage):
    __gtype_name__ = "CategoryPage"

    category_title: Gtk.Label = Gtk.Template.Child()
    subcategory_button_box: Gtk.Box = Gtk.Template.Child()
    app_grid: AppGridView.AppGridView = Gtk.Template.Child()
    scroll_window: Gtk.ScrolledWindow = Gtk.Template.Child()
    loading_box: Gtk.Box = Gtk.Template.Child()
    loading_spinner: Gtk.Spinner = Gtk.Template.Child()

    main_category_page = True
    stillCenter = None
    _scroll_handler_id = None
    _loading = False

    def __init__(self, stillCenter):
        super().__init__()
        self.stillCenter = stillCenter
        category_pages.append(self)

    def _clear_subcategory_buttons(self):
        child = self.subcategory_button_box.get_first_child()
        while child is not None:
            self.subcategory_button_box.remove(child)
            child = self.subcategory_button_box.get_first_child()

    def _configure_subcategories(self, category):
        self._clear_subcategory_buttons()

        if not self.main_category_page or category not in constants.SUBCATEGORIES:
            self.subcategory_button_box.set_visible(False)
            return

        self.subcategory_button_box.set_visible(True)
        for subcategory in constants.SUBCATEGORIES[category]:
            if subcategory[0] in AppStore.STORE.keys():
                button = Gtk.Button(label=subcategory[1])
                button.connect("clicked", self.on_subcategory_clicked, subcategory[0], subcategory[1])
                self.subcategory_button_box.append(button)

    def push_store(self, title, model, category=None):
        self.category_title.set_label(title)
        self.set_title(title)

        # Reset state for new category
        self._loading = False
        self.loading_box.set_visible(False)
        self.loading_spinner.set_spinning(False)

        # Scroll back to the top
        self.scroll_window.get_vadjustment().set_value(0)

        self.app_grid.set_store(self.stillCenter, model)

        # Connect scroll handler once per page instance
        if self._scroll_handler_id is None:
            vadj = self.scroll_window.get_vadjustment()
            self._scroll_handler_id = vadj.connect("value-changed", self._on_scroll)

        self._configure_subcategories(category)

        main_view = self.stillCenter.builder.get_object("main_view")
        main_view.push(self)

    def push_category(self, category, title):
        self.push_store(title, AppStore.STORE[category], category)

    def _on_scroll(self, adj):
        if self._loading or not self.app_grid.has_more:
            return

        # Load only when the user reaches the true bottom.
        at_bottom = adj.get_value() + adj.get_page_size() >= adj.get_upper() - 1
        if at_bottom:
            self._loading = True
            self.loading_box.set_visible(True)
            self.loading_spinner.set_spinning(True)
            # Defer to next idle so the spinner appears before we start building widgets
            GLib.idle_add(self._do_load_more)

    def _do_load_more(self):
        self.app_grid.load_more()
        self._loading = False
        # Keep the loading indicator only while work is in progress.
        self.loading_box.set_visible(False)
        self.loading_spinner.set_spinning(False)
        return GLib.SOURCE_REMOVE

    def on_subcategory_clicked(self, button, subcategory, title):
        CategoryPage.push_subcategory(self.stillCenter, subcategory, title)

    @classmethod
    def push_subcategory(cls, stillCenter, category, title):
        page = cls(stillCenter)
        page.main_category_page = False
        page.push_store(title, AppStore.STORE[category])
        return page

    @classmethod
    def push_apps(cls, stillCenter, title, items, on_page_hidden=None):
        page = cls(stillCenter)
        page.main_category_page = False

        store = Gio.ListStore()
        for item in items:
            if item is not None:
                store.append(item)

        if on_page_hidden is not None:
            page.connect_after("unmap", lambda _w: on_page_hidden())

        page.push_store(title, store)
        return page
