import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gio


BOOKS = [
    "Antony and Cleopatra",
    "Hamlet",
    "Julius Caesar",
    "King Lear",
    "Macbeth",
    "The Merchant of Venice",
    "A Midsummer Night's Dream",
    "Much Ado About Nothing",
    "Othello",
    "Romeo and Juliet",
    "The Tempest",
    "Titus Andronicus",
]

MENU_XML = """
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <menu id="app-menu">
    <item>
      <attribute name="action">app.quit</attribute>
      <attribute name="label" translatable="yes">_Quit</attribute>
      <attribute name="accel">&lt;Primary&gt;q</attribute>
    </item>
  </menu>
</interface>
"""


class App(Gtk.Application):
    def do_activate(self):
        window = AppWindow(app=self)
        window.show_all()

    def do_startup(self):
        Gtk.Application.do_startup(self)

        builder = Gtk.Builder.new_from_string(MENU_XML, length=-1)
        self.set_app_menu(builder.get_object("app-menu"))

        quit = Gio.SimpleAction.new("quit", None)
        self.add_action(quit)
        quit.connect("activate", self.on_quit)

    def on_quit(self, _action, _param):
        self.quit()


class AppWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        super().__init__(
            application=app,
            title="Main Window",
            default_height=480,
            default_width=480,
        )

        self.query: list[str] = []
        self.data = init_model()
        self.data.set_visible_func(self.is_match)

        search_label = Gtk.Label(label="Filter titles in library")
        search = Gtk.SearchEntry()
        search.connect("search-changed", self.on_search_changed)

        results_label = Gtk.Label(label="Press down to select next result")
        results = Gtk.ScrolledWindow()
        results.set_vexpand(True)
        results.add(new_view(self.data))

        self.count = Gtk.Label()
        self.update_count()

        vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
        vbox.add(search_label)
        vbox.add(search)
        vbox.add(results_label)
        vbox.add(results)
        vbox.add(self.count)
        self.add(vbox)

    def is_match(self, model, iterator, _data):
        title = model[iterator][1].lower()
        return all(word in title for word in self.query)

    def on_search_changed(self, entry, *args):
        self.query = entry.get_text().split()
        self.data.refilter()
        self.update_count()

    def update_count(self):
        self.count.set_text("{n} matches".format(n=len(self.data)))


def init_model() -> Gtk.TreeModel:
    data = Gtk.ListStore(int, str)
    for i, title in enumerate(BOOKS):
        data.append((i, title))
    return data.filter_new()


def new_view(data: Gtk.TreeModel) -> Gtk.TreeView:
    view = Gtk.TreeView(model=data)
    column = Gtk.TreeViewColumn("#", Gtk.CellRendererText(), text=0)
    view.append_column(column)
    column = Gtk.TreeViewColumn("Title", Gtk.CellRendererText(), text=1)
    view.append_column(column)
    return view


if __name__ == "__main__":
    import sys
    app = App(application_id="com.example.MyApp")
    exit_code = app.run(sys.argv)
    sys.exit(exit_code)
