"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.PermissionService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const event_emitter_1 = require("@nestjs/event-emitter");
const permission_entity_1 = require("../entities/permission.entity");
const auth_constants_1 = require("../../auth.constants");
const auth_config_service_1 = require("../../core/services/auth-config.service");
const permission_created_event_1 = require("../events/permission-created.event");
const permission_updated_event_1 = require("../events/permission-updated.event");
const permission_deleted_event_1 = require("../events/permission-deleted.event");
let PermissionService = class PermissionService {
    permissionRepository;
    authConfigService;
    eventEmitter;
    constructor(permissionRepository, authConfigService, eventEmitter) {
        this.permissionRepository = permissionRepository;
        this.authConfigService = authConfigService;
        this.eventEmitter = eventEmitter;
    }
    getDefaultRoleGuard() {
        return this.authConfigService.getRoleGuards()[0] ?? auth_constants_1.DEFAULT_GUARD_NAME;
    }
    resolveAndValidateGuard(guard) {
        const resolved = guard ?? this.getDefaultRoleGuard();
        if (!this.authConfigService.isRoleGuardAllowed(resolved)) {
            throw new common_1.BadRequestException({
                message: `Guard '${resolved}' is not allowed. Allowed guards: ${this.authConfigService.getRoleGuards().join(', ')}`,
                code: auth_constants_1.GUARD_ERROR_CODES.GUARD_NOT_ALLOWED,
            });
        }
        return resolved;
    }
    async createPermission(data) {
        const guard = this.resolveAndValidateGuard(data.guard);
        const existing = await this.permissionRepository.findOne({
            where: { name: data.name.trim(), guard },
        });
        if (existing) {
            throw new common_1.ConflictException(`Permission '${data.name}' with guard '${guard}' already exists`);
        }
        const permission = this.permissionRepository.create({
            name: data.name.trim(),
            guard,
            description: data.description?.trim(),
            category: data.category?.trim(),
        });
        const saved = await this.permissionRepository.save(permission);
        await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.PERMISSION_CREATED, new permission_created_event_1.PermissionCreatedEvent({ permission: saved }));
        return saved;
    }
    async getPermissions(options) {
        const query = this.permissionRepository.createQueryBuilder('permission');
        if (options?.search) {
            query.where('(permission.name LIKE :search OR permission.description LIKE :search)', { search: `%${options.search}%` });
        }
        if (options?.category) {
            query.andWhere('permission.category = :category', { category: options.category });
        }
        if (options?.guard) {
            query.andWhere('permission.guard = :guard', { guard: options.guard });
        }
        query.orderBy('permission.name', 'ASC');
        if (options?.limit) {
            query.limit(options.limit);
        }
        return query.getMany();
    }
    async getPermissionByName(name, guard) {
        return this.permissionRepository.findOne({
            where: { name, guard: guard || auth_constants_1.DEFAULT_GUARD_NAME },
        });
    }
    async getPermissionsByGuard(guard) {
        return this.permissionRepository.find({
            where: { guard },
            order: { name: 'ASC' },
        });
    }
    async getGuards() {
        const result = await this.permissionRepository
            .createQueryBuilder('permission')
            .select('DISTINCT permission.guard', 'guard')
            .getRawMany();
        return result.map(r => r.guard).filter(Boolean).sort();
    }
    async getPermissionById(id) {
        const permission = await this.permissionRepository.findOne({
            where: { id },
        });
        if (!permission) {
            throw new common_1.NotFoundException(`Permission with id ${id} not found`);
        }
        return permission;
    }
    async updatePermission(id, data) {
        const permission = await this.permissionRepository.findOne({
            where: { id },
        });
        if (!permission) {
            throw new common_1.NotFoundException(`Permission with id ${id} not found`);
        }
        if (data.name !== undefined) {
            const newName = data.name.trim();
            if (!newName) {
                throw new common_1.BadRequestException('Permission name is required');
            }
            if (newName !== permission.name) {
                const existing = await this.permissionRepository.findOne({
                    where: { name: newName, guard: permission.guard },
                });
                if (existing) {
                    throw new common_1.ConflictException(`Permission '${newName}' with guard '${permission.guard}' already exists`);
                }
                permission.name = newName;
            }
        }
        if (data.description !== undefined) {
            permission.description = data.description?.trim() || null;
        }
        if (data.category !== undefined) {
            permission.category = data.category?.trim() || null;
        }
        const saved = await this.permissionRepository.save(permission);
        await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.PERMISSION_UPDATED, new permission_updated_event_1.PermissionUpdatedEvent({ permission: saved, updatedFields: Object.keys(data ?? {}) }));
        return saved;
    }
    async deletePermission(id) {
        const permission = await this.getPermissionById(id);
        await this.permissionRepository.remove(permission);
        await this.eventEmitter.emitAsync(auth_constants_1.NestAuthEvents.PERMISSION_DELETED, new permission_deleted_event_1.PermissionDeletedEvent({ permission }));
    }
    async searchPermissions(query, guard, limit = 20) {
        const whereConditions = [
            { name: (0, typeorm_2.Like)(`%${query}%`) },
            { description: (0, typeorm_2.Like)(`%${query}%`) },
        ];
        if (guard) {
            whereConditions.forEach(condition => {
                condition.guard = guard;
            });
        }
        return this.permissionRepository.find({
            where: whereConditions,
            take: limit,
            order: { name: 'ASC' },
        });
    }
    async getCategories() {
        const result = await this.permissionRepository
            .createQueryBuilder('permission')
            .select('DISTINCT permission.category', 'category')
            .where('permission.category IS NOT NULL')
            .getRawMany();
        return result.map(r => r.category).filter(Boolean).sort();
    }
    async createPermissions(permissions) {
        const existingPermissions = await this.permissionRepository.find();
        const existingKeySet = new Set(existingPermissions.map((p) => `${p.name}-${p.guard}`));
        const toCreatePermissions = permissions.filter(p => !existingKeySet.has(`${p.name}-${p.guard}`));
        if (toCreatePermissions.length === 0) {
            return existingPermissions;
        }
        const newPermissions = this.permissionRepository.create(toCreatePermissions.map(p => ({
            name: p.name.trim(),
            description: p.description?.trim(),
            guard: p.guard || auth_constants_1.DEFAULT_GUARD_NAME,
            category: p.category?.trim(),
            metadata: p.metadata || {},
        })));
        const saved = await this.permissionRepository.save(newPermissions);
        return [...existingPermissions, ...saved];
    }
};
exports.PermissionService = PermissionService;
exports.PermissionService = PermissionService = __decorate([
    (0, common_1.Injectable)(),
    __param(0, (0, typeorm_1.InjectRepository)(permission_entity_1.NestAuthPermission)),
    __metadata("design:paramtypes", [typeorm_2.Repository,
        auth_config_service_1.AuthConfigService,
        event_emitter_1.EventEmitter2])
], PermissionService);
//# sourceMappingURL=permission.service.js.map