/*
// Copyright (c) 2018 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
*/
#pragma once

#include "node.hpp"

namespace redfish
{

inline std::string getRoleFromPrivileges(std::string_view priv)
{
    if (priv == "priv-admin")
    {
        return "Administrator";
    }
    else if (priv == "priv-callback")
    {
        return "Callback";
    }
    else if (priv == "priv-user")
    {
        return "User";
    }
    else if (priv == "priv-operator")
    {
        return "Operator";
    }
    return "";
}

inline bool getAssignedPrivFromRole(std::string_view role,
                                    nlohmann::json& privArray)
{
    if (role == "Administrator")
    {
        privArray = {"Login", "ConfigureManager", "ConfigureUsers",
                     "ConfigureSelf", "ConfigureComponents"};
    }
    else if (role == "Operator")
    {
        privArray = {"Login", "ConfigureSelf", "ConfigureComponents"};
    }
    else if (role == "User")
    {
        privArray = {"Login", "ConfigureSelf"};
    }
    else if (role == "Callback")
    {
        privArray = {"Login"};
    }
    else
    {
        return false;
    }
    return true;
}

class Roles : public Node
{
  public:
    Roles(CrowApp& app) :
        Node(app, "/redfish/v1/AccountService/Roles/<str>/", std::string())
    {
        entityPrivileges = {
            {boost::beast::http::verb::get, {{"Login"}}},
            {boost::beast::http::verb::head, {{"Login"}}},
            {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
            {boost::beast::http::verb::put, {{"ConfigureManager"}}},
            {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
            {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
    }

  private:
    void doGet(crow::Response& res, const crow::Request& req,
               const std::vector<std::string>& params) override
    {
        if (params.size() != 1)
        {
            messages::internalError(res);
            res.end();
            return;
        }
        const std::string& roleId = params[0];
        nlohmann::json privArray = nlohmann::json::array();
        if (false == getAssignedPrivFromRole(roleId, privArray))
        {
            messages::resourceNotFound(res, "Role", roleId);
            res.end();
            return;
        }

        res.jsonValue = {
            {"@odata.type", "#Role.v1_0_2.Role"},
            {"@odata.context", "/redfish/v1/$metadata#Role.Role"},
            {"Name", "User Role"},
            {"Description", "Administrator User Role"},
            {"OemPrivileges", nlohmann::json::array()},
            {"IsPredefined", true},
            {"Id", roleId},
            {"@odata.id", "/redfish/v1/AccountService/Roles/" + roleId},
            {"AssignedPrivileges", std::move(privArray)}};
        res.end();
    }
};

class RoleCollection : public Node
{
  public:
    RoleCollection(CrowApp& app) :
        Node(app, "/redfish/v1/AccountService/Roles/")
    {
        entityPrivileges = {
            {boost::beast::http::verb::get, {{"Login"}}},
            {boost::beast::http::verb::head, {{"Login"}}},
            {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
            {boost::beast::http::verb::put, {{"ConfigureManager"}}},
            {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
            {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
    }

  private:
    void doGet(crow::Response& res, const crow::Request& req,
               const std::vector<std::string>& params) override
    {
        auto asyncResp = std::make_shared<AsyncResp>(res);
        res.jsonValue = {{"@odata.context",
                          "/redfish/v1/"
                          "$metadata#RoleCollection.RoleCollection"},
                         {"@odata.id", "/redfish/v1/AccountService/Roles"},
                         {"@odata.type", "#RoleCollection.RoleCollection"},
                         {"Name", "Roles Collection"},
                         {"Description", "BMC User Roles"}};

        crow::connections::systemBus->async_method_call(
            [asyncResp](
                const boost::system::error_code ec,
                const sdbusplus::message::variant<std::vector<std::string>>&
                    resp) {
                if (ec)
                {
                    messages::internalError(asyncResp->res);
                    return;
                }
                nlohmann::json& memberArray =
                    asyncResp->res.jsonValue["Members"];
                memberArray = nlohmann::json::array();
                const std::vector<std::string>* privList =
                    sdbusplus::message::variant_ns::get_if<
                        std::vector<std::string>>(&resp);
                for (const std::string& priv : *privList)
                {
                    std::string role = getRoleFromPrivileges(priv);
                    if (!role.empty())
                    {
                        memberArray.push_back(
                            {{"@odata.id",
                              "/redfish/v1/AccountService/Roles/" + role}});
                    }
                }
                asyncResp->res.jsonValue["Members@odata.count"] =
                    memberArray.size();
            },
            "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
            "org.freedesktop.DBus.Properties", "Get",
            "xyz.openbmc_project.User.Manager", "AllPrivileges");
    }
};

} // namespace redfish
