using GB5Shared.DTO.Framework.Login; using GB5Shared.Resource.Response; using GB5Shared.Telemetry; using Microsoft.Extensions.Logging; using PartnerDAL.DTO.PartnerWebhook; using PartnerDAL.Interfaces; namespace PartnerBLL.PartnerWebhook { public class PartnerWebhookBLL : IPartnerWebhookBLL { private readonly IPartnerWebhookDAL _dal; private readonly ILogger _logger; public PartnerWebhookBLL(IPartnerWebhookDAL dal, ILogger logger) { _dal = dal; _logger = logger; } public async Task GetPartnerWebhookList(int partnerProductId, LoginDTO loginDTO) { try { GB5Trace.Step("get-webhook-list", new { partnerProductId }); return await _dal.GetPartnerWebhookList(partnerProductId, loginDTO).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-webhook-list-failed", ex); _logger.LogError(ex, "GetPartnerWebhookList failed for PartnerProductId {PartnerProductId}", partnerProductId); throw; } } public async Task> GetWebhooksByEvent(int eventTypeId, LoginDTO loginDTO) { try { return await _dal.GetWebhooksByEvent(eventTypeId, loginDTO).ConfigureAwait(false); } catch (Exception ex) { GB5Trace.MarkFailed("get-webhooks-by-event-failed", ex); _logger.LogError(ex, "GetWebhooksByEvent failed for EventTypeId {EventTypeId}", eventTypeId); throw; } } public async Task SavePartnerWebhook(PartnerWebhookDTO dto, LoginDTO loginDTO) { try { GB5Trace.Step("validate-webhook", new { dto.PartnerProductId, dto.EventTypeId }); if (dto.PartnerProductId <= 0) throw new ArgumentException("PartnerProductId is required."); if (dto.EventTypeId <= 0) throw new ArgumentException("EventTypeId is required."); if (string.IsNullOrWhiteSpace(dto.CallbackUrl)) throw new ArgumentException("CallbackUrl is required."); if (!dto.CallbackUrl.StartsWith("https://", StringComparison.OrdinalIgnoreCase)) throw new ArgumentException("CallbackUrl must use HTTPS."); if (string.IsNullOrWhiteSpace(dto.Secret) || dto.Secret.Length < 16) throw new ArgumentException("Secret must be at least 16 characters."); var eventExists = await _dal.CheckEventTypeExists(dto.EventTypeId, loginDTO).ConfigureAwait(false); if (eventExists == 0) throw new ArgumentException($"EventTypeId {dto.EventTypeId} does not exist in MEVENTTYPE."); dto.CreatedById = loginDTO.UserId; dto.ModifiedById = loginDTO.UserId; dto.CreatedOn = DateTime.UtcNow; dto.ModifiedOn = DateTime.UtcNow; GB5Trace.Step("save-webhook", new { dto.PartnerProductId, dto.EventTypeId }); var webhookId = await _dal.SavePartnerWebhook(dto, loginDTO).ConfigureAwait(false); _logger.LogInformation("PartnerWebhook {WebhookId} created for PartnerProductId {PartnerProductId} EventTypeId {EventTypeId} by user {UserId}", webhookId, dto.PartnerProductId, dto.EventTypeId, loginDTO.UserId); return $"{SuccessResponse.SaveSuccessMessage} {webhookId}"; } catch (Exception ex) { GB5Trace.MarkFailed("save-webhook-failed", ex); _logger.LogError(ex, "SavePartnerWebhook failed for PartnerProductId {PartnerProductId}", dto.PartnerProductId); throw; } } public async Task DeletePartnerWebhook(int webhookId, LoginDTO loginDTO) { try { GB5Trace.Step("delete-webhook", new { webhookId }); if (webhookId <= 0) throw new ArgumentException("WebhookId is required."); await _dal.DeletePartnerWebhook(webhookId, loginDTO.UserId, loginDTO).ConfigureAwait(false); _logger.LogInformation("PartnerWebhook {WebhookId} deleted by user {UserId}", webhookId, loginDTO.UserId); return SuccessResponse.DeleteSuccessMessage; } catch (Exception ex) { GB5Trace.MarkFailed("delete-webhook-failed", ex); _logger.LogError(ex, "DeletePartnerWebhook failed for WebhookId {WebhookId}", webhookId); throw; } } public async Task UpdateWebhookDeliveryStatus(int webhookId, string status, LoginDTO loginDTO) { try { await _dal.UpdateWebhookDeliveryStatus(webhookId, status, loginDTO).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex, "UpdateWebhookDeliveryStatus failed for WebhookId {WebhookId}", webhookId); } } } }