using ColaFlow.Modules.Identity.Application.Dtos; 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; namespace ColaFlow.Modules.Identity.Application.Commands.Login; public class LoginCommandHandler( ITenantRepository tenantRepository, IUserRepository userRepository, IJwtService jwtService, IPasswordHasher passwordHasher, IRefreshTokenService refreshTokenService, IUserTenantRoleRepository userTenantRoleRepository) : IRequestHandler { public async Task Handle(LoginCommand request, CancellationToken cancellationToken) { // 1. Find tenant var slug = TenantSlug.Create(request.TenantSlug); var tenant = await tenantRepository.GetBySlugAsync(slug, cancellationToken); if (tenant == null) { throw new UnauthorizedAccessException("Invalid credentials"); } // 2. Find user var email = Email.Create(request.Email); var user = await userRepository.GetByEmailAsync(TenantId.Create(tenant.Id), email, cancellationToken); if (user == null) { throw new UnauthorizedAccessException("Invalid credentials"); } // 3. Verify password if (string.IsNullOrEmpty(user.PasswordHash) || !passwordHasher.VerifyPassword(request.Password, user.PasswordHash)) { throw new UnauthorizedAccessException("Invalid credentials"); } // 4. Get user's tenant role var userTenantRole = await userTenantRoleRepository.GetByUserAndTenantAsync( user.Id, tenant.Id, cancellationToken); if (userTenantRole is null) { throw new InvalidOperationException($"User {user.Id} has no role assigned for tenant {tenant.Id}"); } // 5. Generate JWT token with role var accessToken = jwtService.GenerateToken(user, tenant, userTenantRole.Role); // 6. Generate refresh token var refreshToken = await refreshTokenService.GenerateRefreshTokenAsync( user, ipAddress: null, userAgent: null, cancellationToken); // 7. Update last login time user.RecordLogin(); await userRepository.UpdateAsync(user, cancellationToken); // 8. Return result return new LoginResponseDto { User = new UserDto { Id = user.Id, TenantId = tenant.Id, Email = user.Email.Value, FullName = user.FullName.Value, Status = user.Status.ToString(), AuthProvider = user.AuthProvider.ToString(), IsEmailVerified = user.EmailVerifiedAt.HasValue, LastLoginAt = user.LastLoginAt, CreatedAt = user.CreatedAt }, Tenant = new 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 }, AccessToken = accessToken, RefreshToken = refreshToken }; } }