# Copyright (c) 2020-2022 Jan-Michael Brummer <jan.brummer@tabos.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from gi.repository import Adw, Gtk, GLib, GObject
from saldo.widgets.listviewstore import ListViewListStore

from saldo.backend.backend import BankingBackend


class BankElem(GObject.GObject):
    def __init__(
        self, name: str, blz: str, bic: str, logo: str, city: str, server: str
    ):
        super(BankElem, self).__init__()
        self.name = name
        self.blz = blz
        self.bic = bic
        self.city = city

        self.logo = logo
        self.server = server

    def __repr__(self):
        return f"BankElem(name: {self.name} blz: {self.blz})"


class BankFilter(Gtk.Filter):
    __gtype_name__ = "BankFilter"

    def __init__(self, search: str):
        self.search = search.lower()
        super(BankFilter, self).__init__()

    def do_match(self, item: Gtk.Widget) -> bool:
        return (
            self.search in item.name.lower()
            or self.search in item.city.lower()
            or item.blz.lower().startswith(self.search)
            or item.bic.lower().startswith(self.search)
        )


class BankListView(ListViewListStore):
    def __init__(self, win: Gtk.ApplicationWindow, backend: BankingBackend):
        super(BankListView, self).__init__(BankElem)
        self.win = win

        for db in backend._client_db["databases"]:
            blz = str(db["blz"])
            bic = str(db["bic"])
            name = GLib.markup_escape_text(str(db["institute"]))
            logo = str(db["logo"])
            city = str(db["city"])
            server = str(db["url"])

            self.add(BankElem(name, blz, bic, logo, city, server))

    def factory_setup(self, widget: Gtk.ListView, item: Gtk.ListItem) -> None:
        row = Adw.ActionRow()
        row.add_suffix(Gtk.Image.new_from_icon_name("go-next-symbolic"))
        row.set_activatable(True)
        item.set_child(row)

    def factory_bind(self, widget: Gtk.ListView, item: Gtk.ListItem) -> None:
        row = item.get_child()
        data = item.get_item()

        if data.city.lower() in data.name.lower():
            row.set_title(data.name)
        else:
            row.set_title(data.name + " (" + data.city + ")")
        row.set_subtitle(data.blz)
        row.set_title_lines(1)
        row.set_subtitle_lines(1)
        row.set_icon_name(data.logo)

    def factory_unbind(self, widget: Gtk.ListView, item: Gtk.ListItem) -> None:
        pass

    def factory_teardown(self, widget: Gtk.ListView, item: Gtk.ListItem) -> None:
        pass

    def selection_changed(self, widget: Gtk.ListView, ndx: int) -> None:
        pass


@Gtk.Template(resource_path="/org/tabos/saldo/ui/clients.ui")
class Clients(Adw.Dialog):
    __gtype_name__ = "Clients"

    navigation_view = Gtk.Template.Child()
    _credentials_page = Gtk.Template.Child()
    _create_button = Gtk.Template.Child()
    _user_entry = Gtk.Template.Child()
    _password_entry = Gtk.Template.Child()
    _bank_search_entry = Gtk.Template.Child()
    _bank_scrolled_window = Gtk.Template.Child()

    def __init__(self, backend: BankingBackend) -> None:
        super().__init__()

        self._backend = backend
        self._institute = None

        self.view = BankListView(self, self._backend)
        self.view.set_single_click_activate(True)
        self.view.add_css_class("card")
        self.view.connect("activate", self.on_view_activated)
        self._bank_scrolled_window.set_child(self.view)
        self.info = None

        self._bank_search_entry.connect("activate", self._on_next_clicked)
        self._create_button.connect("activated", self._on_create_clicked)
        self._user_entry.connect("entry-activated", self._on_create_clicked)
        self._password_entry.connect("entry-activated", self._on_create_clicked)

    def do_realize(self):
        Gtk.Widget.do_realize(self)
        self._bank_search_entry.grab_focus()

    def on_view_activated(self, view: BankListView, pos: int) -> None:
        idx = self.view.model.get_selection().get_nth(0)
        self.info = self.view.model.get_item(idx)

        if self.info:
            self._credentials_page.set_title(self.info.name)

        self.navigation_view.push_by_tag("credentials")

    @Gtk.Template.Callback()
    def _on_bank_search_changed(self, _: Gtk.Widget) -> None:
        bank = self._bank_search_entry.get_text()

        if len(bank) > 2:
            self.view.filtered.set_filter(BankFilter(bank))
        else:
            self.view.filtered.set_filter(None)

    @Gtk.Template.Callback()
    def _on_bank_credentials_changed(self, edit: Gtk.Widget) -> None:
        if len(self._user_entry.get_text()) and len(self._password_entry.get_text()):
            self._create_button.set_sensitive(True)
        else:
            self._create_button.set_sensitive(False)

    def _on_next_clicked(self, _button: Gtk.Widget) -> None:
        idx = self.view.model.get_selection().get_nth(0)
        self.info = self.view.model.get_item(idx)

        if self.info:
            self._credentials_page.set_title(self.info.name)

        self.navigation_view.push_by_tag("credentials")

    def _on_create_clicked(self, _button: Gtk.Widget) -> None:
        if self.info:
            self._backend.add_client(
                self._user_entry.get_text(),
                self._password_entry.get_text(),
                self.info.server,
                self.info.blz,
            )

        self._backend.refresh_accounts()

        self.close()
