using Meezi.API.Models.Orders;
using Meezi.API.Models.Public;
using Meezi.Core.Entities;
using Meezi.Core.Enums;
using Meezi.API.Services.Printing;

namespace Meezi.API.Services;

public static class OrderTrackingHelper
{
    private static readonly (string Key, int Rank)[] Flow =
    [
        ("submitted", 0),
        ("seen", 1),
        ("preparing", 2),
        ("ready", 3),
        ("done", 4)
    ];

    public static string NewTrackingToken() => Guid.NewGuid().ToString("N");

    public static OrderTrackDto BuildTrackDto(Order order)
    {
        var steps = BuildSteps(order.Status);
        return new OrderTrackDto(
            order.Id,
            ReceiptPrintFormatting.OrderNumberLabel(order.DisplayNumber > 0 ? order.DisplayNumber : ReceiptPrintFormatting.StableDisplayNumberFromId(order.Id)),
            order.Status,
            StatusLabel(order.Status),
            order.Total,
            order.Table?.Number,
            order.CreatedAt,
            order.StatusUpdatedAt,
            order.GuestTrackingToken ?? string.Empty,
            steps,
            order.Items
                .Where(i => !i.IsVoided)
                .Select(i => new OrderItemDto(
                    i.Id,
                    i.MenuItemId,
                    i.MenuItem?.Name ?? "",
                    i.Quantity,
                    i.UnitPrice,
                    i.Notes,
                    i.IsVoided,
                    i.VoidedAt))
                .ToList());
    }

    public static IReadOnlyList<OrderTrackingStepDto> BuildSteps(OrderStatus status)
    {
        if (status == OrderStatus.Cancelled)
        {
            return
            [
                new OrderTrackingStepDto("submitted", "submitted", true, false),
                new OrderTrackingStepDto("cancelled", "cancelled", true, true)
            ];
        }

        var rank = StatusRank(status);
        return Flow.Select(step =>
        {
            var isComplete = rank > step.Rank || status == OrderStatus.Delivered;
            var isCurrent = rank == step.Rank && status is not OrderStatus.Delivered;
            return new OrderTrackingStepDto(step.Key, step.Key, isComplete, isCurrent);
        }).ToList();
    }

    private static int StatusRank(OrderStatus status) => status switch
    {
        OrderStatus.Pending => 0,
        OrderStatus.Confirmed => 1,
        OrderStatus.Preparing => 2,
        OrderStatus.Ready => 3,
        OrderStatus.Delivered => 4,
        _ => 0
    };

    public static string StatusLabel(OrderStatus status) => status switch
    {
        OrderStatus.Pending => "pending",
        OrderStatus.Confirmed => "seen",
        OrderStatus.Preparing => "preparing",
        OrderStatus.Ready => "ready",
        OrderStatus.Delivered => "done",
        OrderStatus.Cancelled => "cancelled",
        _ => "pending"
    };
}
