"use strict";
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); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.RoleService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const role_entity_1 = require("../entities/role.entity");
const tenant_1 = require("../../tenant");
let RoleService = class RoleService {
    roleRepository;
    tenantService;
    constructor(roleRepository, tenantService) {
        this.roleRepository = roleRepository;
        this.tenantService = tenantService;
    }
    async createRole(name, guard, tenantId = null, isSystem = false, permissionIds) {
        tenantId = await this.tenantService.resolveTenantId(tenantId);
        const existingRole = await this.roleRepository.findOne({
            where: {
                name,
                guard,
                tenantId: tenantId || (0, typeorm_2.IsNull)()
            },
        });
        if (existingRole) {
            throw new common_1.ConflictException({
                message: `Role with name '${name}' already exists in guard '${guard}'${tenantId ? ` for tenant '${tenantId}'` : ''}`,
                code: 'ROLE_ALREADY_EXISTS'
            });
        }
        const role = await role_entity_1.NestAuthRole.createRole(name, guard, isSystem, tenantId);
        if (permissionIds) {
            await role.syncPermissions(permissionIds);
        }
        await this.roleRepository.save(role);
        return role;
    }
    async getRoleById(id, options) {
        if (!id) {
            return null;
        }
        const role = await this.roleRepository.findOne({
            ...(options ? options : {}),
            where: { id }
        });
        if (!role) {
            return null;
        }
        return role;
    }
    async getRoleByName(name, guard, tenantId, options) {
        const systemRole = await this.roleRepository.findOne({
            ...(options ? options : {}),
            where: {
                name,
                ...(guard ? { guard } : {}),
                isSystem: true
            }
        });
        if (systemRole) {
            return systemRole;
        }
        const role = await this.roleRepository.findOne({
            ...(options ? options : {}),
            where: {
                name,
                ...(guard ? { guard } : {}),
                ...(tenantId ? { tenantId } : { tenantId: (0, typeorm_2.IsNull)() })
            }
        });
        return role;
    }
    async getSystemRoles(options) {
        return this.roleRepository.find({
            ...(options ? options : {}),
            where: {
                isSystem: true,
                tenantId: (0, typeorm_2.IsNull)(),
                ...(options?.where ? options.where : {})
            },
            order: {
                name: 'ASC'
            }
        });
    }
    async getRoles(params = {}, options) {
        const { guard, onlyTenantRoles, onlySystemRoles } = params;
        let { tenantId } = params;
        if (!onlySystemRoles) {
            tenantId = await this.tenantService.resolveTenantId(tenantId);
        }
        const query = this.roleRepository.createQueryBuilder();
        if (guard) {
            query.andWhere(`${query.alias}.guard = :guard`, { guard });
        }
        if (onlySystemRoles) {
            query.andWhere(`${query.alias}.isSystem = :isSystem`, { isSystem: true });
        }
        else if (onlyTenantRoles) {
            if (!tenantId) {
                return [];
            }
            query.andWhere(`${query.alias}.tenantId = :tenantId`, { tenantId });
        }
        else {
            if (tenantId) {
                query.andWhere(new typeorm_2.Brackets(qb => {
                    qb.where(`${query.alias}.tenantId = :tenantId`, { tenantId })
                        .orWhere(`${query.alias}.isSystem = :isSystem`, { isSystem: true });
                }));
            }
            else {
                query.andWhere(`${query.alias}.isSystem = :isSystem`, { isSystem: true });
            }
        }
        if (options) {
            if (options.where) {
                query.andWhere(options.where);
            }
            if (options.order) {
                Object.entries(options.order).forEach(([key, value]) => {
                    query.addOrderBy(`${query.alias}.${key}`, value);
                });
            }
        }
        else {
            query.orderBy(`${query.alias}.name`, 'ASC');
        }
        query.take(1000);
        return query.getMany();
    }
    async updateRole(id, data) {
        const role = await this.getRoleById(id);
        if (!role) {
            throw new common_1.NotFoundException({
                message: `Role with ID ${id} not found`,
                code: 'ROLE_NOT_FOUND'
            });
        }
        delete data.isSystem;
        delete data.tenantId;
        if (data.name && data.name !== role.name) {
            throw new common_1.BadRequestException({
                message: 'Cannot update role name. Please delete and create a new role if you need to change the name.',
                code: 'ROLE_NAME_UPDATE_NOT_ALLOWED'
            });
        }
        if (data.guard && data.guard !== role.guard) {
            throw new common_1.BadRequestException({
                message: 'Cannot update role guard. Please delete and create a new role if you need to change the guard.',
                code: 'ROLE_GUARD_UPDATE_NOT_ALLOWED'
            });
        }
        delete data.name;
        delete data.guard;
        Object.assign(role, data);
        return this.roleRepository.save(role);
    }
    async updateRolePermissions(id, permissionIds) {
        const role = await this.getRoleById(id);
        if (!role) {
            throw new common_1.NotFoundException({
                message: `Role with ID ${id} not found`,
                code: 'ROLE_NOT_FOUND'
            });
        }
        await role.syncPermissions(permissionIds);
        return this.roleRepository.save(role);
    }
    async deleteRole(id) {
        const role = await this.getRoleById(id);
        if (!role) {
            throw new common_1.NotFoundException({
                message: `Role with ID ${id} not found`,
                code: 'ROLE_NOT_FOUND'
            });
        }
        await this.roleRepository.remove(role);
    }
};
exports.RoleService = RoleService;
exports.RoleService = RoleService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(role_entity_1.NestAuthRole)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        tenant_1.TenantService])
], RoleService);
//# sourceMappingURL=role.service.js.map