using System; using System.Collections.Generic; using System.Threading.Tasks; using DysonNetwork.Common.Models; using DysonNetwork.Pass.Data; using DysonNetwork.Pass.Features.Auth.Models; using Microsoft.EntityFrameworkCore; using NodaTime; using Account = DysonNetwork.Common.Models.Account; using AuthTokens = DysonNetwork.Common.Models.AuthTokens; namespace DysonNetwork.Pass.Features.Auth.Services; public class AccountService : IAccountService { private readonly PassDatabase _db; private readonly IClock _clock; public AccountService(PassDatabase db, IClock clock) { _db = db; _clock = clock; } public async Task CreateAccount(Common.Models.OidcUserInfo userInfo) { if (string.IsNullOrEmpty(userInfo.Email)) throw new ArgumentException("Email is required for account creation", nameof(userInfo)); var now = _clock.GetCurrentInstant(); var account = new Models.Account { Id = Guid.NewGuid(), Email = userInfo.Email, Name = userInfo.Name ?? userInfo.Email.Split('@')[0], CreatedAt = now, UpdatedAt = now, Status = "Active" }; _db.Accounts.Add(account); await _db.SaveChangesAsync(); return new Account { Id = account.Id.ToString(), Email = account.Email, Name = account.Name, CreatedAt = account.CreatedAt, UpdatedAt = account.UpdatedAt, Status = account.Status }; } public async Task FindByEmailAsync(string email) { if (string.IsNullOrEmpty(email)) return null; var account = await _db.Accounts .FirstOrDefaultAsync(a => a.Email == email); if (account == null) return null; return new Account { Id = account.Id.ToString(), Email = account.Email, Name = account.Name, CreatedAt = account.CreatedAt, UpdatedAt = account.UpdatedAt, Status = account.Status }; } public async Task FindByIdAsync(string accountId) { if (string.IsNullOrEmpty(accountId) || !Guid.TryParse(accountId, out var id)) return null; var account = await _db.Accounts .FirstOrDefaultAsync(a => a.Id == id); if (account == null) return null; return new Account { Id = account.Id.ToString(), Email = account.Email, Name = account.Name, CreatedAt = account.CreatedAt, UpdatedAt = account.UpdatedAt, Status = account.Status }; } public async Task UpdateAccount(Account account) { if (!Guid.TryParse(account.Id, out var id)) throw new ArgumentException("Invalid account ID format", nameof(account)); var existingAccount = await _db.Accounts.FindAsync(id); if (existingAccount == null) throw new InvalidOperationException($"Account with ID {account.Id} not found"); existingAccount.Name = account.Name; existingAccount.Email = account.Email; existingAccount.UpdatedAt = _clock.GetCurrentInstant(); existingAccount.Status = account.Status; _db.Accounts.Update(existingAccount); await _db.SaveChangesAsync(); } public async Task FindOrCreateAccountAsync(Common.Models.OidcUserInfo userInfo, string provider) { if (string.IsNullOrEmpty(userInfo.Email)) throw new ArgumentException("Email is required for account creation", nameof(userInfo)); // Check if account exists by email var account = await FindByEmailAsync(userInfo.Email); if (account != null) return account; // Create new account if not found return await CreateAccount(userInfo); } public async Task GetAccountByIdAsync(Guid accountId) { var account = await _db.Accounts .FirstOrDefaultAsync(a => a.Id == accountId); if (account == null) return null; return new Account { Id = account.Id.ToString(), Email = account.Email, Name = account.Name, CreatedAt = account.CreatedAt, UpdatedAt = account.UpdatedAt, Status = account.Status }; } public async Task GenerateAuthTokensAsync(Account account, string sessionId) { if (!Guid.TryParse(sessionId, out var sessionGuid)) throw new ArgumentException("Invalid session ID format", nameof(sessionId)); var now = _clock.GetCurrentInstant(); var accessTokenLifetime = Duration.FromHours(1); var accessTokenExpiry = now.Plus(accessTokenLifetime); // In a real implementation, you would generate proper JWT tokens here // This is a simplified version for demonstration var accessToken = $"access_token_{Guid.NewGuid()}"; var refreshToken = $"refresh_token_{Guid.NewGuid()}"; // Create or update the session var session = await _db.AuthSessions.FindAsync(sessionGuid); if (session != null) { session.UpdateTokens(accessToken, refreshToken, accessTokenLifetime); _db.AuthSessions.Update(session); await _db.SaveChangesAsync(); } return new AuthTokens { AccessToken = accessToken, RefreshToken = refreshToken, ExpiresIn = (int)accessTokenLifetime.TotalSeconds, TokenType = "Bearer" }; } }