File size: 5,410 Bytes
b9c7f0e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7039b6a
 
 
 
 
35321eb
b9c7f0e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7039b6a
67d4c53
 
b9c7f0e
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
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<IEnumerable<UserResponseDto>> GetAllAsync()
        {
            var users = await _repo.GetAllAsync();
            return users.Select(MapToDto);
        }

        public async Task<UserResponseDto?> GetByIdAsync(Guid id)
        {
            var user = await _repo.GetByIdAsync(id);
            return user is null ? null : MapToDto(user);
        }

        public async Task<AuthResponseDto> 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<AuthResponseDto?> 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<AuthResponseDto> GoogleLoginAsync(GoogleLoginDto dto)
        {
            var settings = new Google.Apis.Auth.GoogleJsonWebSignature.ValidationSettings
            {
                Audience = new List<string> { _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<UserResponseDto?> 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<bool> 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
        };
    }
}