#!/usr/bin/python3

# sudo apt install libgirepository-2.0-dev
from typing import Callable
import gi
import os
import sys
import gettext

gi.require_version("Gtk", "4.0")
# so Gtk for graphics
# Gio for data files
# GLib.Error (FileDialog?)
from gi.repository import Gtk, Gio

# libAdapta uses its own module name (Adap.ApplicationWindow etc..).
# We would normally import it like this:
# from gi.repository import Adap
# Since libAdapta and libAdwaita use the same class names,
# the same code can work with both libraries, as long as we rename
# the module when importing it
try:
    gi.require_version("Adap", "1")
    from gi.repository import Adap as Adw
except ImportError or ValueError as ex:
    # To use libAdwaita, we would import this instead:
    print("Using Adwaita as Adapta not found:\n", ex)
    gi.require_version("Adw", "1")
    from gi.repository import Adw

# locale handling
path = os.path.dirname(__file__)
domain = open(path + "/domain.txt").read().strip()
# ah the package name
xapp_adapta = __name__.split(".")[0]
gettext.bindtextdomain(domain + xapp_adapta)
gettext.textdomain(domain + xapp_adapta)
_ = gettext.gettext
icon = domain + "." + ".".join(os.path.basename(__file__).split(".")[:-1])


class MainWindow(Adw.ApplicationWindow):  # pyright: ignore
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Create a split view
        self.split_view = Adw.NavigationSplitView()

        # set layout variables
        self.names = []
        self.layout()
        self.page_map = {}  # autogenerated by side()
        self.listbox = Gtk.ListBox()

        # set for overrides in complex examples
        self.split_view.set_sidebar(self.side(**self.buttons))  # pyright: ignore
        self.select_new()
        self.set_content(self.split_view)

    # override for different behaviour
    def layout(self):
        self.set_title(__name__)
        self.set_default_size(800, 600)
        self.split_view.set_min_sidebar_width(200)
        self.split_view.set_max_sidebar_width(300)
        # multipaned content by selection widget
        # set list name [] and button nav {}
        self.pages = [self.content()]
        self.buttons = {}

    def select_new(self):
        self.split_view.set_content(
            self.page_map.get(self.listbox.get_selected_row(), self.pages[0])
        )  # pyright: ignore

    # general packing margins
    def fancy(self) -> Gtk.Box:
        box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        box.set_margin_top(10)
        box.set_margin_bottom(10)
        box.set_margin_start(10)
        box.set_margin_end(10)
        box.set_spacing(10)
        return box

    # make top navbar in navigation pages
    # allows optional named (left/right) array of buttons
    def top(self, content: Gtk.Box, title: str, **buttons) -> Adw.NavigationPage:
        # make a page
        toolbar = Adw.ToolbarView()
        header = Adw.HeaderBar()
        footer_on = False
        footer = Adw.HeaderBar()
        # left and right arrays of buttons
        for key, value in buttons.items():
            for b in value:
                match key:
                    case "left":
                        header.pack_start(b)
                    case "right":
                        header.pack_end(b)
                    case "bottom":
                        # I like the alignment
                        footer_on = True
                        footer.pack_end(b)
                    case _:
                        pass
        # can't alter buttons later
        # buttons can have callbacks connected at creation
        toolbar.add_top_bar(header)
        if footer_on:
            toolbar.add_bottom_bar(footer)
        toolbar.set_content(content)
        self.names.append(title)
        page = Adw.NavigationPage(title=title)
        page.set_child(toolbar)
        return page

    # the side navigation generator
    def side(self, **buttons) -> Adw.NavigationPage:
        # Create a sidebar
        sidebar_box = self.fancy()
        self.listbox.add_css_class("navigation-sidebar")
        self.listbox.set_selection_mode(Gtk.SelectionMode.SINGLE)
        for idx, named in enumerate(self.names):
            params = {}
            subs = buttons.get("subs", None)
            if subs:
                params["subtitle"] = str(subs[idx])
            icons = buttons.get("icons", None)
            if icons:
                params["icon_name"] = str(icons[idx])
            row = Adw.ActionRow(title=named, **params)
            self.listbox.append(row)
            self.page_map.update({row: self.pages[idx]})
            row.connect("activated", self.select_new)
        sidebar_box.append(self.listbox)
        return self.top(sidebar_box, _("Navigation"), **buttons)

    def burger(self):
        menu = Gio.Menu.new()
        # Create a popover
        popover = Gtk.PopoverMenu()  # Create a new popover menu
        popover.set_menu_model(menu)
        # Create a menu button
        hamburger = Gtk.MenuButton()
        hamburger.set_popover(popover)
        hamburger.set_icon_name("open-menu-symbolic")
        return hamburger

    # text might have to be translated. adds menu to burger
    def add_menu(self, index: str, callback: Callable, text: str):
        action = Gio.SimpleAction.new(index, None)
        action.connect("activate", callback)
        self.add_action(action)
        # Create a new menu, containing that action
        self.menu.append(text, "win." + index)

    # methods to define navigation pages
    def content(self) -> Adw.NavigationPage:
        # Create the content page _() for i18n
        content_box = self.fancy()
        status_page = Adw.StatusPage()
        status_page.set_title("Python libAdapta Example")
        status_page.set_description(
            "Split navigation view, symbolic icon and a calendar widget to feature the accent color."
        )
        status_page.set_icon_name("document-open-recent-symbolic")
        calendar = Gtk.Calendar()
        content_box.append(status_page)
        content_box.append(calendar)
        # set title and bar
        return self.top(content_box, _("Content"))


class MyApp(Adw.Application):  # pyright: ignore
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect("activate", self.on_activate)

    def on_activate(self, app):
        self.win = MainWindow(application=app)
        self.win.present()


def main():
    app = MyApp(application_id=icon)
    app.run(sys.argv)


if __name__ == "__main__":
    main()
