# SPDX-License-Identifier: GPL-3.0-only
""" GUI Page and function in order to create a new Safe"""
from __future__ import annotations

import logging
from gettext import gettext as _

from gi.repository import Adw, Gio, GLib, Gtk

from gsecrets.utils import (
    KeyFileFilter,
    generate_keyfile_async,
    generate_keyfile_finish,
)


@Gtk.Template(resource_path="/org/gnome/World/Secrets/gtk/create_database.ui")
class CreateDatabase(Adw.Bin):
    """Creates a new Safe when invoked"""

    __gtype_name__ = "CreateDatabase"

    stack = Gtk.Template.Child()

    password_action_row = Gtk.Template.Child()

    password_creation_input = Gtk.Template.Child()

    password_check_button = Gtk.Template.Child()
    password_check_input = Gtk.Template.Child()

    password_repeat_button = Gtk.Template.Child()
    password_repeat_input1 = Gtk.Template.Child()
    password_repeat_input2 = Gtk.Template.Child()

    generate_keyfile_button = Gtk.Template.Child()

    open_safe_button = Gtk.Template.Child()
    back_button = Gtk.Template.Child()

    new_password = ""

    composite = False

    def __init__(self, window, dbm):
        super().__init__()

        self.database_manager = dbm
        self.window = window

        self.back_button.props.sensitive = True
        self.back_button.connect("clicked", self.on_headerbar_back_button_clicked)

    def do_realize(self):  # pylint: disable=arguments-differ
        Gtk.Widget.do_realize(self)
        self.password_action_row.grab_focus()

    def success_page(self):
        self.stack.set_visible_child_name("safe-successfully-create")
        self.clear_input_fields()
        # TODO This should be improved upon. Widgets should not
        # modify widgets outside of their scope.
        self.back_button.props.sensitive = False
        self.open_safe_button.grab_focus()

    def failure_page(self):
        self.stack.set_visible_child_name("password-creation")
        self.clear_input_fields()
        self.window.send_notification(_("Unable to create database"))

    def keyfile_generation_page(self):
        self.stack.set_visible_child_name("keyfile-creation")
        self.generate_keyfile_button.grab_focus()

    def on_headerbar_back_button_clicked(self, _widget):
        """Back button: Always goes back to the page in which you select the
        authentication method. In the case we are already in that page
        we kill this page."""
        self.go_back()

    def go_back(self):
        if self.stack.get_visible_child_name() == "select_auth_method":
            self.window.invoke_initial_screen()
        else:
            self.stack.set_visible_child_name("select_auth_method")
            self.clear_input_fields()
            self.composite = False

    def _on_set_credentials(self, dbm, result):
        try:
            is_saved = dbm.set_credentials_finish(result)
        except GLib.Error as err:
            logging.error("Could not set credentials: %s", err.message)
            self.failure_page()
        else:
            if is_saved:
                self.success_page()
            else:  # Unreachable
                self.failure_page()
        finally:
            self.new_password = ""
            self.stop_pwc_loading()
            self.stop_pwr_loading()

    @Gtk.Template.Callback()
    def on_password_generated(self, _popover, password):
        self.password_creation_input.props.text = password
        self.password_check_input.props.text = password

    @Gtk.Template.Callback()
    def on_auth_chooser_row_activated(
        self, _widget: Gtk.ListBox, row: Gtk.ListBoxRow
    ) -> None:
        if row.get_name() == "password":
            self.stack.set_visible_child_name("password-creation")
            self.password_creation_input.grab_focus()
        elif row.get_name() == "keyfile":
            self.keyfile_generation_page()
        elif row.get_name() == "composite":
            self.composite = True
            self.stack.set_visible_child_name("password-creation")
            self.password_creation_input.grab_focus()

    @Gtk.Template.Callback()
    def on_password_creation_button_clicked(self, _widget: Gtk.Button) -> None:
        self.database_manager.set_password_try(self.password_creation_input.get_text())
        self.stack.set_visible_child_name("check-password")
        self.password_check_input.grab_focus()

    @Gtk.Template.Callback()
    def on_password_check_button_clicked(self, _widget: Gtk.Button) -> None:
        password_check = self.password_check_input.get_text()

        if self.database_manager.compare_passwords(password_check):
            self.new_password = password_check

            if self.composite:
                self.keyfile_generation_page()
            else:
                self.show_pwc_loading()
                self.database_manager.set_credentials_async(
                    password_check, callback=self._on_set_credentials
                )
        else:
            self.stack.set_visible_child_name("passwords-dont-match")
            self.password_repeat_input1.grab_focus()

    @Gtk.Template.Callback()
    def on_password_repeat_button_clicked(self, _widget: Gtk.Button) -> None:

        passwd: str = self.password_repeat_input1.get_text()
        self.database_manager.set_password_try(passwd)
        conf_passwd: str = self.password_repeat_input2.get_text()

        if self.database_manager.compare_passwords(conf_passwd):
            self.new_password = conf_passwd

            if self.composite:
                self.keyfile_generation_page()
            else:
                self.show_pwr_loading()
                self.database_manager.set_credentials_async(
                    self.new_password,
                    callback=self._on_set_credentials,
                )
        else:
            self.window.send_notification(_("Passwords do not match"))
            self.clear_input_fields()
            self.password_repeat_input1.add_css_class("error")
            self.password_repeat_input2.add_css_class("error")

    @Gtk.Template.Callback()
    def on_generate_keyfile_button_clicked(self, _widget: Gtk.Button) -> None:
        """cb invoked when we create a new keyfile for a newly created Safe"""
        filters = Gio.ListStore.new(Gtk.FileFilter)
        filters.append(KeyFileFilter().file_filter)

        dialog = Gtk.FileDialog.new()
        dialog.props.filters = filters
        dialog.props.title = _("Generate Keyfile")
        dialog.props.accept_label = _("_Generate")
        dialog.props.initial_name = _("Keyfile")

        dialog.save(
            self.window,
            None,
            self._on_filechooser_response,
        )

    def _on_filechooser_response(self, dialog, result):
        try:
            keyfile = dialog.save_finish(result)
        except GLib.Error as err:
            logging.debug("Could not save file: %s", err.message)
        else:
            self.generate_keyfile_button.set_sensitive(False)
            self.generate_keyfile_button.set_label(_("Generating…"))

            keyfile_path = keyfile.get_path()
            logging.debug("New keyfile location: %s", keyfile_path)

            def callback(gfile, result):
                password = self.new_password
                keyfile_path = gfile.get_path()
                try:
                    _res, keyfile_hash = generate_keyfile_finish(result)
                except GLib.Error as err:
                    logging.debug("Could not create keyfile: %s", err.message)
                    self.window.send_notification(_("Could not create keyfile"))
                    self.generate_keyfile_button.set_sensitive(True)
                    self.generate_keyfile_button.set_label(_("Generate"))
                else:
                    if not self.composite:
                        password = ""

                    self.database_manager.set_credentials_async(
                        password,
                        keyfile_path,
                        keyfile_hash,
                        self._on_set_credentials,
                    )

            generate_keyfile_async(keyfile, callback)

    @Gtk.Template.Callback()
    def on_finish_button_clicked(self, _widget: Gtk.Button) -> None:
        self.window.start_database_opening_routine(self.database_manager.path)

    @Gtk.Template.Callback()
    def on_password_repeat_input_activate(self, _widget: Gtk.Entry) -> None:
        self.password_repeat_button.activate()

    def show_pwc_loading(self):
        password_check_button = self.password_check_button
        spinner = Gtk.Spinner()
        spinner.start()
        password_check_button.set_child(spinner)
        password_check_button.set_sensitive(False)
        self.password_check_input.set_sensitive(False)

    def stop_pwc_loading(self):
        self.password_check_button.props.icon_name = "object-select-symbolic"
        self.password_check_button.props.sensitive = True
        self.password_check_input.props.sensitive = True

    def show_pwr_loading(self):
        password_repeat_button = self.password_repeat_button
        spinner = Gtk.Spinner()
        spinner.start()
        password_repeat_button.set_child(spinner)
        password_repeat_button.set_sensitive(False)
        self.password_repeat_input1.set_sensitive(False)
        self.password_repeat_input2.set_sensitive(False)

    def stop_pwr_loading(self):
        self.password_repeat_button.props.label = _("_Confirm")
        self.password_repeat_button.props.sensitive = True
        self.password_repeat_input1.props.sensitive = True
        self.password_repeat_input2.props.sensitive = True

    def clear_input_fields(self) -> None:
        """Empty all Entry textfields"""
        self.password_creation_input.set_text("")
        self.password_check_input.set_text("")
        self.password_repeat_input1.set_text("")
        self.password_repeat_input2.set_text("")
