/*****************************************************************************
 * Copyright (c) 2014-2026 OpenRCT2 developers
 *
 * For a complete list of all authors, please refer to contributors.md
 * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
 *
 * OpenRCT2 is licensed under the GNU General Public License version 3.
 *****************************************************************************/

#ifndef DISABLE_NETWORK

    #include "NetworkGroup.h"

    #include "../core/Guard.hpp"
    #include "../core/Json.hpp"
    #include "NetworkAction.h"
    #include "NetworkTypes.h"

namespace OpenRCT2::Network
{
    NetworkGroup NetworkGroup::FromJson(const json_t& jsonData)
    {
        Guard::Assert(jsonData.is_object(), "NetworkGroup::FromJson expects parameter jsonData to be object");

        NetworkGroup group;
        json_t jsonId = jsonData["id"];
        json_t jsonName = jsonData["name"];
        json_t jsonPermissions = jsonData["permissions"];

        if (jsonId.is_null() || jsonName.is_null() || jsonPermissions.is_null())
        {
            throw std::runtime_error("Missing group data");
        }

        group.Id = Json::GetNumber<uint8_t>(jsonId);
        group._name = Json::GetString(jsonName);
        std::fill(group.ActionsAllowed.begin(), group.ActionsAllowed.end(), 0);

        for (const auto& jsonValue : jsonPermissions)
        {
            const std::string permission = Json::GetString(jsonValue);

            Permission action_id = NetworkActions::FindCommandByPermissionName(permission);
            if (action_id != Permission::count)
            {
                group.ToggleActionPermission(action_id);
            }
        }
        return group;
    }

    json_t NetworkGroup::ToJson() const
    {
        json_t jsonGroup = {
            { "id", Id },
            { "name", GetName() },
        };
        json_t actionsArray = json_t::array();
        for (size_t i = 0; i < NetworkActions::Actions.size(); i++)
        {
            if (CanPerformAction(static_cast<Permission>(i)))
            {
                actionsArray.emplace_back(NetworkActions::Actions[i].PermissionName);
            }
        }
        jsonGroup["permissions"] = actionsArray;
        return jsonGroup;
    }

    const std::string& NetworkGroup::GetName() const noexcept
    {
        return _name;
    }

    void NetworkGroup::SetName(std::string_view name)
    {
        _name = name;
    }

    void NetworkGroup::Read(Packet& packet)
    {
        packet >> Id;
        SetName(packet.ReadString());
        for (auto& action : ActionsAllowed)
        {
            packet >> action;
        }
    }

    void NetworkGroup::Write(Packet& packet) const
    {
        packet << Id;
        packet.WriteString(GetName().c_str());
        for (const auto& action : ActionsAllowed)
        {
            packet << action;
        }
    }

    void NetworkGroup::ToggleActionPermission(Permission index)
    {
        size_t index_st = static_cast<size_t>(index);
        size_t byte = index_st / 8;
        size_t bit = index_st % 8;
        if (byte >= ActionsAllowed.size())
        {
            return;
        }
        ActionsAllowed[byte] ^= (1 << bit);
    }

    bool NetworkGroup::CanPerformAction(Permission index) const noexcept
    {
        size_t index_st = static_cast<size_t>(index);
        size_t byte = index_st / 8;
        size_t bit = index_st % 8;
        if (byte >= ActionsAllowed.size())
        {
            return false;
        }
        return (ActionsAllowed[byte] & (1 << bit)) != 0;
    }

    bool NetworkGroup::CanPerformCommand(GameCommand command) const
    {
        Permission action = NetworkActions::FindCommand(command);
        if (action != Permission::count)
        {
            return CanPerformAction(action);
        }
        return false;
    }
} // namespace OpenRCT2::Network

#endif
