using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using LittleShop.Data; using LittleShop.DTOs; using LittleShop.Enums; using LittleShop.Models; namespace LittleShop.Services; public class TeleBotMessagingService : ITeleBotMessagingService { private readonly LittleShopContext _context; private readonly ICustomerMessageService _customerMessageService; private readonly ILogger _logger; public TeleBotMessagingService( LittleShopContext context, ICustomerMessageService customerMessageService, ILogger logger) { _context = context; _customerMessageService = customerMessageService; _logger = logger; } public async Task SendOrderStatusUpdateAsync(Guid orderId, OrderStatus newStatus) { return newStatus switch { OrderStatus.PaymentReceived => await SendPaymentConfirmedAsync(orderId), OrderStatus.Accepted => await SendOrderAcceptedAsync(orderId), OrderStatus.Packing => await SendOrderPackingAsync(orderId), OrderStatus.Dispatched => await SendOrderDispatchedAsync(orderId), OrderStatus.Delivered => await SendOrderDeliveredAsync(orderId), OrderStatus.OnHold => await SendOrderOnHoldAsync(orderId), _ => false }; } public async Task SendPaymentConfirmedAsync(Guid orderId) { var order = await GetOrderWithCustomerAsync(orderId); if (order?.Customer == null) return false; var message = $"πŸ’° *Payment Confirmed!*\n\n" + $"Your order #{orderId.ToString()[..8]} has been paid successfully. " + $"We'll start processing it shortly.\n\n" + $"πŸ“¦ Total: Β£{order.TotalAmount:F2}\n" + $"⏱️ Expected processing: Within 24 hours"; return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Payment Confirmed", message); } public async Task SendOrderAcceptedAsync(Guid orderId) { var order = await GetOrderWithCustomerAsync(orderId); if (order?.Customer == null) return false; var message = $"βœ… *Order Accepted!*\n\n" + $"Great news! Your order #{orderId.ToString()[..8]} has been accepted " + $"and is being prepared for packing.\n\n" + $"⏱️ Expected packing: Within 24 hours\n" + $"🚚 We'll notify you when it's dispatched"; return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order Accepted", message); } public async Task SendOrderPackingAsync(Guid orderId) { var order = await GetOrderWithCustomerAsync(orderId); if (order?.Customer == null) return false; var message = $"πŸ“¦ *Being Packed!*\n\n" + $"Your order #{orderId.ToString()[..8]} is currently being packed with care.\n\n" + $"🚚 We'll send tracking details once dispatched.\n" + $"⏱️ Expected dispatch: Later today"; return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order Packing", message); } public async Task SendOrderDispatchedAsync(Guid orderId, string? trackingNumber = null) { var order = await GetOrderWithCustomerAsync(orderId); if (order?.Customer == null) return false; var trackingInfo = !string.IsNullOrEmpty(trackingNumber) ? $"πŸ“ Tracking: `{trackingNumber}`\n" : ""; var message = $"🚚 *Order Dispatched!*\n\n" + $"Your order #{orderId.ToString()[..8]} is on its way!\n\n" + $"{trackingInfo}" + $"⏱️ Estimated delivery: 1-3 working days\n" + $"πŸ“ Track your package for real-time updates"; return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.ShippingInfo, "Order Dispatched", message); } public async Task SendOrderDeliveredAsync(Guid orderId) { var order = await GetOrderWithCustomerAsync(orderId); if (order?.Customer == null) return false; var message = $"πŸŽ‰ *Order Delivered!*\n\n" + $"Your order #{orderId.ToString()[..8]} has been delivered successfully!\n\n" + $"⭐ Please consider leaving a review using the /review command.\n" + $"πŸ›’ Thank you for choosing us for your order!"; return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order Delivered", message); } public async Task SendOrderOnHoldAsync(Guid orderId, string? reason = null) { var order = await GetOrderWithCustomerAsync(orderId); if (order?.Customer == null) return false; var reasonText = !string.IsNullOrEmpty(reason) ? $"\n\nπŸ“ Reason: {reason}" : ""; var message = $"⏸️ *Order On Hold*\n\n" + $"Your order #{orderId.ToString()[..8]} has been temporarily put on hold.{reasonText}\n\n" + $"πŸ’¬ Please contact support if you have any questions.\n" + $"⏱️ We'll resolve this as quickly as possible"; return await QueueMessageAsync(order.Customer.Id, orderId, MessageType.OrderUpdate, "Order On Hold", message); } public async Task SendTestMessageAsync(Guid customerId, string message) { var customer = await _context.Customers.FindAsync(customerId); if (customer == null) return false; var testMessage = $"πŸ§ͺ *Test Message*\n\n{message}"; return await QueueMessageAsync(customerId, null, MessageType.CustomerService, "Test Message", testMessage); } public async Task IsAvailableAsync() { // TeleBot is always "available" since it polls for messages from the database queue // No need to check HTTP endpoint availability return true; } private async Task GetOrderWithCustomerAsync(Guid orderId) { return await _context.Orders .Include(o => o.Customer) .FirstOrDefaultAsync(o => o.Id == orderId); } private async Task QueueMessageAsync(Guid customerId, Guid? orderId, MessageType type, string subject, string content) { try { var createMessageDto = new CreateCustomerMessageDto { CustomerId = customerId, OrderId = orderId, Type = type, Subject = subject, Content = content, Priority = 5, // Normal priority IsUrgent = false }; var result = await _customerMessageService.CreateMessageAsync(createMessageDto); if (result != null) { _logger.LogInformation("Queued message {MessageId} for customer {CustomerId} - {Subject}", result.Id, customerId, subject); return true; } else { _logger.LogWarning("Failed to queue message for customer {CustomerId} - {Subject}", customerId, subject); return false; } } catch (Exception ex) { _logger.LogError(ex, "Error queuing message for customer {CustomerId} - {Subject}", customerId, subject); return false; } } }