'''Accounts Service D-Bus mock template'''

# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 3 of the License, or (at your option) any
# later version.  See http://www.gnu.org/copyleft/lgpl.html for the full text
# of the license.

__author__ = 'Marco Trevisan'
__email__ = 'marco.trevisan@canonical.com'
__copyright__ = '(c) 2021 Canonical Ltd.'
__license__ = 'LGPL 3+'

import sys
import time

import dbus
import dbusmock
from dbusmock import MOCK_IFACE, mockobject

BUS_NAME = 'org.freedesktop.Accounts'
MAIN_OBJ = '/org/freedesktop/Accounts'
MAIN_IFACE = 'org.freedesktop.Accounts'
USER_IFACE = MAIN_IFACE + '.User'
SYSTEM_BUS = True

DEFAULT_USER_PASSWORD = 'Pa$$wo0rd'


def get_user_path(uid):
    return f'/org/freedesktop/Accounts/User{uid}'


def load(mock, parameters=None):
    parameters = parameters if parameters else {}
    mock.mock_users = {}
    mock.users_auto_uids = 2000

    mock.AddProperties(MAIN_IFACE, {
        'HasNoUsers': dbus.Boolean(True),
        'HasMultipleUsers': dbus.Boolean(False),
    })

    for uid, name in parameters.get('users', {}):
        mock.AddUser(uid, name, '', {})


@dbus.service.method(MOCK_IFACE, in_signature='xssa{sv}',
                     out_signature='o')
def AddUser(self, uid, username, password, overrides):
    '''Add user via uid and username and optionally overriding properties

    Returns the new object path.
    '''
    path = get_user_path(uid)
    default_props = {
        'Uid': dbus.UInt64(uid),
        'UserName': username,
        'RealName': username[0].upper() + username[1:] + ' Fake',
        'AccountType': dbus.Int32(1),
        'AutomaticLogin': False,
        'BackgroundFile': '',
        'Email': f'{username}@python-dbusmock.org',
        'FormatsLocale': 'C',
        'HomeDirectory': f'/nonexisting/mock-home/{username}',
        'IconFile': '',
        'InputSources': dbus.Array([], signature='a{ss}'),
        'Language': 'C',
        'LocalAccount': True,
        'Location': '',
        'Locked': False,
        'LoginFrequency': dbus.UInt64(0),
        'LoginHistory': dbus.Array([], signature='(xxa{sv})'),
        'LoginTime': dbus.Int64(0),
        'PasswordHint': 'Remember it, come on!',
        'PasswordMode': 0,
        'Session': 'mock-session',
        'SessionType': 'wayland',
        'Shell': '/usr/bin/zsh',
        'SystemAccount': False,
        'XHasMessages': False,
        'XKeyboardLayouts': dbus.Array([], signature='s'),
        'XSession': 'mock-xsession',
    }
    default_props.update(overrides if overrides else {})
    self.AddObject(path, USER_IFACE, default_props, [])
    user_object = mockobject.objects[path]

    user_object.AddProperty(
            'com.endlessm.ParentalControls.AppFilter',
            'AppFilter', dbus.Struct([
                             False, dbus.Array(signature='s')
                         ], variant_level=1),
            )

    user = mockobject.objects[path]
    user.password = password
    user.properties = default_props
    self.mock_users[uid] = default_props

    self.EmitSignal(MAIN_IFACE, 'UserAdded', 'o', [path])

    self.UpdateProperties(MAIN_IFACE, {
        'HasNoUsers': dbus.Boolean(len(self.mock_users) == 0),
        'HasMultipleUsers': dbus.Boolean(len(self.mock_users) > 1),
    })

    return path


@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='ao')
def ListMockUsers(self):
    """ List the mock users that have been created """
    return [get_user_path(uid) for uid in self.mock_users.keys()]


@dbus.service.method(MAIN_IFACE, in_signature='x', out_signature='o')
def FindUserById(_self, uid):
    """ Finds an user by its user id """
    user = mockobject.objects.get(get_user_path(uid), None)
    if not user:
        raise dbus.exceptions.DBusException(
            'No such user exists',
            name='org.freedesktop.Accounts.Error.Failed')
    return get_user_path(uid)


@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
def FindUserByName(self, username):
    """ Finds an user form its name """
    try:
        [user_id] = [uid for uid, props in self.mock_users.items()
                     if props['UserName'] == username]
    except ValueError as e:
        raise dbus.exceptions.DBusException(f'No such user exists: {e}', name='org.freedesktop.Accounts.Error.Failed')
    return get_user_path(user_id)