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<bool> SyncInternalStatusAsync(
        string cafeId,
        string orderId,
        OrderStatus newStatus,
        CancellationToken ct = default);

    Task<bool> 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<DeliveryStatusSyncService> _logger;

    public DeliveryStatusSyncService(
        AppDbContext db,
        IKdsNotifier kds,
        ISnappfoodClient snappfood,
        ITap30Client tap30,
        IInventoryService inventory,
        ILogger<DeliveryStatusSyncService> logger)
    {
        _db = db;
        _kds = kds;
        _snappfood = snappfood;
        _tap30 = tap30;
        _inventory = inventory;
        _logger = logger;
    }

    public async Task<bool> 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<bool> 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
        };
}
