#include "users_script.h"
#include "users_utils.h"
#include "projects_utils.h"
#include <library/cpp/json/json_reader.h>
#include <util/string/vector.h>

namespace NRTYDeploy {

    TScriptUsers::TFactory::TRegistrator<TScriptUsers> TScriptUsers::Registrator("users");

    void TScriptUsers::DoProcess(IDeployInfoRequest& request) {
        const TCgiParameters& cgi = request.GetRD().CgiParam;
        const TString& action = cgi.Get("action");
        const TString& login = cgi.Get("login");
        if (action == "who_am_i") {
            Report.InsertValue("login", User.Login);
        } else if (action == "list") {
            if (GetUser(request.GetStorage(), User.Login).GetDefaultRole() < NDMInterface::TUser::WATCHER)
                ythrow TCodedException(403) << "user " << User.Login << " not permitted to list of other users";
            TVector<TString> users;
            ListUsers(request.GetStorage(), users);
            Report.SetType(NJson::JSON_ARRAY);
            for (const auto& user : users)
                Report.AppendValue(NJson::JSON_MAP).InsertValue("login", user);
        } else if (action == "get") {
            if (!login)
                ythrow TCodedException(400) << "login not set";
            if (login != User.Login && GetUser(request.GetStorage(), User.Login).GetDefaultRole() < NDMInterface::TUser::WATCHER)
                ythrow TCodedException(403) << "user " << User.Login << " not permitted to watch data of user " << login;
            Proto2Json(GetUser(request.GetStorage(), login), Report, true);
        } else if (action == "set_role_in_project") {
            const TString& project = cgi.Get("project");
            if (!project)
                ythrow TCodedException(400) << "project not set";
            if (GetUserRoleInProject(request.GetStorage(), User.Login, project) < NDMInterface::TUser::ADMINISTRATOR)
                ythrow TCodedException(403) << "user " << User.Login << " not permitted to change project " << project;
            if (!login)
                ythrow TCodedException(400) << "login not set";
            const TString& role = cgi.Get("role");
            NDMInterface::TUser user = GetUser(request.GetStorage(), login);
            if (role == "DEFAULT") {
                const auto roles = user.GetRoleInProject();
                user.ClearRoleInProject();
                for (const auto& r : roles)
                    if (r.GetProject() != project)
                        *user.AddRoleInProject() = r;
            } else {
                const auto roleVal = NDMInterface::TUser::descriptor()->FindEnumValueByName(role);
                if (!roleVal)
                    ythrow TCodedException(400) << "Unknown role " << role;
                bool set = false;
                for (auto& roleInPrj : *user.MutableRoleInProject())
                    if (roleInPrj.GetProject() == project) {
                        roleInPrj.SetRole((NDMInterface::TUser::TRole)roleVal->number());
                        set = true;
                    }
                if (!set) {
                    auto& roleInPrj = *user.AddRoleInProject();
                    roleInPrj.SetRole((NDMInterface::TUser::TRole)roleVal->number());
                    roleInPrj.SetProject(project);
                }
            }
            SaveUser(request.GetStorage(), user);
        } else if (action == "set") {
            if (GetUser(request.GetStorage(), User.Login).GetDefaultRole() < NDMInterface::TUser::SUPER_USER)
                ythrow TCodedException(403) << "user " << User.Login << " not permitted to change list of other users";
            NDMInterface::TUser user;
            TMemoryInput mi(request.GetBlob().AsCharPtr(), request.GetBlob().Size());
            NJson::TJsonValue json;
            if (!NJson::ReadJsonTree(&mi, &json))
                ythrow TCodedException(400) << "errors in json";
            Json2Proto(json, user);
            if (login)
                user.SetLogin(login);
            SaveUser(request.GetStorage(), user);
        } else {
            ythrow TCodedException(400) << "unknown action " << action;
        }
    }
};
