using Dapr.Client.Autogen.Grpc.v1; using FrameworkDAL.CustomCode.MessageHub; using FrameworkDAL.DTO.Menu; using FrameworkDAL.DTO.MessageHub; using FrameworkDAL.DTO.MessageHub.MessageHubGenerator; using GB5Shared.DTO.Framework.Criteria; using GB5Shared.DTO.Framework.Login; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Polly; using Polly.Retry; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; using VaultSharp.V1.SystemBackend; namespace FrameworkBLL.MessageHub { public class MessageHubBLL : IMessageHubBLL { private readonly IMessageHubDAL _MessageHubDAL; private readonly IHttpClientFactory _HttpClientFactory; private readonly ILogger _Logger; private readonly Dapr.Client.DaprClient _Dapr; private readonly MessageHubSettings _settings; // Retry policy for external HTTP calls private readonly AsyncRetryPolicy _retryPolicy = Polly.Policy .Handle() .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); private readonly Dictionary _whatsAppTemplates; public MessageHubBLL( IMessageHubDAL messageHubDAL, IHttpClientFactory httpFactory, ILogger logger, Dapr.Client.DaprClient dapr, IOptions settings) { _MessageHubDAL = messageHubDAL; _HttpClientFactory = httpFactory; _Logger = logger; _Dapr = dapr; _settings = settings.Value; _whatsAppTemplates = _settings.WhatsAppTemplates ?? new Dictionary(); } public async Task GetMessageHub(int MessageHubId, LoginDTO LoginDTO) { try { return await _MessageHubDAL.GetMessageHub(MessageHubId, LoginDTO); } catch (Exception) { throw; } } public async Task SaveMessageHub( MessageHubOldDTO dto, LoginDTO login) { try { // ---------- DEFAULT MODE (0 = WhatsApp) ---------- int mode = dto.Mode; // default is already 0 // ---------- AUDIT ---------- dto.CreatedById = login.UserId; dto.ModifiedById = login.UserId; dto.CreatedOn = DateTime.UtcNow; dto.ModifiedOn = DateTime.UtcNow; dto.Payload ??= new Dictionary(); dto.Payload["CreatedOn"] = dto.CreatedOn; dto.Payload["CreatedBy"] = login.UserName; // ---------- BUILD MESSAGE TEXT ---------- dto.MessageText = BuildDynamicMessage(dto.Payload, login.UserName); // ---------- SAVE TO DATABASE ---------- if (dto.MessageHubId == 0) await _MessageHubDAL.SaveMessageHub(dto, login); else await _MessageHubDAL.UpdateMessageHub(dto, login); // ---------- VALIDATE RECIPIENT ---------- string to = !string.IsNullOrWhiteSpace(dto.To) ? dto.To : dto.Recipient; if (string.IsNullOrWhiteSpace(to)) throw new ArgumentException("Recipient (To) cannot be empty"); // ---------- DYNAMIC VALUES ---------- var values = dto.Payload.ToDictionary( k => k.Key, v => v.Value?.ToString() ?? string.Empty ); int templateId = dto.TemplateId = 1; // ---------- ROUTE BASED ON MODE ---------- switch (mode) { case 0: // WhatsApp (Default) return await SendWhatsAppMessageAsync(to, templateId, values); //case 1: // Telegram // return await SendTelegramMessageAsync(dto, login); //case 2: // Teams // return await SendTeamsMessageAsync(dto, login); default: // Unknown Mode → silently fallback to WhatsApp return await SendWhatsAppMessageAsync(to, templateId, values); } } catch (Exception ex) { _Logger.LogError(ex, "MessageHub Error"); return new MessageHubResponseDTO { Success = false, Message = ex.Message, ResponseData = ex.ToString() }; } } private List BuildTemplateComponents( Dictionary values, WhatsAppTemplateConfig template) { var components = new List(); // ---------- HEADER IMAGE (Optional) ---------- if (values.ContainsKey("QRCodeLink") && !string.IsNullOrWhiteSpace(values["QRCodeLink"])) { components.Add(new { type = "header", parameters = new[] { new { type = "image", image = new { link = values["QRCodeLink"] } } } }); } // ---------- BODY PARAMETERS ---------- var bodyParams = new List(); foreach (var key in template.ParameterKeys .Where(k => k != "QRCodeLink")) { var value = values.ContainsKey(key) ? values[key] : "-"; if (string.IsNullOrWhiteSpace(value)) value = "-"; bodyParams.Add(new { type = "text", text = value }); } components.Add(new { type = "body", parameters = bodyParams }); return components; } // ===================================================== // BUILD MESSAGE TEXT (FOR DB / LOGGING) // ===================================================== private string BuildDynamicMessage( Dictionary payload, string sentBy) { var sb = new StringBuilder(); sb.AppendLine("📌 Message Details"); sb.AppendLine(); if (payload != null && payload.Any()) { foreach (var kv in payload) { if (kv.Value != null && !string.IsNullOrWhiteSpace(kv.Value.ToString())) sb.AppendLine($"{kv.Key}: {kv.Value}"); } } sb.AppendLine(); sb.AppendLine($"Sent by: {sentBy}"); return sb.ToString().Trim(); } // ===================================================== // SEND WHATSAPP TEMPLATE MESSAGE (DYNAMIC) // ===================================================== private async Task SendWhatsAppMessageAsync(string to, int templateId, Dictionary values) { try { if (!_settings.WhatsAppTemplates.TryGetValue(templateId, out var template)) throw new Exception($"WhatsApp template not configured for TemplateId {templateId}"); // ---------- PARAMETER VALIDATION ---------- foreach (var key in template.ParameterKeys) { if (!values.ContainsKey(key)) { _Logger.LogWarning( "Missing WhatsApp parameter '{Key}' for template '{Template}'", key, template.TemplateName); } } // ---------- BUILD COMPONENTS ---------- var components = new List(); // HEADER IMAGE (Optional - QRCodeLink) if (values.ContainsKey("QRCodeLink") && !string.IsNullOrWhiteSpace(values["QRCodeLink"])) { components.Add(new { type = "header", parameters = new[] { new { type = "image", image = new { link = values["QRCodeLink"] } } } }); } // BODY PARAMETERS var bodyParams = new List(); foreach (var key in template.ParameterKeys .Where(k => k != "QRCodeLink")) { var value = values.ContainsKey(key) ? values[key] : "-"; if (string.IsNullOrWhiteSpace(value)) value = "-"; bodyParams.Add(new { type = "text", text = value }); } components.Add(new { type = "body", parameters = bodyParams }); // ---------- PAYLOAD ---------- var payload = new { messaging_product = "whatsapp", to = to, type = "template", template = new { name = template.TemplateName, language = new { code = template.LanguageCode ?? _settings.WhatsApp.DefaultLanguageCode }, components = components } }; var json = JsonConvert.SerializeObject(payload); var content = new StringContent(json, Encoding.UTF8, "application/json"); var client = _HttpClientFactory.CreateClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _settings.WhatsApp.AuthToken); var url = $"https://graph.facebook.com/v20.0/{_settings.WhatsApp.PhoneNumberId}/messages"; var response = await _retryPolicy.ExecuteAsync(() => client.PostAsync(url, content)); var responseBody = await response.Content.ReadAsStringAsync(); if (!response.IsSuccessStatusCode) { _Logger.LogError("WhatsApp API Error: {Response}", responseBody); } return new MessageHubResponseDTO { Success = response.IsSuccessStatusCode, Message = response.IsSuccessStatusCode ? "WhatsApp message sent successfully" : "WhatsApp message failed", ResponseData = responseBody }; } catch (Exception ex) { _Logger.LogError(ex, "WhatsApp Send Failed"); return new MessageHubResponseDTO { Success = false, Message = ex.Message, ResponseData = ex.ToString() }; } } // 🔹 Telegram private async Task SendTelegramMessageAsync(MessageHubOldDTO MessageHubOldDTO, LoginDTO LoginDTO) { var httpClient = _HttpClientFactory.CreateClient(); string url = $"https://api.telegram.org/bot{_settings.Telegram.BotToken}/sendMessage"; var payload = new { chat_id = MessageHubOldDTO.Recipient != "" ? MessageHubOldDTO.Recipient : _settings.Telegram.DefaultRecipient, text = $"{MessageHubOldDTO.MessageText}\n\nSent by: {LoginDTO.UserName}" }; var json = JsonConvert.SerializeObject(payload); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await httpClient.PostAsync(url, content); var responseBody = await response.Content.ReadAsStringAsync(); return new MessageHubResponseDTO { Success = response.IsSuccessStatusCode, Message = response.IsSuccessStatusCode ? "Telegram message sent" : "Telegram send failed", ResponseData = responseBody }; } // 🔹 Teams private async Task SendTeamsMessageAsync(MessageHubOldDTO MessageHubOldDTO, LoginDTO LoginDTO) { var httpClient = _HttpClientFactory.CreateClient(); var payload = new { text = $"{MessageHubOldDTO.MessageText}\n\nSent by: {LoginDTO.UserName}" }; var json = JsonConvert.SerializeObject(payload); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await httpClient.PostAsync(_settings.Teams.WebhookUrl, content); var responseBody = await response.Content.ReadAsStringAsync(); return new MessageHubResponseDTO { Success = response.IsSuccessStatusCode, Message = response.IsSuccessStatusCode ? "Teams message sent" : "Teams send failed", ResponseData = responseBody }; } public async Task DeleteMessageHub(int MessageHubId, LoginDTO LoginDTO) { try { return await _MessageHubDAL.DeleteMessageHub(MessageHubId, LoginDTO); } catch (Exception) { throw; } } public async Task GetSelectListMessageHub(CriteriaDTO criteriaDTO, LoginDTO LoginDTO) { try { return await _MessageHubDAL.GetSelectListMessageHub(criteriaDTO, LoginDTO); } catch (Exception) { throw; } } public async Task GetMessageHubTemplate(int MailTemplateId, LoginDTO LoginDTO) { try { return await _MessageHubDAL.GetMessageHub(MailTemplateId, LoginDTO); } catch (Exception) { throw; } } } }