using Modules.User.Domain.Gateways; namespace Modules.User.Domain.Entities.Account; public class Account { public Guid Id { get; private set; } public Email Email { get; private set; } public string HashedPassword { get; private set; } private List _sessions = []; public IReadOnlyList Sessions => _sessions.AsReadOnly(); public Account(Models.Account model) { Id = model.Id; Email = new Email(model.Email); HashedPassword = model.HashedPassword; _sessions = model.Sessions.Select(q => new Session(q)).ToList(); } private Account(Email email, string hashedPassword) { Email = email; HashedPassword = hashedPassword; } public static Account Create(string email, string password, IPasswordGateway passwordHasher) { if (string.IsNullOrWhiteSpace(email)) throw new ArgumentNullException(nameof(email)); if (string.IsNullOrWhiteSpace(password)) throw new ArgumentNullException(nameof(password)); var account = new Account(new Email(email), passwordHasher.HashPassword(password)); return account; } public void SetEmail(string email) { if (string.IsNullOrWhiteSpace(email)) throw new ArgumentNullException(nameof(email)); Email = new Email(email); } public void SetPassword(string password, IPasswordGateway passwordHasher) { var newPasswordHash = passwordHasher.HashPassword(password); if (newPasswordHash != HashedPassword) throw new Exception("Password must not be aqual to previous"); HashedPassword = newPasswordHash; } public Session AddSession(TimeSpan expirationTime, IRefreshTokenGateway gateway, string? userAgent, string? country, string? city) { if (Id == Guid.Empty) throw new ArgumentNullException(nameof(Id)); ClearExpiredSessions(); var sessionCollisions = FindSessions(userAgent); var session = Session.Create(Id, expirationTime, gateway, userAgent, country, city); if (sessionCollisions.Any()) { session.SetId(sessionCollisions.OrderBy(q => q.ExpiredDate).Last().Id); _sessions = _sessions.Where(q => !sessionCollisions.Contains(q)).ToList(); } _sessions.Add(session); return session; } public string? UpdateRefreshToken(Guid sessionId, IRefreshTokenGateway gateway, TimeSpan expirationTime, string? userAgent, string? country, string? city) { ClearExpiredSessions(); var session = _sessions.FirstOrDefault(s => s.Id == sessionId); if (session == null) return null; return session.UpdateRefreshToken(gateway, expirationTime, userAgent, country, city); } private IEnumerable FindSessions(string? userAgent) => _sessions.Where(q => q.ClientInfo.UserAgent == userAgent); public bool DeleteSession(Guid sessionId) { var session = _sessions.FirstOrDefault(s => s.Id == sessionId); if (session == null) return false; _sessions.Remove(session); return true; } public void ClearExpiredSessions() => _sessions = _sessions.Where(q => q.ExpiredDate >= DateTime.UtcNow).ToList(); public void ClearAllSessions() => _sessions.Clear(); }