#include "idm_service.h"

#include <maps/wikimap/mapspro/services/mrc/drive/firmware_updater/libs/db/include/idm/user_role_gateway.h>

namespace maps::fw_updater::storage::idm {

RoleTree getRoleTree(pqxx::transaction_base& txn)
{
    return RoleTree::load(txn);
}


void addUserRole(
    pqxx::transaction_base& txn,
    const Login& login,
    const SlugPath& slugPath)
{
    auto tree = RoleTree::load(txn);
    auto projectRoleId = tree.leafNodeIdBySlugPath(slugPath);

    if (!projectRoleId) {
        throw BadParameter() << "Slug path " << slugPath << " does not exist";
    }

    db::idm::UserRoleGateway gtw{txn};
    gtw.upsert(db::idm::UserRole(login, *projectRoleId));
}


void removeUserRole(
    pqxx::transaction_base& txn,
    const Login& login,
    const SlugPath& slugPath)
{
    auto tree = RoleTree::load(txn);
    auto projectRoleId = tree.leafNodeIdBySlugPath(slugPath);

    if (!projectRoleId) {
        throw BadParameter() << "Slug path " << slugPath << " does not exist";
    }

    db::idm::UserRoleGateway{txn}.remove(
        db::idm::table::UserRole::login == login &&
        db::idm::table::UserRole::projectRoleId == *projectRoleId);
}


SlugPaths getUserRoles(pqxx::transaction_base& txn, const Login& login)
{
    auto tree = RoleTree::load(txn);
    auto userRoles = db::idm::UserRoleGateway{txn}.load(
        db::idm::table::UserRole::login == login);

    SlugPaths result;
    result.reserve(userRoles.size());

    for (const auto& userRole : userRoles) {
        result.push_back(tree.slugPathByLeafNodeId(userRole.projectRoleId()));
    }
    return result;
}


std::map<Login, SlugPaths> getAllRoles(pqxx::transaction_base& txn)
{
    auto tree = RoleTree::load(txn);
    auto userRoles = db::idm::UserRoleGateway{txn}.load();
    std::map<Login, std::vector<SlugPath>> result;

    for (const auto& userRole : userRoles) {
        result[userRole.login()].push_back(
            tree.slugPathByLeafNodeId(userRole.projectRoleId()));
    }
    return result;
}

bool userHasRoleInProject(pqxx::transaction_base& txn,
                          const Login& login,
                          const std::string& roleKey,
                          Id projectId)
{
    const auto tree = RoleTree::load(txn);
    const auto& node = tree.getNode(projectId);
    auto projectRoleId = std::find_if(
        node.leafChildIds().begin(),
        node.leafChildIds().end(),
        [&](Id id) { return tree.getLeafNode(id).role().key() == roleKey; });

    if (projectRoleId == node.leafChildIds().end()) {
        return false;
    }

    return db::idm::UserRoleGateway{txn}.exists(
        db::idm::table::UserRole::login == login &&
        db::idm::table::UserRole::projectRoleId == *projectRoleId);
}


} //namespace maps::fw_updater::storage::idm
