using ColaFlow.Modules.Identity.Domain.Aggregates.Users; using ColaFlow.Modules.Identity.Domain.Aggregates.Users.Events; using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants; using ColaFlow.Modules.Identity.Domain.Repositories; using MediatR; namespace ColaFlow.Modules.Identity.Application.Commands.AssignUserRole; public class AssignUserRoleCommandHandler : IRequestHandler { private readonly IUserTenantRoleRepository _userTenantRoleRepository; private readonly IUserRepository _userRepository; private readonly ITenantRepository _tenantRepository; public AssignUserRoleCommandHandler( IUserTenantRoleRepository userTenantRoleRepository, IUserRepository userRepository, ITenantRepository tenantRepository) { _userTenantRoleRepository = userTenantRoleRepository; _userRepository = userRepository; _tenantRepository = tenantRepository; } public async Task Handle(AssignUserRoleCommand request, CancellationToken cancellationToken) { // Validate user exists var user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken); if (user == null) throw new InvalidOperationException("User not found"); // Validate tenant exists var tenant = await _tenantRepository.GetByIdAsync(TenantId.Create(request.TenantId), cancellationToken); if (tenant == null) throw new InvalidOperationException("Tenant not found"); // Parse and validate role if (!Enum.TryParse(request.Role, out var role)) throw new ArgumentException($"Invalid role: {request.Role}"); // Prevent manual assignment of AIAgent role if (role == TenantRole.AIAgent) throw new InvalidOperationException("AIAgent role cannot be assigned manually"); // Check if user already has a role in this tenant var existingRole = await _userTenantRoleRepository.GetByUserAndTenantAsync( request.UserId, request.TenantId, cancellationToken); TenantRole? previousRole = existingRole?.Role; if (existingRole != null) { // Update existing role existingRole.UpdateRole(role, request.AssignedBy); await _userTenantRoleRepository.UpdateAsync(existingRole, cancellationToken); } else { // Create new role assignment var userTenantRole = UserTenantRole.Create( UserId.Create(request.UserId), TenantId.Create(request.TenantId), role, UserId.Create(request.AssignedBy)); await _userTenantRoleRepository.AddAsync(userTenantRole, cancellationToken); } // Raise domain event for role assignment user.RaiseRoleAssignedEvent( TenantId.Create(request.TenantId), role, previousRole, request.AssignedBy ); // Save changes to persist event await _userRepository.UpdateAsync(user, cancellationToken); return Unit.Value; } }