#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Copyright 2025 GNOME Foundation, Inc.
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# This library 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 2.1 of the License, or (at your option) any later version.
#
# This library 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
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA  02110-1301  USA

"""AccountsService mock template

This creates the expected methods and properties of the main
org.freedesktop.Accounts object. You can specify a mock list of user accounts
in `parameters`.
"""

__author__ = "Philip Withnall"
__copyright__ = """
(c) 2025 GNOME Foundation, Inc.
"""

import dbus
import dbusmock

BUS_NAME = "org.freedesktop.Accounts"
MAIN_OBJ = "/org/freedesktop/Accounts"
MAIN_IFACE = "org.freedesktop.Accounts"
SYSTEM_BUS = True


def load(mock, parameters):
    mock.AddMethods(
        MAIN_IFACE,
        [
            ("CacheUser", "s", "o", ""),
            ("CreateUser", "ssi", "o", ""),
            ("DeleteUser", "xb", "", ""),
        ],
    )

    mock.AddProperties(
        MAIN_IFACE,
        dbus.Dictionary(
            {
                "AutomaticLoginUsers": parameters.get(
                    "AutomaticLoginUsers", dbus.Array([], signature="o")
                ),
                "HasMultipleUsers": len(parameters.get("Users", [])) > 1,
                "HasNoUsers": len(parameters.get("Users", [])) == 0,
                "DaemonVersion": parameters.get("DaemonVersion", "25.05.0"),
            },
            signature="sv",
        ),
    )

    for user in parameters.get("Users", []):
        uid = user.get("Uid", 1000)
        username = user.get("UserName", "alice")
        user_path = "/org/freedesktop/Accounts/User" + str(uid)

        mock.AddObject(
            user_path,
            "org.freedesktop.Accounts.User",
            {
                "Languages": dbus.Array(["en_GB.UTF-8"], signature="s"),
                "LoginHistory": dbus.Array([], signature="(xxa{sv})"),
                "AutomaticLogin": False,
                "LocalAccount": True,
                "Locked": False,
                "Saved": True,
                "SystemAccount": False,
                "AccountType": dbus.Int32(1),
                "PasswordMode": dbus.Int32(0),
                "LoginTime": dbus.Int64(1754492399),
                "Email": "",
                "HomeDirectory": "/home/" + username,
                "IconFile": "/var/lib/AccountsService/icons/" + username,
                "Language": "en_GB.UTF-8",
                "Location": "",
                "PasswordHint": "",
                "RealName": "Alice",
                "Session": "gnome",
                "SessionType": "",
                "Shell": "/bin/bash",
                "UserName": username,
                "XSession": "",
                "LoginFrequency": dbus.UInt64(569),
                "Uid": dbus.UInt64(uid),
            },
            [
                ("GetPasswordExpirationPolicy", "", "(xxxxxx)", ""),
                ("SetAccountType", "i", "", ""),
                ("SetAutomaticLogin", "b", "", ""),
                ("SetEmail", "s", "", ""),
                ("SetHomeDirectory", "s", "", ""),
                ("SetIconFile", "s", "", ""),
                ("SetLanguage", "s", "", ""),
                ("SetLanguages", "as", "", ""),
                ("SetLocation", "s", "", ""),
                ("SetLocked", "b", "", ""),
                ("SetPassword", "ss", "", ""),
                ("SetPasswordExpirationPolicy", "xxxx", "", ""),
                ("SetPasswordHint", "s", "", ""),
                ("SetPasswordMode", "i", "", ""),
                ("SetRealName", "s", "", ""),
                ("SetSession", "s", "", ""),
                ("SetSessionType", "s", "", ""),
                ("SetShell", "s", "", ""),
                ("SetUserExpirationPolicy", "x", "", ""),
                ("SetUserName", "s", "", ""),
                ("SetXSession", "s", "", ""),
            ],
        )

        user_obj = dbusmock.mockobject.get_object(user_path)

        user_obj.AddProperties(
            "com.endlessm.ParentalControls.AccountInfo",
            {
                "IsParent": user.get("IsParent", True),
            },
        )
        user_obj.AddProperties(
            "com.endlessm.ParentalControls.AppFilter",
            {
                "AllowSystemInstallation": user.get("AllowSystemInstallation", True),
                "AllowUserInstallation": user.get("AllowSystemInstallation", True),
                "AppFilter": user.get(
                    "AppFilter", (False, dbus.Array([], signature="s"))
                ),
                "OarsFilter": user.get(
                    "OarsFilter", (True, dbus.Dictionary({}, signature="ss"))
                ),
            },
        )
        user_obj.AddProperties(
            "com.endlessm.ParentalControls.SessionLimits",
            {
                "DailySchedule": user.get(
                    "DailySchedule", (dbus.UInt32(0), dbus.UInt32(86400))
                ),
                "DailyLimit": user.get("DailyLimit", dbus.UInt32(0)),
                "LimitType": user.get("LimitType", dbus.UInt32(0)),
            },
        )
        user_obj.AddProperties(
            "org.freedesktop.Malcontent.WebFilter",
            {
                "CustomAllowList": user.get(
                    "CustomAllowList", dbus.Array([], signature="s")
                ),
                "CustomBlockList": user.get(
                    "CustomBlockList", dbus.Array([], signature="s")
                ),
                "ForceSafeSearch": user.get("ForceSafeSearch", False),
                "AllowLists": user.get(
                    "AllowLists", dbus.Dictionary({}, signature="ss")
                ),
                "BlockLists": user.get(
                    "BlockLists", dbus.Dictionary({}, signature="ss")
                ),
                "FilterType": user.get("FilterType", dbus.UInt32(0)),
            },
        )


#
# AccountsService methods which are too big for squeezing into AddMethod()
#


@dbus.service.method(MAIN_IFACE, in_signature="x", out_signature="o")
def FindUserById(_, id):
    # FIXME: Does it load and cache the user if not found?
    for k, obj in dbusmock.mockobject.objects.items():
        if "/User" in k and obj.Get("org.freedesktop.Accounts.User", "Uid") == id:
            return k
    return None


@dbus.service.method(MAIN_IFACE, in_signature="s", out_signature="o")
def FindUserByName(_, name):
    # FIXME: Does it load and cache the user if not found?
    for k, obj in dbusmock.mockobject.objects.items():
        if (
            "/User" in k
            and obj.Get("org.freedesktop.Accounts.User", "UserName") == name
        ):
            return k
    return None


@dbus.service.method(MAIN_IFACE, in_signature="", out_signature="as")
def GetUsersLanguages(_):
    languages = []
    for k, obj in dbusmock.mockobject.objects.items():
        if "/User" in k:
            user_languages = obj.Get("org.freedesktop.Accounts.User", "Languages")
            languages += user_languages
    return list(set(languages))


@dbus.service.method(MAIN_IFACE, in_signature="", out_signature="ao")
def ListCachedUsers(_):
    users = []
    for k, obj in dbusmock.mockobject.objects.items():
        if "/User" in k:
            users.append(k)
    return users


@dbus.service.method(MAIN_IFACE, in_signature="s", out_signature="")
def UncacheUser(self, name):
    for k, obj in dbusmock.mockobject.objects.items():
        if obj.Get("org.freedesktop.Accounts.User", "UserName") == name:
            self.RemoveObject(k)
            return
