# 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, Gio, GLib, Gtk

import saldo.config_manager as config
from saldo.const import APP_ID
import os
from gettext import gettext as _
from random import randint


@Gtk.Template(resource_path="/org/tabos/saldo/ui/settings_dialog.ui")
class SettingsDialog(Adw.PreferencesDialog):
    __gtype_name__ = "SettingsDialog"

    _general_group = Gtk.Template.Child()
    _dark_theme_row = Gtk.Template.Child()
    _lock_timer_spin_button = Gtk.Template.Child()
    _safe_days_spin_button = Gtk.Template.Child()
    _automatic_refresh_switch = Gtk.Template.Child()
    _background_notification_switch = Gtk.Template.Child()
    _autostart_switch = Gtk.Template.Child()

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

        self.window = window
        self.autostart_failed = False

        self._set_config_values()

    def on_dark_theme(self, action, *args):  # pylint: disable=unused-argument
        manager = Adw.StyleManager.get_default()
        if action.props.state:
            manager.props.color_scheme = Adw.ColorScheme.PREFER_DARK
        else:
            manager.props.color_scheme = Adw.ColorScheme.DEFAULT

    def on_lock_timer_changed(self, val):
        config.set_lock_timer_seconds(val.get_value_as_int())

    def on_safe_days_changed(self, val):
        config.set_safe_days(val.get_value_as_int())

    def _set_config_values(self):
        action_group = Gio.SimpleActionGroup.new()
        settings = Gio.Settings.new(APP_ID)

        # General
        manager = Adw.StyleManager.get_default()
        if manager.props.system_supports_color_schemes:
            self._dark_theme_row.props.visible = False
            dark_mode_action = settings.create_action("dark-theme")
            action_group.add_action(dark_mode_action)
            dark_mode_action.connect("notify::state", self.on_dark_theme)

        settings.bind(
            "lock-timer",
            self._lock_timer_spin_button,
            "value",
            Gio.SettingsBindFlags.DEFAULT,
        )
        self._lock_timer_spin_button.connect(
            "value-changed", self.on_lock_timer_changed
        )

        settings.bind(
            "safe-days",
            self._safe_days_spin_button,
            "value",
            Gio.SettingsBindFlags.DEFAULT,
        )
        self._safe_days_spin_button.connect("value-changed", self.on_safe_days_changed)

        settings.bind(
            "automatic-refresh",
            self._automatic_refresh_switch,
            "active",
            Gio.SettingsBindFlags.DEFAULT,
        )
        self._automatic_refresh_switch.connect("state-set", self._on_automatic_refresh)

        settings.bind(
            "run-in-background",
            self._background_notification_switch,
            "active",
            Gio.SettingsBindFlags.DEFAULT,
        )

        settings.bind(
            "autostart",
            self._autostart_switch,
            "active",
            Gio.SettingsBindFlags.DEFAULT,
        )
        self._autostart_switch.connect("notify::active", self._on_autostart_refresh)

        quickunlock_action = settings.create_action("quickunlock")
        action_group.add_action(quickunlock_action)
        fingerprint_quickunlock_action = settings.create_action(
            "fingerprint-quickunlock",
        )
        action_group.add_action(fingerprint_quickunlock_action)

        self.insert_action_group("settings", action_group)

    def _on_automatic_refresh(self, action, *args):  # pylint: disable=unused-argument
        if not action.props.state:
            self.window.start_automatic_refresh()
        else:
            self.window.stop_automatic_refresh()

    def __get_window_identifier(self):
        session = os.getenv("XDG_SESSION_TYPE")
        surface = self.window.get_surface()

        if session == "x11":
            return f"x11:{str(surface.get_xid())}"
        elif session == "wayland":
            return "wayland:"
        return ""

    def _on_autostart_refresh(self, action, *args):  # pylint: disable=unused-argument
        if self.autostart_failed:
            self.autostart_failed = False
            return

        bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
        proxy = Gio.DBusProxy.new_sync(
            bus,
            Gio.DBusProxyFlags.NONE,
            None,
            "org.freedesktop.portal.Desktop",
            "/org/freedesktop/portal/desktop",
            "org.freedesktop.portal.Background",
            None,
        )

        print(self._autostart_switch.get_active())
        identifier = self.__get_window_identifier()
        token = 0 + randint(10000000, 90000000)
        options = {
            "handle_token": GLib.Variant("s", f"org/tabos/saldo/{token}"),
            "reason": GLib.Variant("s", _("Autostart Saldo in background.")),
            "autostart": GLib.Variant("b", self._autostart_switch.get_active()),
            "commandline": GLib.Variant("as", ["org.tabos.saldo", "--hidden"]),
            "dbus-activatable": GLib.Variant("b", False),
        }

        try:
            request = proxy.RequestBackground("(sa{sv})", identifier, options)  # type: ignore
            if request is None:
                raise Exception(
                    "The DBus proxy didn't return an object path."
                    + "\nThe portal can't subscribe to the signal."
                )

            bus.signal_subscribe(
                "org.freedesktop.portal.Desktop",
                "org.freedesktop.portal.Request",
                "Response",
                request,
                None,
                Gio.DBusSignalFlags.NO_MATCH_RULE,
                self.__receive_autostart,
                None,
            )

        except Exception as e:
            print(e)

            error_dialog = Adw.AlertDialog.new(
                _("Request error"), _("The autostart request failed.")
            )
            error_dialog.add_response("ok", _("Ok"))
            error_dialog.present(self.window)
            self.autostart_failed = True
            self.autostart.set_active(self.autostart_saved)

    def __receive_autostart(self, *args):
        self.window.present()

        active = self._autostart_switch.get_active()
        state = args[5][0]
        autostart = args[5][1]["autostart"]

        if state == 0:
            pass
        elif state == 1:
            if active:
                error_dialog = Adw.AlertDialog.new(
                    _("Authorization failed"),
                    _(
                        "Make sure Saldo has permission to run in the background in Settings → Applications → Saldo and try again."
                    ),
                )
                error_dialog.add_response("ok", _("Ok"))
                error_dialog.present(self.window)
        elif state == 2:
            error_dialog = Adw.AlertDialog.new(
                _("Request error"), _("The autostart request failed.")
            )
            error_dialog.add_response("ok", _("Ok"))
            error_dialog.present(self.window)

        self._autostart_switch.set_active(autostart)
        # Settings.get().autostart = autostart
        return
