File size: 12,314 Bytes
4433399
1a7e978
7fe61c9
1a7e978
 
c312181
 
1a7e978
 
7fe61c9
1a7e978
 
 
 
 
 
6f32ae8
 
7fe61c9
 
b8cc5e6
25f925e
7fe61c9
ad67295
6f32ae8
1a7e978
 
 
 
 
 
 
 
 
 
 
 
ec76476
 
 
 
 
 
 
 
1a7e978
 
 
 
 
 
 
 
 
 
 
6f32ae8
1a7e978
 
 
6f32ae8
1a7e978
 
 
 
 
 
 
 
6f32ae8
1a7e978
 
 
 
 
6f32ae8
1a7e978
 
 
 
 
 
 
 
 
6f32ae8
 
1a7e978
 
 
 
 
 
 
 
6f32ae8
1a7e978
 
 
6f32ae8
 
1a7e978
 
6f32ae8
 
 
ad67295
 
 
 
 
1a7e978
6f32ae8
1a7e978
 
 
 
6f32ae8
1a7e978
 
 
7fe61c9
 
 
 
 
 
 
6f32ae8
7fe61c9
 
 
 
 
ec76476
6f32ae8
ad67295
7fe61c9
6f32ae8
7fe61c9
 
 
 
6f32ae8
7fe61c9
 
 
 
 
 
 
ec76476
7fe61c9
 
6f32ae8
ec76476
 
7fe61c9
 
 
ec76476
 
 
 
 
7fe61c9
 
 
 
 
 
6f32ae8
7fe61c9
 
6f32ae8
ec76476
 
 
 
 
 
 
7fe61c9
 
 
ec76476
 
 
 
 
7fe61c9
 
25f925e
 
 
 
6f32ae8
25f925e
 
6f32ae8
ec76476
 
 
 
 
 
 
25f925e
 
 
 
 
6f32ae8
25f925e
 
 
 
7fe61c9
 
 
 
6f32ae8
ec76476
 
 
 
 
7fe61c9
 
ec76476
 
 
 
 
7fe61c9
ad67295
 
 
 
 
6f32ae8
ad67295
 
6f32ae8
 
ad67295
 
 
 
 
6f32ae8
ad67295
 
 
 
6f32ae8
ad67295
6f32ae8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1a7e978
 
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
using LibraryManagement.Shared.Models;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using System.Linq;

namespace Backend.Features.Loyalty
{
    public interface ILoyaltyService
    {
        Task<bool> RegisterUserAsync(string externalUserId, string email, string mobile);
        Task<bool> ProcessEventAsync(string externalUserId, string eventKey, double eventValue, string? referenceId = null, string? description = null, string? email = null, string? mobile = null);
        Task<LoyaltyAccountDto?> GetUserAccountAsync(string externalUserId);
        Task<(bool Success, string Message)> ClaimRewardAsync(string externalUserId, string rewardId, string notes);
        Task<IEnumerable<LoyaltyRedemptionDto>> GetPendingRedemptionsAsync();
        Task<IEnumerable<LoyaltyRedemptionDto>> GetUserRedemptionsAsync(string externalUserId);
        Task<IEnumerable<LoyaltyRedemptionDto>> GetRedemptionsHistoryAsync();
        Task<bool> UpdateRedemptionStatusAsync(string redemptionId, string status);
        Task<IEnumerable<PointHistoryEntryDto>> GetPointsHistoryAsync(string accountId);
        Task<IEnumerable<LoyaltyRewardDto>> GetActiveRewardsAsync();
    }

    public class LoyaltyService : ILoyaltyService
    {
        private readonly HttpClient _httpClient;
        private readonly ILogger<LoyaltyService> _logger;
        private const string SystemId = "THS-LMS";

        public LoyaltyService(HttpClient httpClient, ILogger<LoyaltyService> logger)
        {
            _httpClient = httpClient;
            _logger = logger;
            _httpClient.DefaultRequestHeaders.Remove("x-system-id");
            _httpClient.DefaultRequestHeaders.Add("x-system-id", SystemId);
        }

        private class LoyaltyResponseWrapper<T>
        {
            [JsonPropertyName("items")]
            public IEnumerable<T> Items { get; set; } = Enumerable.Empty<T>();
        }

        public async Task<bool> RegisterUserAsync(string externalUserId, string email, string mobile)
        {
            try
            {
                var payload = new
                {
                    externalUserId = externalUserId,
                    email = email,
                    mobile = mobile,
                    systemId = SystemId
                };

                var response = await _httpClient.PostAsJsonAsync("/api/v1/accounts", payload);
                return response.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error registering user in loyalty system.");
                return false;
            }
        }

        public async Task<bool> ProcessEventAsync(string externalUserId, string eventKey, double eventValue, string? referenceId = null, string? description = null, string? email = null, string? mobile = null)
        {
            try
            {
                var payload = new
                {
                    systemId = SystemId,
                    externalUserId = externalUserId,
                    eventKey = eventKey,
                    eventValue = eventValue,
                    referenceId = referenceId,
                    description = description,
                    email = email,
                    mobile = mobile
                };

                var response = await _httpClient.PostAsJsonAsync($"/api/v1/events/process?systemId={SystemId}", payload);
                return response.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error processing loyalty event {eventKey}.");
                return false;
            }
        }

        public async Task<LoyaltyAccountDto?> GetUserAccountAsync(string externalUserId)
        {
            try
            {
                var response = await _httpClient.GetAsync($"/api/v1/accounts/lookup/{externalUserId}?systemId={SystemId}");
                
                if (response.IsSuccessStatusCode)
                {
                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
                    var account = await response.Content.ReadFromJsonAsync<LoyaltyAccountDto>(options);
                    
                    if (account != null && string.IsNullOrWhiteSpace(account.Id) && !string.IsNullOrWhiteSpace(account.AccountId))
                    {
                        account.Id = account.AccountId;
                    }
                    return account;
                }
                
                return null;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error looking up loyalty account for {externalUserId}.");
                return null;
            }
        }

        public async Task<(bool Success, string Message)> ClaimRewardAsync(string externalUserId, string rewardId, string notes)
        {
            try
            {
                var payload = new
                {
                    systemId = SystemId,
                    externalUserId = externalUserId,
                    rewardId = rewardId,
                    notes = notes
                };

                var response = await _httpClient.PostAsJsonAsync($"/api/v1/redemptions/claim?systemId={SystemId}", payload);
                if (response.IsSuccessStatusCode) return (true, "Reward claimed successfully!");

                var error = await response.Content.ReadAsStringAsync();
                return (false, error);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error while claiming reward.");
                return (false, "An error occurred.");
            }
        }

        public async Task<IEnumerable<LoyaltyRedemptionDto>> GetUserRedemptionsAsync(string externalUserId)
        {
            try
            {
                var response = await _httpClient.GetAsync($"/api/v1/redemptions/history/{externalUserId}?systemId={SystemId}");
                if (response.IsSuccessStatusCode)
                {
                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
                    var wrapper = await response.Content.ReadFromJsonAsync<LoyaltyResponseWrapper<LoyaltyRedemptionDto>>(options);
                    return wrapper?.Items ?? Enumerable.Empty<LoyaltyRedemptionDto>();
                }
                return Enumerable.Empty<LoyaltyRedemptionDto>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error fetching user redemptions for {externalUserId}.");
                return Enumerable.Empty<LoyaltyRedemptionDto>();
            }
        }

        public async Task<IEnumerable<LoyaltyRedemptionDto>> GetPendingRedemptionsAsync()
        {
            try
            {
                var response = await _httpClient.GetAsync($"/api/v1/admin/redemptions/pending?systemId={SystemId}");
                if (response.IsSuccessStatusCode)
                {
                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
                    var wrapper = await response.Content.ReadFromJsonAsync<LoyaltyResponseWrapper<LoyaltyRedemptionDto>>(options);
                    return wrapper?.Items ?? Enumerable.Empty<LoyaltyRedemptionDto>();
                }
                else
                {
                    var content = await response.Content.ReadAsStringAsync();
                    _logger.LogWarning($"Failed to fetch pending redemptions. Status: {response.StatusCode}, Content: {content}");
                }
                return Enumerable.Empty<LoyaltyRedemptionDto>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching pending redemptions.");
                return Enumerable.Empty<LoyaltyRedemptionDto>();
            }
        }

        public async Task<IEnumerable<LoyaltyRedemptionDto>> GetRedemptionsHistoryAsync()
        {
            try
            {
                var response = await _httpClient.GetAsync($"/api/v1/admin/redemptions/history?systemId={SystemId}");
                if (response.IsSuccessStatusCode)
                {
                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
                    var wrapper = await response.Content.ReadFromJsonAsync<LoyaltyResponseWrapper<LoyaltyRedemptionDto>>(options);
                    return wrapper?.Items ?? Enumerable.Empty<LoyaltyRedemptionDto>();
                }
                else
                {
                    var content = await response.Content.ReadAsStringAsync();
                    _logger.LogWarning($"Failed to fetch redemption history. Status: {response.StatusCode}, Content: {content}");
                }
                return Enumerable.Empty<LoyaltyRedemptionDto>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching redemption history.");
                return Enumerable.Empty<LoyaltyRedemptionDto>();
            }
        }

        public async Task<bool> UpdateRedemptionStatusAsync(string redemptionId, string status)
        {
            try
            {
                var response = await _httpClient.PutAsJsonAsync($"/api/v1/admin/redemptions/{redemptionId}/status?systemId={SystemId}", new { systemId = SystemId, status });
                if (!response.IsSuccessStatusCode)
                {
                    var content = await response.Content.ReadAsStringAsync();
                    _logger.LogWarning($"Failed to update redemption status. Status: {response.StatusCode}, Content: {content}");
                }
                return response.IsSuccessStatusCode;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error updating redemption status for {redemptionId}.");
                return false;
            }
        }

        public async Task<IEnumerable<PointHistoryEntryDto>> GetPointsHistoryAsync(string accountId)
        {
            try
            {
                var response = await _httpClient.GetAsync($"/api/v1/accounts/{accountId}/history?systemId={SystemId}");
                if (response.IsSuccessStatusCode)
                {
                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
                    return await response.Content.ReadFromJsonAsync<IEnumerable<PointHistoryEntryDto>>(options) ?? Enumerable.Empty<PointHistoryEntryDto>();
                }
                return Enumerable.Empty<PointHistoryEntryDto>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error fetching points history for {accountId}.");
                return Enumerable.Empty<PointHistoryEntryDto>();
            }
        }

        public async Task<IEnumerable<LoyaltyRewardDto>> GetActiveRewardsAsync()
        {
            try
            {
                var response = await _httpClient.GetAsync($"/api/v1/rewards/active?systemId={SystemId}");
                
                if (response.IsSuccessStatusCode)
                {
                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true, NumberHandling = JsonNumberHandling.AllowReadingFromString };
                    return await response.Content.ReadFromJsonAsync<IEnumerable<LoyaltyRewardDto>>(options) ?? Enumerable.Empty<LoyaltyRewardDto>();
                }
                return Enumerable.Empty<LoyaltyRewardDto>();
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "Error fetching active rewards.");
                return Enumerable.Empty<LoyaltyRewardDto>();
            }
        }
    }
}