import gettext
from gi.repository import Gtk, GObject

from DomainjoinGUI.dbus_client import Domain, DomainUser
from DomainjoinGUI.utils import get_ui_file_path, GET_TEXT_DOMAIN, create_builder, show_error_dialog

_ = gettext.gettext
class DomainListBoxRow(Gtk.ListBoxRow):
    __gsignals__ = {
        'show-domain-details': (GObject.SIGNAL_RUN_FIRST, None,(Domain,))
    }

    def __init__(self, domain):
        Gtk.ListBoxRow.__init__(self)
        self.domain = domain

        builder = create_builder(get_ui_file_path('listbox-rows.ui'))
        self._domain_listbox_row = builder.get_object('_domain_listbox_row')
        self._title = builder.get_object('_domain_listbox_row_title')
        self._subtitle = builder.get_object('_domain_listbox_row_subtitle')
        self._show_domain_details_button = builder.get_object('_show_domain_details_button')

        self.set_selectable(False)
        self.set_activatable(False)

        self._show_domain_details_button.connect('clicked', self._on_show_domain_details_button_clicked)

        self.add(self._domain_listbox_row)
        self.update()

    def update(self):
        domain_info = self.domain.domain_info
        
        users = domain_info['user-count']
        groups = domain_info['group-count']
        all_users = users + groups

        description = _("Allowed users: %s") % all_users if all_users > 0 else _("No users allowed")

        self._title.set_text(str(self.domain.domain_name))
        self._subtitle.set_markup('<small><i>{}</i></small>'.format(_(description)))


    def _on_show_domain_details_button_clicked(self, button):
        self.emit('show-domain-details', self.domain)


class AllowedUserListBoxRow(Gtk.ListBoxRow):
    SUBTITLE_FORMAT = "<small><i>{}</i></small>"

    __gsignals__ = {
        'show-user-config': (GObject.SIGNAL_RUN_FIRST, None,(Gtk.Button, DomainUser))
    }

    def __init__(self, user):
        Gtk.ListBoxRow.__init__(self)

        self.user = user
        self.user.connect('user-changed', self._on_user_changed)

        builder = create_builder(get_ui_file_path('listbox-rows.ui'))

        child = builder.get_object('_allowed_user_listbox_row')
        self.add(child)

        self._title = builder.get_object('_user_listbox_row_title')
        self._subtitle = builder.get_object('_user_listbox_row_subtitle')
        self._icon = builder.get_object('_user_listbox_row_icon')
        self._preferences = builder.get_object('_user_listbox_row_config')

        self._load()

        self._preferences.connect('clicked', self._on_preferences_button_clicked)

    def _load(self):
        self._title.set_text(self.user.username)
        self._subtitle.set_markup(self.SUBTITLE_FORMAT.format(_("Administrator") if self.user.is_admin else ""))
        self._icon.set_from_icon_name(
            'system-users-symbolic' if self.user.is_group else 'avatar-default-symbolic',
            Gtk.IconSize.DND
        )

    def _on_user_changed(self, user):
        self._load()

    def _on_preferences_button_clicked(self, button):
        self.emit('show-user-config', self._preferences, self.user)


class UserDetailsPopover(GObject.GObject):
    def __init__(self, window):
        GObject.GObject.__init__(self)

        self.window = window

        builder = create_builder(get_ui_file_path('user-popover.ui'))

        self._popover = builder.get_object('_user_actions_popover')
        self._admin_permissions_switch = builder.get_object('_admin_permissions_switch')
        self._remove_user_button = builder.get_object('_remove_user_button')

        self._admin_permissions_switch_changed_id = -1
        self._remove_user_button_clicked_id = -1

        self._popover.connect('closed', self._on_close)

    def _on_close(self, popover):
        if self._admin_permissions_switch_changed_id > 0:
            self._admin_permissions_switch.disconnect(self._admin_permissions_switch_changed_id)
            self._admin_permissions_switch_changed_id = -1

        if self._remove_user_button_clicked_id > 0:
            self._remove_user_button.disconnect(self._remove_user_button_clicked_id)
            self._remove_user_button_clicked_id = -1

    def show_popover(self, widget, user, domain):
        self._admin_permissions_switch.set_active(user.is_admin)
        self._admin_permissions_switch.set_sensitive(not user.is_group)

        self._admin_permissions_switch_changed_id = self._admin_permissions_switch.connect(
            'state-set',
            self._admin_permissions_switch_changed,
            (user, domain)
        )
        self._remove_user_button_clicked_id = self._remove_user_button.connect(
            'clicked',
            self._remove_user_button_clicked,
            (user, domain)
        )

        self._popover.set_relative_to(widget)
        self._popover.popup()

    def hide_popover(self):
        self._popover.popdown()

    def _remove_user_button_clicked(self, button, data):
        try:
            user, domain = data

            def on_remove_user_success():
                self.window.hide_loading_indicator()

            def on_remove_user_error(error):
                self.window.hide_loading_indicator()
                show_error_dialog(error)

            domain.remove_user_async(user, on_success=on_remove_user_success, on_error=on_remove_user_error)
            self.hide_popover()
            self.window.show_loading_indicator()
        except Exception as e:
            print(e)

    def _admin_permissions_switch_changed(self, switch, state, data):
        try:
            user, domain = data
            def on_set_permissions_success():
                self.window.hide_loading_indicator()

            def on_set_permissions_error(error):
                self.window.hide_loading_indicator()
                show_error_dialog(error)

            domain.set_user_admin_status_async(
                user,
                state,
                on_success=on_set_permissions_success,
                on_error=on_set_permissions_error
            )
            self.hide_popover()
            self.window.show_loading_indicator()
        except Exception as e:
            print(e)


class AddUserDialog(Gtk.Dialog):
    
    def __init__(self, parent):
        super().__init__(
            title=_("Add user"), 
            transient_for=parent,
            flags=Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT
        )

        builder = create_builder(get_ui_file_path('add-user-dialog.ui'))
        self.get_content_area().add(builder.get_object('_add_dialog_box'))

        self.user_name_entry = builder.get_object('_user_name_entry')
        self.is_group_switch = builder.get_object('_is_group_switch')
        self.is_admin_switch = builder.get_object('_is_admin_switch')

        self.is_group_switch.connect('state-set', self.is_group_switch_changed)

        self.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_ADD, Gtk.ResponseType.OK
        )

    def is_group_switch_changed(self, switch, state, data=None):
        self.is_admin_switch.set_sensitive(not state)


class AddDomainDialog(Gtk.Dialog):
    
    def __init__(self, parent):
        super().__init__(
            title=_("Join domain"), 
            transient_for=parent,
            flags=Gtk.DialogFlags.MODAL|Gtk.DialogFlags.DESTROY_WITH_PARENT
        )

        builder = create_builder(get_ui_file_path('add-domain-dialog.ui'))
        self.get_content_area().add(builder.get_object('_add_dialog_box'))

        self.domain_name_entry = builder.get_object('_domain_name_entry')
        self.domain_user_entry = builder.get_object('_domain_user_entry')
        self.password_entry = builder.get_object('_password_entry')

        self.add_buttons(
            Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
            Gtk.STOCK_ADD, Gtk.ResponseType.OK
        )


class DomainDetailsBox(Gtk.Bin):
    def __init__(self, window):
        GObject.GObject.__init__(self)

        self.window = window
        self.domain = None

        self._domain_user_added_id = -1
        self._domain_user_removed_id = -1
        self._domain_user_changed_id = -1
        self._fqdn_switch_changed_id = -1

        builder = create_builder(get_ui_file_path('domain-details.ui'))
        self._box = builder.get_object('_domain_details_root')
        self.add(self._box)
        self._use_fqdn_switch = builder.get_object('_use_fqdn_switch')
        self._allowed_users_listbox = builder.get_object('_allowed_users_listbox')
        self._add_user_button = builder.get_object('_add_user_button')
        self._leave_domain_button = builder.get_object('_leave_domain_button')
        self._add_user_button.connect('clicked', self._on_add_user_button_clicked)
        self._leave_domain_button.connect('clicked', self._on_leave_domain_button_clicked)
        self._user_actions_popover = UserDetailsPopover(self.window)

    def _on_leave_domain_button_clicked(self, button):
        if self.domain is not None:
            def _on_leave_domain_success():
                self.window.hide_loading_indicator()
                self.window.show_main_page()

            def _on_leave_domain_error(error):
                self.window.hide_loading_indicator()
                show_error_dialog(error)

            self.domain.leave_async(on_success=_on_leave_domain_success, on_error=_on_leave_domain_error)
            self.window.show_loading_indicator()

    def _on_add_user_button_clicked(self, button):
        if self.domain is not None:
            dialog = AddUserDialog(self.window)
            response = dialog.run()

            if response == Gtk.ResponseType.OK:
                username = dialog.user_name_entry.get_text()
                isgroup = dialog.is_group_switch.get_state()
                isadmin = dialog.is_admin_switch.get_state()

                def _on_add_user_success():
                    self.window.hide_loading_indicator()

                def _on_add_user_error(error):
                    self.window.hide_loading_indicator()
                    show_error_dialog(error)

                self.domain.add_user_async(username, isgroup, isadmin, on_success=_on_add_user_success, on_error=_on_add_user_error)
                self.window.show_loading_indicator()

            dialog.destroy()

    def _on_use_fqdn_switch_changed(self, switch, state):
        if self.domain is not None:
            self.domain.use_fqdn = state

    def _on_userlist_changed(self, domain):
        if self.domain:
            self._load_userlist()

    def load(self, domain):
        self.domain = domain
        self._domain_user_added_id = self.domain.connect('user-added', self._on_userlist_changed)
        self._domain_user_removed_id = self.domain.connect('user-removed', self._on_userlist_changed)
        self._domain_user_changed_id = self.domain.connect('user-changed', self._on_userlist_changed)

        self._use_fqdn_switch.set_active(domain.use_fqdn)
        self._fqdn_switch_changed_id = self._use_fqdn_switch.connect('state-set', self._on_use_fqdn_switch_changed)
        
        self._load_userlist()
            
    def _load_userlist(self):
        self._user_actions_popover.hide_popover()
        self._allowed_users_listbox.foreach(lambda x : self._allowed_users_listbox.remove(x))
        allowed_users = self.domain.users

        for user in allowed_users:
            row = AllowedUserListBoxRow(user)
            self._allowed_users_listbox.add(row)
            row.set_visible(True)
            row.connect('show-user-config', self._on_show_user_config)

    def _on_show_user_config(self, row, button, user):
        if self.domain:
            self._user_actions_popover.show_popover(button, user, self.domain)

    def unload(self):
        if self._fqdn_switch_changed_id > 0:
            self._use_fqdn_switch.disconnect(self._fqdn_switch_changed_id)
            self._fqdn_switch_changed_id = -1

        if self._domain_user_added_id > 0:
            self.domain.disconnect(self._domain_user_added_id)
            self.domain_user_added_id = -1

        if self._domain_user_removed_id > 0:
            self.domain.disconnect(self._domain_user_removed_id)
            self.domain_user_removed_id = -1

        if self._domain_user_changed_id > 0:
            self.domain.disconnect(self._domain_user_changed_id)
            self.domain_user_changed_id = -1

        self.domain = None

        self._allowed_users_listbox.foreach(lambda x : self._allowed_users_listbox.remove(x))
