using Grand.Domain.Catalog;
using Grand.Domain.Payments;

namespace Grand.Domain.Orders;

public static class OrderExtensions
{
    /// <summary>
    ///     Gets a value indicating - download is allowed
    /// </summary>
    /// <param name="order">Order</param>
    /// <param name="orderItem">Order item to check</param>
    /// <param name="product">Product</param>
    /// <returns>True if download is allowed; otherwise, false.</returns>
    public static bool IsDownloadAllowed(this Order order, OrderItem orderItem, Product product)
    {
        if (orderItem == null)
            return false;

        if (order == null || order.Deleted)
            return false;

        //order status
        if (order.OrderStatusId == (int)OrderStatusSystem.Cancelled)
            return false;

        if (product == null || !product.IsDownload)
            return false;

        //payment status
        switch (product.DownloadActivationTypeId)
        {
            case DownloadActivationType.WhenOrderIsPaid:
            {
                if (order.PaymentStatusId == PaymentStatus.Paid && order.PaidDateUtc.HasValue)
                {
                    //expiration date
                    if (product.DownloadExpirationDays.HasValue)
                    {
                        if (order.PaidDateUtc.Value.AddDays(product.DownloadExpirationDays.Value) > DateTime.UtcNow)
                            return true;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
                break;
            case DownloadActivationType.Manually:
            {
                if (orderItem.IsDownloadActivated)
                {
                    //expiration date
                    if (product.DownloadExpirationDays.HasValue)
                    {
                        if (order.CreatedOnUtc.AddDays(product.DownloadExpirationDays.Value) > DateTime.UtcNow)
                            return true;
                    }
                    else
                    {
                        return true;
                    }
                }
            }
                break;
        }

        return false;
    }

    /// <summary>
    ///     Gets a value indicating whether license download is allowed
    /// </summary>
    /// <param name="order">Order</param>
    /// <param name="orderItem">Order item to check</param>
    /// <param name="product">Product</param>
    /// <returns>True if license download is allowed; otherwise, false.</returns>
    public static bool IsLicenseDownloadAllowed(this Order order, OrderItem orderItem, Product product)
    {
        if (orderItem == null)
            return false;

        return !string.IsNullOrEmpty(orderItem.LicenseDownloadId) && IsDownloadAllowed(order, orderItem, product);
    }

    /// <summary>
    ///     Gets a value indicating whether an order has items to be added to a shipment
    /// </summary>
    /// <param name="order">Order</param>
    /// <returns>A value indicating whether an order has items to be added to a shipment</returns>
    public static bool HasItemsToAddToShipment(this Order order)
    {
        ArgumentNullException.ThrowIfNull(order);

        foreach (var orderItem in order.OrderItems)
        {
            //we can ship only shippable products
            if (!orderItem.IsShipEnabled)
                continue;

            if (orderItem.OpenQty <= 0 || orderItem.Status == OrderItemStatus.Close)
                continue;

            //yes, we have at least one item to create a new shipment
            return true;
        }

        return false;
    }

    /// <summary>
    ///     Indicates whether a order's tag exists
    /// </summary>
    /// <param name="order">Order</param>
    /// <param name="orderTag">Order tag identifier</param>
    /// <returns>Result</returns>
    public static bool OrderTagExists(this Order order, OrderTag orderTag)
    {
        ArgumentNullException.ThrowIfNull(order);

        var result = order.OrderTags.FirstOrDefault(t => t == orderTag.Id) != null;
        return result;
    }
}