using ColaFlow.Modules.Identity.Application.Commands.SendVerificationEmail; using ColaFlow.Modules.Identity.Application.Services; using ColaFlow.Modules.Identity.Domain.Aggregates.Tenants; using ColaFlow.Modules.Identity.Domain.Aggregates.Users; using ColaFlow.Modules.Identity.Domain.Repositories; using MediatR; using Microsoft.Extensions.Configuration; namespace ColaFlow.Modules.Identity.Application.Commands.RegisterTenant; public class RegisterTenantCommandHandler( ITenantRepository tenantRepository, IUserRepository userRepository, IJwtService jwtService, IPasswordHasher passwordHasher, IRefreshTokenService refreshTokenService, IUserTenantRoleRepository userTenantRoleRepository, IMediator mediator, IConfiguration configuration) : IRequestHandler { public async Task Handle( RegisterTenantCommand request, CancellationToken cancellationToken) { // 1. Validate slug uniqueness var slug = TenantSlug.Create(request.TenantSlug); var slugExists = await tenantRepository.ExistsBySlugAsync(slug, cancellationToken); if (slugExists) { throw new InvalidOperationException($"Tenant slug '{request.TenantSlug}' is already taken"); } // 2. Create tenant var plan = Enum.Parse(request.SubscriptionPlan); var tenant = Tenant.Create( TenantName.Create(request.TenantName), slug, plan); await tenantRepository.AddAsync(tenant, cancellationToken); // 3. Create admin user with hashed password var hashedPassword = passwordHasher.HashPassword(request.AdminPassword); var adminUser = User.CreateLocal( TenantId.Create(tenant.Id), Email.Create(request.AdminEmail), hashedPassword, FullName.Create(request.AdminFullName)); await userRepository.AddAsync(adminUser, cancellationToken); // 4. Assign TenantOwner role to admin user var tenantOwnerRole = UserTenantRole.Create( UserId.Create(adminUser.Id), TenantId.Create(tenant.Id), TenantRole.TenantOwner); await userTenantRoleRepository.AddAsync(tenantOwnerRole, cancellationToken); // 5. Generate JWT token with role var accessToken = jwtService.GenerateToken(adminUser, tenant, TenantRole.TenantOwner); // 6. Generate refresh token var refreshToken = await refreshTokenService.GenerateRefreshTokenAsync( adminUser, ipAddress: null, userAgent: null, cancellationToken); // 7. Send verification email (non-blocking) var baseUrl = configuration["App:BaseUrl"] ?? "http://localhost:3000"; var sendEmailCommand = new SendVerificationEmailCommand( adminUser.Id, request.AdminEmail, baseUrl); // Fire and forget - don't wait for email to send _ = mediator.Send(sendEmailCommand, cancellationToken); // 8. Return result return new RegisterTenantResult( new Dtos.TenantDto { Id = tenant.Id, Name = tenant.Name.Value, Slug = tenant.Slug.Value, Status = tenant.Status.ToString(), Plan = tenant.Plan.ToString(), SsoEnabled = tenant.SsoConfig != null, SsoProvider = tenant.SsoConfig?.Provider.ToString(), CreatedAt = tenant.CreatedAt, UpdatedAt = tenant.UpdatedAt ?? tenant.CreatedAt }, new Dtos.UserDto { Id = adminUser.Id, TenantId = tenant.Id, Email = adminUser.Email.Value, FullName = adminUser.FullName.Value, Status = adminUser.Status.ToString(), AuthProvider = adminUser.AuthProvider.ToString(), IsEmailVerified = adminUser.EmailVerifiedAt.HasValue, CreatedAt = adminUser.CreatedAt }, accessToken, refreshToken); } }