using AMPBLL.ApiRequestSubscriber; using AmpDAL.CustomCode.ApiRequestSubscriber; using AmpDAL.DTO.ApiRequestSubscriber; using GB5Shared.DTO.Framework.Login; using GB5Shared.EventLogPublish; using GB5Shared.GB5Constant; using GB5Shared.GenerateAutoNumber; using GB5Shared.Resource.Response; using Microsoft.Extensions.Logging; public class ApiRequestSubscriberBLL( IApiRequestSubscriberDAL _dal, AutoNumber _autoNumber, EventLogPublish _eventLog, ILogger _logger ) : IApiRequestSubscriberBLL { public async Task> GetSubscribersAsync( int apiRequestId, LoginDTO login, CancellationToken ct) { // ✅ Guard if (apiRequestId == 0) throw new ArgumentException("ApiRequestId must be a positive number."); try { return await _dal.GetByRequestAsync(apiRequestId, login.ClientId, login, ct) .ConfigureAwait(false); } catch (Exception ex) { _logger.LogError(ex, "GetSubscribers failed for ApiRequestId {ApiRequestId}", apiRequestId); throw; } } public async Task SubscribeAsync( ApiRequestSubscriberSaveDTO dto, LoginDTO login, CancellationToken ct) { // ✅ Guards if (dto.ApiRequestId == 0) throw new ArgumentException("ApiRequestId must be a positive number."); if (dto.SubscriberUserId == 0) throw new ArgumentException("SubscriberUserId must be a positive number."); try { dto.TenantId = login.ClientId; dto.CreatedById = login.UserId; // ✅ Duplicate subscription guard var existing = await _dal.GetByRequestAsync(dto.ApiRequestId, login.ClientId, login, ct) .ConfigureAwait(false); if (existing.Any(s => s.SubscriberUserId == dto.SubscriberUserId)) { _logger.LogWarning( "Subscribe skipped — already subscribed. ApiRequestId {ApiRequestId} | UserId {UserId}", dto.ApiRequestId, dto.SubscriberUserId); return $"Already subscribed to ApiRequestId {dto.ApiRequestId}"; } // ✅ GetNumberAsync — consistent with rest of system var autoNumberDto = await _autoNumber.GetNumberAsync(1, "MAPIREQUESTSUBSCRIBER", login) .ConfigureAwait(false); dto.SubscriberId = autoNumberDto.StartNumber; await _dal.SaveSubscriberAsync(dto, login, ct).ConfigureAwait(false); try { await _eventLog.PublishEventLogAsync( "AMP Request Subscriber Added", new { dto.ApiRequestId, dto.SubscriberUserId, dto.NotifyOnStatus }, Constant.EventTypeConstant.SAVEDOCUMENTSET, 0, login).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex, "Event publish failed for subscriber {SubscriberId}", dto.SubscriberId); } return $"{SuccessResponse.SaveSuccessMessage} {dto.SubscriberId}"; } catch (Exception ex) when (ex is not ArgumentException) { _logger.LogError(ex, "Subscribe failed for ApiRequestId {ApiRequestId}", dto.ApiRequestId); throw; } } public async Task UnsubscribeAsync( int subscriberId, int apiRequestId, LoginDTO login, CancellationToken ct) { // ✅ Guards if (subscriberId == 0) throw new ArgumentException("SubscriberId must be a positive number."); if (apiRequestId == 0) throw new ArgumentException("ApiRequestId must be a positive number."); try { await _dal.DeleteSubscriberAsync(subscriberId, apiRequestId, login, ct).ConfigureAwait(false); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { _logger.LogError(ex, "Unsubscribe failed for SubscriberId {SubscriberId}", subscriberId); throw; } } public async Task NotifySubscribersAsync( int apiRequestId, byte newStatus, LoginDTO login, CancellationToken ct) { try { var subscribers = await _dal.GetByStatusAsync(apiRequestId, newStatus, login.ClientId, login, ct) .ConfigureAwait(false); if (subscribers.Count == 0) return; // ✅ Event publish isolated — non-fatal try { await _eventLog.PublishEventLogAsync( "AMP Request Status Changed — Subscriber Notification", new { apiRequestId, Status = newStatus, SubscriberCount = subscribers.Count }, Constant.EventTypeConstant.SAVEDOCUMENTSET, 0, login).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex, "NotifySubscribers event publish failed. ApiRequestId {ApiRequestId} | Status {Status}", apiRequestId, newStatus); } } catch (Exception ex) { // DAL fetch failure — non-fatal to status transition _logger.LogWarning(ex, "NotifySubscribers DAL fetch failed. ApiRequestId {ApiRequestId} | Status {Status}", apiRequestId, newStatus); } } }