"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "UserService", {
    enumerable: true,
    get: function() {
        return UserService;
    }
});
const _models = require("../../models");
const _runtimeexceptions = require("../../exceptions/runtime.exceptions");
const _validators = require("../../handlers/validators");
const _userservicevalidation = require("../validators/user-service.validation");
const _authorizationconstants = require("../../constants/authorization.constants");
const _cryptoutils = require("../../utils/crypto.utils");
class UserService {
    roleService;
    constructor({ roleService }){
        this.roleService = roleService;
    }
    toDto(user) {
        return {
            id: user.id,
            createdAt: user.createdAt,
            isVerified: user.isVerified,
            isDemoUser: user.isDemoUser,
            isRootUser: user.isRootUser,
            username: user.username,
            needsPasswordChange: user.needsPasswordChange,
            roles: user.roles.map((r)=>r.toString())
        };
    }
    async listUsers(limit = 10) {
        return _models.User.find().limit(limit);
    }
    async findUsersByRoleId(roleId) {
        return _models.User.find({
            roles: {
                $in: [
                    roleId
                ]
            }
        });
    }
    async findVerifiedUsers() {
        return _models.User.find({
            isVerified: true
        });
    }
    async isUserRootUser(userId) {
        return (await _models.User.findById(userId))?.isRootUser;
    }
    async findRootUsers() {
        return _models.User.find({
            isRootUser: true
        });
    }
    async getDemoUserId() {
        return (await _models.User.findOne({
            isDemoUser: true
        }))?.id;
    }
    async findRawByUsername(username) {
        return _models.User.findOne({
            username
        });
    }
    async getUser(userId, throwNotFoundError = true) {
        const user = await _models.User.findById(userId);
        if (!user && throwNotFoundError) throw new _runtimeexceptions.NotFoundException("User not found");
        return user;
    }
    async getUserRoleIds(userId) {
        const user = await this.getUser(userId);
        return user.roles?.map((r)=>r.toString());
    }
    async setUserRoleIds(userId, roleIds) {
        const user = await _models.User.findById(userId);
        if (!user) throw new _runtimeexceptions.NotFoundException("User not found");
        const roles = this.roleService.getManyRoles(roleIds);
        user.roles = roles.map((r)=>r.id);
        user.roles = Array.from(new Set(user.roles));
        return await user.save();
    }
    async deleteUser(userId) {
        const user = await this.getUser(userId);
        if (user.isRootUser) {
            throw new _runtimeexceptions.InternalServerException("Cannot delete a root user");
        }
        const role = this.roleService.getRoleByName(_authorizationconstants.ROLES.ADMIN);
        if (user.roles.includes(role.id)) {
            const administrators = await this.findUsersByRoleId(role.id);
            if (administrators?.length === 1 && administrators[0].id === userId) {
                throw new _runtimeexceptions.InternalServerException("Cannot delete the last user with ADMIN role");
            }
        }
        await _models.User.findByIdAndDelete(user.id);
    }
    async updateUsernameById(userId, newUsername) {
        const user = await _models.User.findById(userId);
        if (!user) throw new _runtimeexceptions.NotFoundException("User not found");
        user.username = newUsername;
        return await user.save();
    }
    async updatePasswordById(userId, oldPassword, newPassword) {
        const user = await _models.User.findById(userId);
        if (!user) throw new _runtimeexceptions.NotFoundException("User not found");
        if (!(0, _cryptoutils.comparePasswordHash)(oldPassword, user.passwordHash)) {
            throw new _runtimeexceptions.NotFoundException("User old password incorrect");
        }
        const { password } = await (0, _validators.validateInput)({
            password: newPassword
        }, _userservicevalidation.newPasswordRules);
        user.passwordHash = (0, _cryptoutils.hashPassword)(password);
        user.needsPasswordChange = false;
        return await user.save();
    }
    async updatePasswordUnsafeByUsername(username, newPassword) {
        const { password } = await (0, _validators.validateInput)({
            password: newPassword
        }, _userservicevalidation.newPasswordRules);
        const passwordHash = (0, _cryptoutils.hashPassword)(password);
        const user = await this.findRawByUsername(username);
        if (!user) throw new _runtimeexceptions.NotFoundException("User not found");
        user.passwordHash = passwordHash;
        user.needsPasswordChange = false;
        return await user.save();
    }
    async setIsRootUserById(userId, isRootUser) {
        const user = await _models.User.findById(userId);
        if (!user) throw new _runtimeexceptions.NotFoundException("User not found");
        if (!isRootUser) {
            const rootUsers = await this.findRootUsers();
            if (rootUsers.length === 1 && rootUsers[0].id === userId) {
                throw new _runtimeexceptions.InternalServerException("Cannot set the last root user to non-root user");
            }
        }
        user.isRootUser = isRootUser;
        await user.save();
    }
    async setVerifiedById(userId, isVerified) {
        const user = await _models.User.findById(userId);
        if (!user) throw new _runtimeexceptions.NotFoundException("User not found");
        if (!isVerified) {
            if (user.isRootUser) {
                throw new _runtimeexceptions.InternalServerException("Cannot set a owner (root user) to unverified");
            }
            const verifiedUsers = await this.findVerifiedUsers();
            if (verifiedUsers.length === 1) {
                throw new _runtimeexceptions.InternalServerException("Cannot set the last user to unverified");
            }
        }
        user.isVerified = isVerified;
        await user.save();
    }
    async register(input) {
        const { username, password, roles, isDemoUser, isRootUser, needsPasswordChange, isVerified } = await (0, _validators.validateInput)(input, (0, _userservicevalidation.registerUserRules)(false));
        const passwordHash = (0, _cryptoutils.hashPassword)(password);
        return await _models.User.create({
            username,
            passwordHash,
            roles,
            isVerified: isVerified ?? false,
            isDemoUser: isDemoUser ?? false,
            isRootUser: isRootUser ?? false,
            needsPasswordChange: needsPasswordChange ?? true
        });
    }
}

//# sourceMappingURL=user.service.js.map