"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
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());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
    return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadAccountMethods = loadAccountMethods;
var handlebars = require("handlebars");
var jwt = require("jsonwebtoken");
var simpl_schema_1 = require("simpl-schema");
var user_collection_1 = require("../collections/user.collection");
var resolveio_server_app_1 = require("../resolveio-server-app");
var common_1 = require("../util/common");
var customer_portal_password_1 = require("../util/customer-portal-password");
var error_reporter_1 = require("../util/error-reporter");
function loadAccountMethods(methodManager) {
    methodManager.methods({
        incorrectUser: {
            check: new simpl_schema_1.default({
                old_user: {
                    type: Object,
                    blackbox: true
                },
                new_user: {
                    type: Object,
                    blackbox: true
                },
                client_subs: {
                    type: Array
                },
                'client_subs.$': {
                    type: Object,
                    blackbox: true
                }
            }),
            function: function (old_user, new_user, client_subs) {
                return __awaiter(this, void 0, void 0, function () {
                    var ws, correlationId;
                    var _a;
                    return __generator(this, function (_b) {
                        switch (_b.label) {
                            case 0:
                                if (!resolveio_server_app_1.ResolveIOServer.getMainServer()) return [3 /*break*/, 2];
                                ws = resolveio_server_app_1.ResolveIOServer.getMainServer().getWebSocketManager().getWebSocket(this.id_ws);
                                correlationId = (0, common_1.objectIdHexString)();
                                return [4 /*yield*/, error_reporter_1.ErrorReporter.report({
                                        sourceApp: 'method-accounts',
                                        message: 'SERVER - WRONG USER Detected - ' + this.serverConfig['CLIENT_NAME'],
                                        environment: (_a = this.serverConfig) === null || _a === void 0 ? void 0 : _a.ROOT_URL,
                                        clientSlug: resolveio_server_app_1.ResolveIOServer.getClientName(),
                                        clientName: this.serverConfig['CLIENT_NAME'],
                                        context: {
                                            ws: ws,
                                            userMethod: this.user,
                                            id_user: this.id_user,
                                            activeSubs: resolveio_server_app_1.ResolveIOServer.getMainServer().getSubscriptionManager().getActiveSubscriptions(),
                                            old_user: old_user,
                                            new_user: new_user,
                                            client_subs: client_subs
                                        },
                                        metadata: {
                                            context: 'incorrectUser',
                                            correlationId: correlationId
                                        },
                                        correlationId: correlationId
                                    })];
                            case 1:
                                _b.sent();
                                _b.label = 2;
                            case 2: return [2 /*return*/, Promise.resolve(null)];
                        }
                    });
                });
            }
        },
        reloadWS: {
            check: new simpl_schema_1.default({
                id_ws: String
            }),
            function: function (id_ws) {
                return __awaiter(this, void 0, void 0, function () {
                    var ws;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                ws = resolveio_server_app_1.ResolveIOServer.getMainServer().getWebSocketManager().getWebSocket(id_ws);
                                if (!ws) return [3 /*break*/, 2];
                                return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().unsubscribeWS(ws)];
                            case 1:
                                _a.sent();
                                return [2 /*return*/, true];
                            case 2: throw new Error('Error in Reload WS: No WS');
                        }
                    });
                });
            }
        },
        reconnectWS: {
            check: new simpl_schema_1.default({
                id_ws: String
            }),
            function: function (id_ws) {
                return __awaiter(this, void 0, void 0, function () {
                    var ws;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                ws = resolveio_server_app_1.ResolveIOServer.getMainServer().getWebSocketManager().getWebSocket(id_ws);
                                if (!ws) return [3 /*break*/, 2];
                                return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().unsubscribeWS(ws)];
                            case 1:
                                _a.sent();
                                return [2 /*return*/, true];
                            case 2: throw new Error('Error in Reconnect WS: No WS');
                        }
                    });
                });
            }
        },
        disconnectWS: {
            check: new simpl_schema_1.default({
                id_ws: String
            }),
            function: function (id_ws) {
                return __awaiter(this, void 0, void 0, function () {
                    var ws;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                ws = resolveio_server_app_1.ResolveIOServer.getMainServer().getWebSocketManager().getWebSocket(id_ws);
                                if (!ws) return [3 /*break*/, 2];
                                return [4 /*yield*/, resolveio_server_app_1.ResolveIOServer.getMainServer().unsubscribeWS(ws)];
                            case 1:
                                _a.sent();
                                return [2 /*return*/, true];
                            case 2: throw new Error('Error in Disconnect WS: No WS');
                        }
                    });
                });
            }
        },
        createUserAndEmailEnrollment: {
            check: new simpl_schema_1.default({
                newUser: {
                    type: user_collection_1.Users['simplschema']
                },
                sendEnrollmentEmail: {
                    type: Boolean,
                    optional: true
                }
            }),
            function: function (newUser_1) {
                return __awaiter(this, arguments, void 0, function (newUser, sendEnrollmentEmail) {
                    var otherUser, emailData, html, template, err_1;
                    if (sendEnrollmentEmail === void 0) { sendEnrollmentEmail = true; }
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0:
                                if (!(newUser.username.toLocaleLowerCase() === 'admin')) return [3 /*break*/, 1];
                                throw new Error('Error in Create User And Email Enrollment: Username can not be admin');
                            case 1: return [4 /*yield*/, user_collection_1.Users.findOne({
                                    $or: [
                                        { username: newUser.username.toLocaleLowerCase() },
                                        { email: newUser.email.toLocaleLowerCase() }
                                    ]
                                })];
                            case 2:
                                otherUser = _a.sent();
                                if (otherUser) {
                                    throw new Error('Error in Create User And Email Enrollment: Username/Email is already used');
                                }
                                _a.label = 3;
                            case 3:
                                newUser._id = (0, common_1.objectIdHexString)();
                                newUser.services = {
                                    enrollment: jwt.sign({ id_user: newUser._id }, this.serverConfig['JWT_SECRET'], {
                                        expiresIn: 3 * 24 * 60 * 60 * 1000 // 3 days
                                    })
                                };
                                newUser.is_customer = false;
                                return [4 /*yield*/, user_collection_1.Users.insertOne(newUser)];
                            case 4:
                                _a.sent();
                                if (!sendEnrollmentEmail) return [3 /*break*/, 9];
                                emailData = {
                                    fullname: newUser.fullname,
                                    user: this.user,
                                    url: (this.serverConfig['ROOT_URL'] + '/enroll-account?' + encodeURIComponent(this.serverConfig['SERVER_URL']) + '&' + newUser.services['enrollment'])
                                };
                                _a.label = 5;
                            case 5:
                                _a.trys.push([5, 7, , 8]);
                                html = this.readFile('email-templates/enrollment.html');
                                template = handlebars.compile(html);
                                handlebars.registerHelper('equals', function (a, b) {
                                    return a === b;
                                });
                                return [4 /*yield*/, this.sendEmail(newUser.email, 'ResolveIO (' + resolveio_server_app_1.ResolveIOServer.getClientName() + ') - Enrollment Email', '', template(emailData), null, null, '')];
                            case 6:
                                _a.sent();
                                return [2 /*return*/, newUser];
                            case 7:
                                err_1 = _a.sent();
                                err_1.message = "Error in Create User And Email Enrollment: email-templates/enrollment.html - ".concat(err_1.message);
                                throw err_1;
                            case 8: return [3 /*break*/, 10];
                            case 9: return [2 /*return*/, newUser];
                            case 10: return [2 /*return*/];
                        }
                    });
                });
            }
        },
        resetUserPassword: {
            check: new simpl_schema_1.default({
                userId: {
                    type: String
                }
            }),
            function: function (userId) {
                return __awaiter(this, void 0, void 0, function () {
                    var user, emailData, html, template, err_2;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, user_collection_1.Users.findOne({ _id: userId })];
                            case 1:
                                user = _a.sent();
                                if (!user) return [3 /*break*/, 6];
                                if (!user.services) {
                                    user.services = {};
                                }
                                user.services['forgot_password'] = jwt.sign({ id_user: userId }, this.serverConfig['JWT_SECRET']);
                                emailData = {
                                    userToChangePassword: user.fullname,
                                    userWhoResetPassword: this.user,
                                    url: (this.serverConfig['ROOT_URL'] + '/forgot-password?' + encodeURIComponent(this.serverConfig['SERVER_URL']) + '&' + user.services['forgot_password'])
                                };
                                _a.label = 2;
                            case 2:
                                _a.trys.push([2, 5, , 6]);
                                return [4 /*yield*/, user_collection_1.Users.updateOne({ _id: user._id }, { $set: { services: user.services, attempts: 0 } })];
                            case 3:
                                _a.sent();
                                html = this.readFile('email-templates/forgot-password.html');
                                template = handlebars.compile(html);
                                handlebars.registerHelper('equals', function (a, b) {
                                    return a === b;
                                });
                                return [4 /*yield*/, this.sendEmail(user.email, 'ResolveIO (' + resolveio_server_app_1.ResolveIOServer.getClientName() + ') - Forgot Password', '', template(emailData), null, null, '')];
                            case 4:
                                _a.sent();
                                return [2 /*return*/, true];
                            case 5:
                                err_2 = _a.sent();
                                err_2.message = "Error in Reset User Password: email-templates/forgot-password.html - ".concat(err_2.message);
                                throw err_2;
                            case 6: throw new Error('Error in Reset User Password: Invalid User');
                        }
                    });
                });
            }
        },
        setUserPassword: {
            check: new simpl_schema_1.default({
                userId: {
                    type: String
                },
                password: {
                    type: String
                }
            }),
            function: function (userId, password) {
                return __awaiter(this, void 0, void 0, function () {
                    var user;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, user_collection_1.Users.findOne({ _id: userId })];
                            case 1:
                                user = _a.sent();
                                if (!(user && !user.roles.super_admin)) return [3 /*break*/, 4];
                                return [4 /*yield*/, user_collection_1.Users.setPassword(user, password)];
                            case 2:
                                _a.sent();
                                return [4 /*yield*/, (0, customer_portal_password_1.saveCustomerPortalPassword)(user, password, {
                                        updatedByUserId: this.id_user,
                                        updatedByUser: this.user
                                    })];
                            case 3:
                                _a.sent();
                                return [2 /*return*/, true];
                            case 4: throw new Error('Error in Set User Password: Invalid User');
                        }
                    });
                });
            }
        },
        getCustomerPortalUserPassword: {
            check: new simpl_schema_1.default({
                userId: {
                    type: String
                }
            }),
            function: function (userId) {
                return __awaiter(this, void 0, void 0, function () {
                    var methodUser, targetUser, result;
                    return __generator(this, function (_a) {
                        switch (_a.label) {
                            case 0: return [4 /*yield*/, resolveMethodUser(this.id_user, this.user)];
                            case 1:
                                methodUser = _a.sent();
                                if (!canViewCustomerPortalPasswords(methodUser)) {
                                    throw new Error('Error in Get Customer Portal User Password: Unauthorized');
                                }
                                return [4 /*yield*/, user_collection_1.Users.findOne({ _id: userId })];
                            case 2:
                                targetUser = _a.sent();
                                if (!targetUser) {
                                    throw new Error('Error in Get Customer Portal User Password: Invalid User');
                                }
                                if (!(0, customer_portal_password_1.isCustomerPortalUser)(targetUser)) {
                                    throw new Error('Error in Get Customer Portal User Password: User is not a customer portal user');
                                }
                                return [4 /*yield*/, (0, customer_portal_password_1.getDecryptedCustomerPortalPassword)(userId)];
                            case 3:
                                result = _a.sent();
                                return [2 /*return*/, {
                                        password: result.password,
                                        last_set_at: result.lastSetAt || null
                                    }];
                        }
                    });
                });
            }
        },
        saveUserStickySelects: {
            check: new simpl_schema_1.default({
                stickySelects: {
                    type: Array
                },
                'stickySelects.$': {
                    type: Object,
                    blackbox: true
                },
                id_user: {
                    type: String,
                    optional: true
                }
            }),
            function: function (stickySelects, id_user) {
                return __awaiter(this, void 0, void 0, function () {
                    var targetUserId, attempts, mergedStickySelects, nextVersion, user, nextUser, res;
                    var _a;
                    return __generator(this, function (_b) {
                        switch (_b.label) {
                            case 0:
                                targetUserId = id_user || this.id_user;
                                if (!targetUserId) {
                                    throw new Error('Error in Save User Sticky Selects: Invalid User');
                                }
                                attempts = 0;
                                mergedStickySelects = [];
                                nextVersion = 0;
                                _b.label = 1;
                            case 1:
                                if (!(attempts < 5)) return [3 /*break*/, 4];
                                return [4 /*yield*/, user_collection_1.Users.findOne({ _id: targetUserId })];
                            case 2:
                                user = _b.sent();
                                if (!user) {
                                    throw new Error('Error in Save User Sticky Selects: Invalid User');
                                }
                                mergedStickySelects = mergeStickySelects((_a = user.other) === null || _a === void 0 ? void 0 : _a.stickySelects, stickySelects);
                                nextUser = (0, common_1.deepCopy)(user);
                                nextUser.other = __assign(__assign({}, (nextUser.other || {})), { stickySelects: mergedStickySelects });
                                return [4 /*yield*/, user_collection_1.Users.replaceOne({ _id: nextUser._id, __v: user.__v }, nextUser, {}, false, false, user)];
                            case 3:
                                res = _b.sent();
                                if (res && res.modifiedCount) {
                                    nextVersion = (user.__v || 0) + 1;
                                    return [3 /*break*/, 4];
                                }
                                attempts += 1;
                                return [3 /*break*/, 1];
                            case 4:
                                if (attempts >= 5) {
                                    throw new Error('Error in Save User Sticky Selects: Could not acquire latest version');
                                }
                                return [2 /*return*/, {
                                        stickySelects: mergedStickySelects,
                                        __v: nextVersion
                                    }];
                        }
                    });
                });
            }
        }
    });
}
function mergeStickySelects(existingList, incomingList) {
    var _a;
    var existingMap = new Map();
    if (Array.isArray(existingList)) {
        existingList.forEach(function (entry) {
            var normalized = normalizeStickyPreference(entry);
            if (normalized && normalized.key) {
                existingMap.set(normalized.key, normalized);
            }
        });
    }
    var _loop_1 = function (i) {
        var normalized = normalizeStickyPreference(incomingList[i]);
        if (!normalized || !normalized.key) {
            return "continue";
        }
        var prev = existingMap.get(normalized.key);
        var mergedOptions = trimOptions(normalized.options && normalized.options.length
            ? mergeOptions((prev === null || prev === void 0 ? void 0 : prev.options) || [], normalized.options)
            : ((prev === null || prev === void 0 ? void 0 : prev.options) || []));
        var defaultValue = normalized.defaultValue !== undefined ? normalized.defaultValue : (prev ? prev.defaultValue : null);
        if (defaultValue === undefined) {
            defaultValue = null;
        }
        var defaultLabel = cleanStickyLabel(normalized.defaultLabel);
        if (!defaultLabel && (prev === null || prev === void 0 ? void 0 : prev.defaultLabel)) {
            defaultLabel = cleanStickyLabel(prev.defaultLabel);
        }
        if (defaultValue !== null && !defaultLabel) {
            var optionLabel = ((_a = mergedOptions.find(function (opt) { return valuesMatch(opt.value, defaultValue, !!normalized.multiple); })) === null || _a === void 0 ? void 0 : _a.label) || '';
            defaultLabel = cleanStickyLabel(optionLabel);
        }
        existingMap.set(normalized.key, {
            key: normalized.key,
            defaultValue: defaultValue,
            defaultLabel: defaultLabel,
            multiple: normalized.multiple !== undefined ? normalized.multiple : !!(prev === null || prev === void 0 ? void 0 : prev.multiple),
            options: mergedOptions,
            updatedAt: new Date().toISOString()
        });
    };
    for (var i = 0; i < incomingList.length; i++) {
        _loop_1(i);
    }
    return Array.from(existingMap.values());
}
function mergeOptions(existing, incoming) {
    var map = new Map();
    normalizeStickyOptions(existing).forEach(function (opt) {
        var key = buildOptionKey(opt.value);
        map.set(key, opt);
    });
    normalizeStickyOptions(incoming).forEach(function (opt) {
        var key = buildOptionKey(opt.value);
        map.set(key, opt);
    });
    return Array.from(map.values());
}
function trimOptions(options) {
    if (!Array.isArray(options)) {
        return [];
    }
    if (options.length <= STICKY_MAX_OPTIONS) {
        return options;
    }
    return options.slice(0, STICKY_MAX_OPTIONS);
}
function normalizeStickyPreference(entry) {
    if (!entry || !entry.key) {
        return null;
    }
    var normalized = {
        key: "".concat(entry.key),
        defaultValue: entry.defaultValue !== undefined ? entry.defaultValue : null,
        defaultLabel: cleanStickyLabel(entry.defaultLabel),
        multiple: !!entry.multiple,
        options: normalizeStickyOptions(entry.options),
        updatedAt: entry.updatedAt
    };
    return normalized;
}
function normalizeStickyOptions(options) {
    if (Array.isArray(options)) {
        return options
            .map(function (opt) { return normalizeStickyOption(opt); })
            .filter(function (opt) { return !!opt; });
    }
    if (options && typeof options === 'object') {
        return Object.keys(options)
            .sort()
            .map(function (key) { return normalizeStickyOption(options[key]); })
            .filter(function (opt) { return !!opt; });
    }
    return [];
}
function normalizeStickyOption(option) {
    if (!option || option.value === undefined) {
        return null;
    }
    return {
        value: option.value,
        label: cleanStickyLabel(option.label)
    };
}
function cleanStickyLabel(label) {
    if (!label) {
        return '';
    }
    var trimmed = "".concat(label).trim();
    if (!trimmed || trimmed.toLowerCase() === 'loading...') {
        return '';
    }
    return trimmed;
}
function buildOptionKey(value) {
    if (value === null) {
        return 'null';
    }
    if (value === undefined) {
        return 'undefined';
    }
    if (typeof value === 'object') {
        try {
            return JSON.stringify(value);
        }
        catch (_a) {
            return "".concat(value);
        }
    }
    return "".concat(value);
}
function valuesMatch(a, b, multiple) {
    if (multiple) {
        var arrA = Array.isArray(a) ? a : [];
        var arrB_1 = Array.isArray(b) ? b : [];
        if (arrA.length !== arrB_1.length) {
            return false;
        }
        return arrA.every(function (item) { return arrB_1.some(function (candidate) { return buildOptionKey(candidate) === buildOptionKey(item); }); });
    }
    return buildOptionKey(a) === buildOptionKey(b);
}
var STICKY_MAX_OPTIONS = 200;
function resolveMethodUser(id_user, username) {
    return __awaiter(this, void 0, void 0, function () {
        var userById, userByUsername;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    if (!id_user) return [3 /*break*/, 2];
                    return [4 /*yield*/, user_collection_1.Users.findById(id_user)];
                case 1:
                    userById = _a.sent();
                    if (userById) {
                        return [2 /*return*/, userById];
                    }
                    _a.label = 2;
                case 2:
                    if (!username) return [3 /*break*/, 4];
                    return [4 /*yield*/, user_collection_1.Users.findOne({ username: username })];
                case 3:
                    userByUsername = _a.sent();
                    if (userByUsername) {
                        return [2 /*return*/, userByUsername];
                    }
                    _a.label = 4;
                case 4: return [2 /*return*/, null];
            }
        });
    });
}
function canViewCustomerPortalPasswords(user) {
    if (!user || !user.roles) {
        return false;
    }
    if (user.roles.super_admin) {
        return true;
    }
    var groups = Array.isArray(user.roles.groups) ? user.roles.groups : [];
    return groups.some(function (group) { return Array.isArray(group === null || group === void 0 ? void 0 : group.views) && group.views.includes('/admin/customer-user'); });
}

//# sourceMappingURL=accounts.js.map
