using System.Security.Cryptography; using System.Text; using FlowAPI.Application.DTOs.User; using FlowAPI.Application.Interfaces; using FlowAPI.Domain.Entities; using Microsoft.Extensions.Configuration; namespace FlowAPI.Application.Services { public class UserService : IUserService { private readonly IUserRepository _repo; private readonly ITokenService _tokenService; private readonly IConfiguration _config; private readonly IAchievementService _achievementService; public UserService(IUserRepository repo, ITokenService tokenService, IConfiguration config, IAchievementService achievementService) { _repo = repo; _tokenService = tokenService; _config = config; _achievementService = achievementService; } public async Task> GetAllAsync() { var users = await _repo.GetAllAsync(); return users.Select(MapToDto); } public async Task GetByIdAsync(Guid id) { var user = await _repo.GetByIdAsync(id); return user is null ? null : MapToDto(user); } public async Task RegisterAsync(CreateUserDto dto) { var existing = await _repo.GetByEmailAsync(dto.Email); if (existing is not null) throw new InvalidOperationException("User with this email already exists."); var user = new User { Id = Guid.NewGuid(), Email = dto.Email, PasswordHash = HashPassword(dto.Password), DisplayName = dto.DisplayName, CreatedAt = DateTime.UtcNow }; var created = await _repo.CreateAsync(user); return new AuthResponseDto { User = MapToDto(created), Token = _tokenService.CreateToken(created) }; } public async Task LoginAsync(LoginDto dto) { var user = await _repo.GetByEmailAsync(dto.Email); if (user is null || string.IsNullOrEmpty(user.PasswordHash) || user.PasswordHash != HashPassword(dto.Password)) return null; return new AuthResponseDto { User = MapToDto(user), Token = _tokenService.CreateToken(user) }; } public async Task GoogleLoginAsync(GoogleLoginDto dto) { var settings = new Google.Apis.Auth.GoogleJsonWebSignature.ValidationSettings { Audience = new List { _config["Google:ClientId"]! } }; var payload = await Google.Apis.Auth.GoogleJsonWebSignature.ValidateAsync(dto.IdToken, settings); var user = await _repo.GetByEmailAsync(payload.Email); if (user == null) { user = new User { Id = Guid.NewGuid(), Email = payload.Email, DisplayName = payload.Name, CreatedAt = DateTime.UtcNow, PasswordHash = "" // No password for Google users }; user = await _repo.CreateAsync(user); } return new AuthResponseDto { User = MapToDto(user), Token = _tokenService.CreateToken(user) }; } public async Task UpdateAsync(Guid id, UpdateUserDto dto) { var user = await _repo.GetByIdAsync(id); if (user is null) return null; bool isAvatarUpdated = dto.AvatarUrl is not null && user.AvatarUrl != dto.AvatarUrl; if (dto.DisplayName is not null) user.DisplayName = dto.DisplayName; if (dto.IsPremium.HasValue) user.IsPremium = dto.IsPremium.Value; if (dto.AvatarUrl is not null) user.AvatarUrl = dto.AvatarUrl; if (dto.SubscriptionTier is not null) { user.SubscriptionTier = dto.SubscriptionTier; user.IsPremium = dto.SubscriptionTier != "Free"; } if (!string.IsNullOrEmpty(dto.Password)) user.PasswordHash = HashPassword(dto.Password); var updated = await _repo.UpdateAsync(user); if (isAvatarUpdated) { await _achievementService.ProcessEventAsync(id, "AvatarUploaded"); } return MapToDto(updated); } public async Task DeleteAsync(Guid id) { return await _repo.DeleteAsync(id); } private static string HashPassword(string password) { var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(password)); return Convert.ToBase64String(bytes); } private static UserResponseDto MapToDto(User user) => new() { Id = user.Id, Email = user.Email, DisplayName = user.DisplayName, IsPremium = user.IsPremium, AvatarUrl = user.AvatarUrl, CreatedAt = user.CreatedAt, SubscriptionTier = user.SubscriptionTier, DailyAiGenerationsCount = user.DailyAiGenerationsCount }; } }