"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
const { getMultiIDParams, getGlobalIDFromUserMetadataID, } = require("../db/utils");
const { BUILTIN_ROLE_IDS } = require("@devlego/backend-core/roles");
const { getProdAppID } = require("@devlego/backend-core/db");
const { getGlobalUserParams } = require("@devlego/backend-core/db");
const { user: userCache } = require("@devlego/backend-core/cache");
const { getGlobalDB, isUserInAppTenant, } = require("@devlego/backend-core/tenancy");
const env = require("../environment");
const { getAppId } = require("@devlego/backend-core/context");
const { groups } = require("@devlego/pro");
exports.updateAppRole = (user, { appId } = {}) => {
    appId = appId || getAppId();
    if (!user || !user.roles) {
        return user;
    }
    // if in an multi-tenancy environment make sure roles are never updated
    if (env.MULTI_TENANCY && !isUserInAppTenant(appId, user)) {
        delete user.builder;
        delete user.admin;
        user.roleId = BUILTIN_ROLE_IDS.PUBLIC;
        return user;
    }
    // always use the deployed app
    user.roleId = user.roles[getProdAppID(appId)];
    // if a role wasn't found then either set as admin (builder) or public (everyone else)
    if (!user.roleId && user.builder && user.builder.global) {
        user.roleId = BUILTIN_ROLE_IDS.ADMIN;
    }
    else if (!user.roleId) {
        user.roleId = BUILTIN_ROLE_IDS.PUBLIC;
    }
    delete user.roles;
    return user;
};
function checkGroupRoles(user, { appId } = {}) {
    return __awaiter(this, void 0, void 0, function* () {
        if (!user.roleId) {
            let roleId = yield groups.getGroupRoleId(user, appId);
            user.roleId = roleId;
        }
        return user;
    });
}
function processUser(user, { appId } = {}) {
    var _a;
    return __awaiter(this, void 0, void 0, function* () {
        if (user) {
            delete user.password;
        }
        user = yield exports.updateAppRole(user, { appId });
        if ((_a = user === null || user === void 0 ? void 0 : user.userGroups) === null || _a === void 0 ? void 0 : _a.length) {
            user = yield checkGroupRoles(user, { appId });
        }
        return user;
    });
}
exports.getCachedSelf = (ctx, appId) => __awaiter(void 0, void 0, void 0, function* () {
    // this has to be tenant aware, can't depend on the context to find it out
    // running some middlewares before the tenancy causes context to break
    const user = yield userCache.getUser(ctx.user._id);
    return processUser(user, { appId });
});
exports.getRawGlobalUser = (userId) => __awaiter(void 0, void 0, void 0, function* () {
    const db = getGlobalDB();
    return db.get(getGlobalIDFromUserMetadataID(userId));
});
exports.getGlobalUser = (userId) => __awaiter(void 0, void 0, void 0, function* () {
    let user = yield exports.getRawGlobalUser(userId);
    return processUser(user);
});
exports.getGlobalUsers = (users = null) => __awaiter(void 0, void 0, void 0, function* () {
    const appId = getAppId();
    const db = getGlobalDB();
    let globalUsers;
    if (users) {
        const globalIds = users.map(user => getGlobalIDFromUserMetadataID(user._id));
        globalUsers = (yield db.allDocs(getMultiIDParams(globalIds))).rows.map(row => row.doc);
    }
    else {
        globalUsers = (yield db.allDocs(getGlobalUserParams(null, {
            include_docs: true,
        }))).rows.map(row => row.doc);
    }
    globalUsers = globalUsers
        .filter(user => user != null)
        .map(user => {
        delete user.password;
        delete user.forceResetPassword;
        return user;
    });
    if (!appId) {
        return globalUsers;
    }
    return globalUsers.map(user => exports.updateAppRole(user));
});
exports.getGlobalUsersFromMetadata = (users) => __awaiter(void 0, void 0, void 0, function* () {
    const globalUsers = yield exports.getGlobalUsers(users);
    return users.map(user => {
        const globalUser = globalUsers.find(globalUser => globalUser && user._id.includes(globalUser._id));
        return Object.assign(Object.assign({}, globalUser), user);
    });
});
