var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
    return function (target, key) { decorator(target, key, paramIndex); }
};
import { Arg, Ctx, Field, InputType, Mutation, ObjectType, registerEnumType } from 'type-graphql';
import { LogError, Metadata, RunView } from '@memberjunction/core';
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
let SyncRolesAndUsersResultType = class SyncRolesAndUsersResultType {
    Success;
};
__decorate([
    Field(() => Boolean),
    __metadata("design:type", Boolean)
], SyncRolesAndUsersResultType.prototype, "Success", void 0);
SyncRolesAndUsersResultType = __decorate([
    ObjectType()
], SyncRolesAndUsersResultType);
export { SyncRolesAndUsersResultType };
let RoleInputType = class RoleInputType {
    ID;
    Name;
    Description;
};
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], RoleInputType.prototype, "ID", void 0);
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], RoleInputType.prototype, "Name", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], RoleInputType.prototype, "Description", void 0);
RoleInputType = __decorate([
    InputType()
], RoleInputType);
export { RoleInputType };
export var UserType;
(function (UserType) {
    UserType["Owner"] = "Owner";
    UserType["User"] = "User";
})(UserType || (UserType = {}));
registerEnumType(UserType, {
    name: "UserType",
    description: "Defines whether a user is an Owner or a User",
});
let UserInputType = class UserInputType {
    ID;
    Name;
    Email;
    Type;
    FirstName;
    LastName;
    Title;
    Roles;
};
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], UserInputType.prototype, "ID", void 0);
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], UserInputType.prototype, "Name", void 0);
__decorate([
    Field(() => String),
    __metadata("design:type", String)
], UserInputType.prototype, "Email", void 0);
__decorate([
    Field(() => UserType),
    __metadata("design:type", String)
], UserInputType.prototype, "Type", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UserInputType.prototype, "FirstName", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UserInputType.prototype, "LastName", void 0);
__decorate([
    Field(() => String, { nullable: true }),
    __metadata("design:type", String)
], UserInputType.prototype, "Title", void 0);
__decorate([
    Field(() => [RoleInputType], { nullable: true }),
    __metadata("design:type", Array)
], UserInputType.prototype, "Roles", void 0);
UserInputType = __decorate([
    InputType()
], UserInputType);
export { UserInputType };
let RolesAndUsersInputType = class RolesAndUsersInputType {
    Users;
    Roles;
};
__decorate([
    Field(() => [UserInputType]),
    __metadata("design:type", Array)
], RolesAndUsersInputType.prototype, "Users", void 0);
__decorate([
    Field(() => [RoleInputType]),
    __metadata("design:type", Array)
], RolesAndUsersInputType.prototype, "Roles", void 0);
RolesAndUsersInputType = __decorate([
    InputType()
], RolesAndUsersInputType);
export { RolesAndUsersInputType };
export class SyncRolesAndUsersResolver {
    async SyncRolesAndUsers(data, context) {
        try {
            const roleResult = await this.SyncRoles(data.Roles, context);
            if (roleResult?.Success) {
                const usersResult = await this.SyncUsers(data.Users, context);
                if (usersResult?.Success) {
                    await UserCache.Instance.Refresh(context.dataSource);
                }
                return usersResult;
            }
            else {
                return roleResult;
            }
        }
        catch (err) {
            LogError(err);
            throw new Error('Error syncing roles and users\n\n' + err);
        }
    }
    async SyncRoles(roles, context) {
        try {
            const rv = new RunView();
            const result = await rv.RunView({
                EntityName: "Roles",
                ResultType: 'entity_object'
            }, context.userPayload.userRecord);
            if (result && result.Success) {
                const currentRoles = result.Results;
                if (await this.DeleteRemovedRoles(currentRoles, roles, context.userPayload.userRecord, context.userPayload)) {
                    if (await this.AddNewRoles(currentRoles, roles, context.userPayload.userRecord, context.userPayload)) {
                        return await this.UpdateExistingRoles(currentRoles, roles, context.userPayload);
                    }
                }
            }
            return { Success: false };
        }
        catch (err) {
            LogError(err);
            throw new Error('Error syncing roles and users\n\n' + err);
        }
    }
    async UpdateExistingRoles(currentRoles, futureRoles, userPayload) {
        const md = new Metadata();
        let ok = true;
        for (const update of futureRoles) {
            const currentRole = currentRoles.find(r => r.Name.trim().toLowerCase() === update.Name.trim().toLowerCase());
            if (currentRole) {
                currentRole.Description = update.Description;
                ok = ok && await currentRole.Save();
            }
        }
        return { Success: ok };
    }
    async AddNewRoles(currentRoles, futureRoles, user, userPayload) {
        const md = new Metadata();
        let ok = true;
        for (const add of futureRoles) {
            if (!currentRoles.find(r => r.Name.trim().toLowerCase() === add.Name.trim().toLowerCase())) {
                const role = await md.GetEntityObject("Roles", user);
                role.Name = add.Name;
                role.Description = add.Description;
                ok = ok && await role.Save();
            }
        }
        return ok;
    }
    async DeleteRemovedRoles(currentRoles, futureRoles, user, userPayload) {
        const rv = new RunView();
        let ok = true;
        for (const remove of currentRoles) {
            if (!this.IsStandardRole(remove.Name)) {
                if (!futureRoles.find(r => r.Name.trim().toLowerCase() === remove.Name.trim().toLowerCase())) {
                    ok = ok && await this.DeleteSingleRole(remove, rv, user, userPayload);
                }
            }
        }
        return ok;
    }
    get StandardRoles() {
        return ['Developer', 'Integration', 'UI'];
    }
    IsStandardRole(roleName) {
        return this.StandardRoles.find(r => r.toLowerCase() === roleName.toLowerCase()) !== undefined;
    }
    async DeleteSingleRole(role, rv, user, userPayload) {
        let ok = true;
        const r2 = await rv.RunView({
            EntityName: "User Roles",
            ExtraFilter: "RoleID = '" + role.ID + "'",
            ResultType: 'entity_object'
        }, user);
        if (r2.Success) {
            for (const ur of r2.Results) {
                ok = ok && await ur.Delete();
            }
        }
        return ok && role.Delete();
    }
    async SyncUsers(users, context) {
        try {
            const rv = new RunView();
            const result = await rv.RunView({
                EntityName: "Users",
                ResultType: 'entity_object'
            }, context.userPayload.userRecord);
            if (result && result.Success) {
                const currentUsers = result.Results;
                if (await this.DeleteRemovedUsers(currentUsers, users, context.userPayload.userRecord, context.userPayload)) {
                    if (await this.AddNewUsers(currentUsers, users, context.userPayload)) {
                        if (await this.UpdateExistingUsers(currentUsers, users, context.userPayload)) {
                            if (await this.SyncUserRoles(users, context.userPayload.userRecord, context.userPayload)) {
                                return { Success: true };
                            }
                        }
                    }
                }
            }
            return { Success: false };
        }
        catch (err) {
            LogError(err);
            throw new Error('Error syncing roles and users\n\n' + err);
        }
    }
    async UpdateExistingUsers(currentUsers, futureUsers, userPayload) {
        let ok = true;
        for (const update of futureUsers) {
            const current = currentUsers.find(c => c.Email?.trim().toLowerCase() === update.Email?.trim().toLowerCase());
            if (current) {
                current.Name = update.Name;
                current.Type = update.Type;
                current.FirstName = update.FirstName;
                current.LastName = update.LastName;
                current.Title = update.Title;
                ok = ok && await current.Save();
            }
        }
        return ok;
    }
    async AddNewUsers(currentUsers, futureUsers, userPayload) {
        const md = new Metadata();
        let ok = true;
        for (const add of futureUsers) {
            const match = currentUsers.find(currentUser => currentUser.Email?.trim().toLowerCase() === add.Email?.trim().toLowerCase());
            if (match) {
                match.IsActive = true;
                ok = ok && await match.Save();
            }
            else {
                const user = await md.GetEntityObject("Users", userPayload.userRecord);
                user.Name = add.Name;
                user.Type = add.Type;
                user.Email = add.Email;
                user.FirstName = add.FirstName;
                user.LastName = add.LastName;
                user.Title = add.Title;
                user.IsActive = true;
                ok = ok && await user.Save();
            }
        }
        return ok;
    }
    async DeleteRemovedUsers(currentUsers, futureUsers, u, userPayload) {
        const rv = new RunView();
        const md = new Metadata();
        let ok = true;
        for (const remove of currentUsers) {
            if (remove.Type.trim().toLowerCase() !== 'owner') {
                if (!futureUsers.find(r => r.Email.trim().toLowerCase() === remove.Email.trim().toLowerCase())) {
                    ok = ok && await this.DeleteSingleUser(remove, rv, u, userPayload);
                }
            }
        }
        return ok;
    }
    async DeleteSingleUser(user, rv, u, userPayload) {
        let ok = true;
        const r2 = await rv.RunView({
            EntityName: "User Roles",
            ExtraFilter: "UserID = '" + user.ID + "'",
            ResultType: 'entity_object'
        }, u);
        if (r2.Success) {
            for (const ur of r2.Results) {
                ok = ok && await ur.Delete();
            }
        }
        if (await user.Delete()) {
            return ok;
        }
        else {
            user.IsActive = false;
            return await user.Save() && ok;
        }
    }
    async SyncUserRoles(users, u, userPayload) {
        const rv = new RunView();
        const md = new Metadata();
        const p1 = rv.RunView({
            EntityName: "Users",
            ResultType: 'entity_object'
        }, u);
        const p2 = rv.RunView({
            EntityName: "Roles",
            ResultType: 'entity_object'
        }, u);
        const p3 = rv.RunView({
            EntityName: "User Roles",
            ResultType: 'entity_object'
        }, u);
        const [uResult, rResult, urResult] = await Promise.all([p1, p2, p3]);
        if (uResult.Success && rResult.Success && urResult.Success) {
            const dbUsers = uResult.Results;
            const dbRoles = rResult.Results;
            const dbUserRoles = urResult.Results;
            let ok = true;
            for (const user of users) {
                const dbUser = dbUsers.find(u => u.Email.trim().toLowerCase() === user.Email.trim().toLowerCase());
                if (dbUser) {
                    for (const role of user.Roles) {
                        const dbRole = dbRoles.find(r => r.Name.trim().toLowerCase() === role.Name.trim().toLowerCase());
                        if (dbRole) {
                            if (!dbUserRoles.find(ur => ur.UserID === dbUser.ID && ur.RoleID === dbRole.ID)) {
                                const ur = await md.GetEntityObject("User Roles", u);
                                ur.UserID = dbUser.ID;
                                ur.RoleID = dbRole.ID;
                                ok = ok && await ur.Save();
                            }
                        }
                    }
                    const thisUserDBRoles = dbUserRoles.filter(ur => ur.UserID === dbUser.ID);
                    for (const dbUserRole of thisUserDBRoles) {
                        const role = user.Roles.find(r => r.Name.trim().toLowerCase() === dbRoles.find(rr => rr.ID === dbUserRole.RoleID)?.Name.trim().toLowerCase());
                        if (!role && !this.IsStandardRole(dbUserRole.Role)) {
                            ok = ok && await dbUserRole.Delete();
                        }
                    }
                }
            }
            return ok;
        }
        else {
            return false;
        }
    }
}
__decorate([
    RequireSystemUser(),
    Mutation(() => SyncRolesAndUsersResultType),
    __param(0, Arg('data', () => RolesAndUsersInputType)),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [RolesAndUsersInputType, Object]),
    __metadata("design:returntype", Promise)
], SyncRolesAndUsersResolver.prototype, "SyncRolesAndUsers", null);
__decorate([
    RequireSystemUser(),
    Mutation(() => SyncRolesAndUsersResultType),
    __param(0, Arg('roles', () => [RoleInputType])),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Object]),
    __metadata("design:returntype", Promise)
], SyncRolesAndUsersResolver.prototype, "SyncRoles", null);
__decorate([
    RequireSystemUser(),
    Mutation(() => SyncRolesAndUsersResultType),
    __param(0, Arg('users', () => [UserInputType])),
    __param(1, Ctx()),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", [Array, Object]),
    __metadata("design:returntype", Promise)
], SyncRolesAndUsersResolver.prototype, "SyncUsers", null);
//# sourceMappingURL=SyncRolesUsersResolver.js.map