import stillCenter.constants as constants
import sadb.database
import threading
import os
import gi
from sam.quick import get_queue_dicts

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

# Import templates for xml builder
import stillCenter.AppStore as AppStore
import stillCenter.AppPage as AppPage
import stillCenter.FlowApps as FlowApps
import stillCenter.AppGridView as AppGridView  # Needed for builder
import stillCenter.AppListView as AppListView  # Needed for builder
import stillCenter.CategoryPage as CategoryPage

from stillCenter.CategoryButtonBig import CategoryButtonBig
from stillCenter.SamInterface import sam_interface, get_sam_error
from stillCenter.LoadingPage import LoadingPage
from stillCenter.ErrorPage import ErrorPage


class StillCenter(Adw.Application):
    def __init__(self):
        super().__init__(application_id="io.stillhq.stillCenter")

        self.builder = Gtk.Builder()
        self.builder.add_from_file(os.path.join(constants.UI_DIR, "stillCenter.ui"))

        # Get objects from the builder
        self.window = self.builder.get_object("window")
        self.sidebar = self.builder.get_object("main_sidebar")
        self.sidebar_split = self.builder.get_object("sidebar_split_view")
        self.main_stack = self.builder.get_object("main_stack")
        self.main_view = self.builder.get_object("main_view")
        self.categories_flowbox = self.builder.get_object("categories_flowbox")
        self.search_stack = self.builder.get_object("search_stack")
        self.search_app_list = self.builder.get_object("search_app_list")
        self.search_entry = self.builder.get_object("search_entry")
        self.search_placeholder = self.builder.get_object("search_placeholder")
        self.update_box = self.builder.get_object("update_box")
        self.update_all_button = self.builder.get_object("update_all_button")
        self.available_updates = self.builder.get_object("available_updates")
        self._search_timeout_id = None

        # Set Window Name
        self.window.set_title("stillCenter")

        # Setting up the sidebar
        self.sidebar_index = []
        main_stack_pages = self.main_stack.get_pages()
        for i in range(main_stack_pages.get_n_items()):
            stack_page = main_stack_pages.get_item(i)
            sidebar_row = Gtk.ListBoxRow()
            label = Gtk.Label(label=stack_page.get_title(), xalign=0)
            sidebar_row.set_child(label)
            self.sidebar_index.append(stack_page.get_name())
            self.sidebar.append(sidebar_row)
        self.sidebar.connect("row-selected", self.sidebar_selected)

        # Set IDs of Flowboxes for Featured Apps
        FlowApps.set_stillcenter(self)

        # Populating Categories
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Audio", "Audio", "audio-x-generic-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Development", "Development", "applications-engineering-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Education", "Education", "accessories-dictionary-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Game", "Games", "applications-games-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Graphics", "Graphics", "applications-graphics-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Network", "Network", "preferences-system-network-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Office", "Office", "x-office-document-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Utility", "Utilities", "applications-utilities-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "Video", "Video", "applications-multimedia-symbolic")
        )
        self.categories_flowbox.append(
            CategoryButtonBig(self, "System", "System", "preferences-other-symbolic")
        )

        # Check for SAM error and push error screen
        sam_error, sam_error_msg = get_sam_error()
        if sam_error:
            errorpage = ErrorPage(
                self, "still App Manager Error", sam_error_msg + \
                "\n\nCheck if the SAM systemd service is running,"
                " or check the systemd status of SAM for possible errors."
            )
            errorpage.push()
            return

        # Setup search
        self.search_entry.connect("changed", self.search_changed)

        # Loading base pages
        self.app_page = AppPage.AppPage(self)
        self.category_page = CategoryPage.CategoryPage(self)

        # Set update button
        sam_interface.connect_to_signal("queue_changed", self.run_update_installed_page)
        self.update_all_button.connect("clicked", self.update_all)

        # Loading screen
        self.loading_screen = LoadingPage(self)

        self.loading_screen.push()
        thread = threading.Thread(target=self.load_apps)
        thread.start()

    def update_all(self, button):
        thread = threading.Thread(target=lambda: sam_interface.update_all(False))
        thread.start()

    def run_update_installed_page(self):
        thread = threading.Thread(target=self.update_installed_page)
        thread.start()

    # Update installed page
    def update_installed_page(self):
        sadb.database.update_installed()

        AppStore.refresh_installed_store()

        GLib.idle_add(self.update_installed_gui)

    def update_installed_gui(self):
        # Set models of ListViews
        self.builder.get_object("installed").set_store(self, AppStore.INSTALLED_STORE["no_update"])
        self.builder.get_object("available_updates").set_store(self, AppStore.INSTALLED_STORE["update"])

        if AppStore.INSTALLED_STORE["update"].get_n_items() == 0:
            self.available_updates.set_visible(False)
            self.update_box.set_visible(False)
        else:
            self.available_updates.set_visible(True)
            self.update_box.set_visible(True)

        queue = get_queue_dicts()
        if not queue:
            queue = []  # Prevent function from breaking if queue is empty
        if len(queue) != 0:
            self.update_all_button.set_sensitive(False)
        else:
            self.update_all_button.set_sensitive(True)

    def load_apps(self):
        sadb.database.update_db()

        self.update_installed_page()

        GLib.idle_add(lambda: self.populate_apps())
        GLib.idle_add(self.loading_screen.pop)

    def populate_apps(self):
        self.search_placeholder.set_title(f"Search from {len(AppStore.STORE["all"])} Apps")
        FlowApps.populate_apps()

    def sidebar_selected(self, _listbox, row):
        self.main_stack.set_visible_child_name(self.sidebar_index[row.get_index()])
        if self.sidebar_split.get_collapsed() and not self.sidebar_split.get_show_content():
            self.sidebar_split.set_show_content(True)

    def search_changed(self, entry):
        # Cancel any pending search
        if self._search_timeout_id:
            GLib.source_remove(self._search_timeout_id)
        
        # Wait 250ms before searching to wait for user to stop typing
        # Removed immediate search call to prevent duplicate searches
        self._search_timeout_id = GLib.timeout_add(250, self.do_search, entry.get_text())
        print(self._search_timeout_id)


    def do_search(self, query: str):
        query = query.strip()
        if len(query) >= 2:  # Require at least 2 characters for search
            store = AppStore.search_algorithm(query)

            if len(store) == 0:
                self.search_stack.set_visible_child_name("no_results")
                return

            self.search_app_list.set_store(self, store)
            self.search_stack.set_visible_child_name("results")
        else:
            self.search_stack.set_visible_child_name("search_placeholder")

    def do_activate(self):
        self.window.set_application(self)
        self.window.present()
