using Meezi.API.Models.Orders; using Meezi.Core.Entities; using Meezi.Core.Enums; using Meezi.Core.Interfaces; using Meezi.Infrastructure.Data; using Microsoft.EntityFrameworkCore; namespace Meezi.API.Services.Delivery; public interface IDeliveryStatusSyncService { Task SyncInternalStatusAsync( string cafeId, string orderId, OrderStatus newStatus, CancellationToken ct = default); Task ApplyPlatformStatusAsync( DeliveryPlatform platform, string externalOrderId, string platformStatus, CancellationToken ct = default); } public class DeliveryStatusSyncService : IDeliveryStatusSyncService { private readonly AppDbContext _db; private readonly IKdsNotifier _kds; private readonly ISnappfoodClient _snappfood; private readonly ITap30Client _tap30; private readonly IInventoryService _inventory; private readonly ILogger _logger; public DeliveryStatusSyncService( AppDbContext db, IKdsNotifier kds, ISnappfoodClient snappfood, ITap30Client tap30, IInventoryService inventory, ILogger logger) { _db = db; _kds = kds; _snappfood = snappfood; _tap30 = tap30; _inventory = inventory; _logger = logger; } public async Task SyncInternalStatusAsync( string cafeId, string orderId, OrderStatus newStatus, CancellationToken ct = default) { var order = await _db.Orders .FirstOrDefaultAsync(o => o.Id == orderId && o.CafeId == cafeId, ct); if (order?.DeliveryPlatform is null || string.IsNullOrEmpty(order.ExternalOrderId)) return false; var platformStatus = MapToPlatformStatus(newStatus); await NotifyPlatformAsync(order.DeliveryPlatform.Value, order.ExternalOrderId, platformStatus, ct); if (newStatus == OrderStatus.Delivered && !string.IsNullOrEmpty(order.SnappfoodOrderId)) await _snappfood.NotifyOrderDeliveredAsync(order.SnappfoodOrderId, ct); return true; } public async Task ApplyPlatformStatusAsync( DeliveryPlatform platform, string externalOrderId, string platformStatus, CancellationToken ct = default) { var order = await _db.Orders .Include(o => o.Items) .ThenInclude(i => i.MenuItem) .FirstOrDefaultAsync( o => o.DeliveryPlatform == platform && o.ExternalOrderId == externalOrderId, ct); if (order is null) return false; var mapped = MapFromPlatformStatus(platformStatus); if (order.Status == mapped) return true; if (mapped == OrderStatus.Cancelled) await RollbackInventoryPlaceholderAsync(order, ct); order.Status = mapped; await _db.SaveChangesAsync(ct); await _kds.NotifyOrderStatusChangedAsync(order.CafeId, order.Id, mapped, ct); if (!string.IsNullOrEmpty(order.TableId)) await _kds.NotifyTableStatusChangedAsync(order.CafeId, ct); return true; } private async Task NotifyPlatformAsync( DeliveryPlatform platform, string externalOrderId, string status, CancellationToken ct) { switch (platform) { case DeliveryPlatform.Snappfood: await _snappfood.NotifyOrderStatusAsync(externalOrderId, status, ct); break; case DeliveryPlatform.Tap30: await _tap30.NotifyOrderStatusAsync(externalOrderId, status, ct); break; } } private Task RollbackInventoryPlaceholderAsync(Order order, CancellationToken ct) { _logger.LogInformation( "Delivery order {OrderId} cancelled — inventory rollback pending BOM linkage", order.Id); return Task.CompletedTask; } private static string MapToPlatformStatus(OrderStatus status) => status switch { OrderStatus.Pending => "pending", OrderStatus.Confirmed => "confirmed", OrderStatus.Preparing => "preparing", OrderStatus.Ready => "ready", OrderStatus.Delivered => "delivered", OrderStatus.Cancelled => "cancelled", _ => "confirmed" }; private static OrderStatus MapFromPlatformStatus(string platformStatus) => platformStatus.Trim().ToLowerInvariant() switch { "pending" => OrderStatus.Pending, "confirmed" => OrderStatus.Confirmed, "preparing" or "in_progress" => OrderStatus.Preparing, "ready" => OrderStatus.Ready, "delivered" or "completed" => OrderStatus.Delivered, "cancelled" or "canceled" => OrderStatus.Cancelled, _ => OrderStatus.Confirmed }; }