using Netina.Common.Models.Api;
using Netina.Common.Models.Exception;

namespace Netina.Domain.Entities.Orders;

public partial class Order
{
    public static Order Create(Guid userId)
    {
        var factorNumber = StringExtensions.GetId(10).ToUpper();
        return new Order(factorNumber, 0, 0, 0, 0, 0, 0, 0, false, OrderStatus.OrderBag, DateTime.MinValue, DateTime.Now, 0, string.Empty, userId, OrderPaymentMethod.OnlinePayment);

    }

    public void AddToOrderBag(Guid productId, double cost, double costWithDiscount, bool hasDiscount, double packingCost, Guid categoryId, int count)
    {
        var orderProduct = OrderProducts.FirstOrDefault(op => op.ProductId == productId);
        if (orderProduct == null)
        {
            orderProduct = OrderProduct.Create(count,
                cost,
                costWithDiscount,
                hasDiscount,
                packingCost,
                OrderStatus.OrderBag,
                productId,
                categoryId,
                this.Id);
            OrderProducts.Add(orderProduct);
        }
        else
        {
            orderProduct.SetCount(count);
        }
    }
    public void RemoveFromOrderBag(Guid productId, int count)
    {
        var orderProduct = OrderProducts.FirstOrDefault(op => op.ProductId == productId);
        if (orderProduct != null)
        {
            orderProduct.SetCount(count);
            if (orderProduct.Count == 0)
                OrderProducts.Remove(orderProduct);
        }
    }

    public void ChangeOrderBag(Guid productId, double cost, double costWithDiscount, bool hasDiscount, double packingCost, Guid categoryId, int count)
    {
        var orderProduct = OrderProducts.FirstOrDefault(op => op.ProductId == productId);
        if (orderProduct != null)
        {
            if (orderProduct.Count > count)
                RemoveFromOrderBag(productId, count);
            else
                AddToOrderBag(productId, cost, costWithDiscount, hasDiscount, packingCost, categoryId, count);
        }
        else
            AddToOrderBag(productId, cost, costWithDiscount, hasDiscount, packingCost, categoryId, count);

    }

    public void SetDiscount(string discountCode)
        => DiscountCode = discountCode;
    public void AddOrderProduct(OrderProduct orderProduct)
        => OrderProducts.Add(orderProduct);

    public void SetOrderPayment(OrderPaymentMethod paymentMethod)
    {
        switch (paymentMethod)
        {
            case OrderPaymentMethod.OnlinePayment:
                OrderStatus = OrderStatus.Paid;
                IsPayed = true;
                PayedAt = DateTime.Now;
                OrderAt = DateTime.Now;
                PaymentMethod = paymentMethod;
                break;
            case OrderPaymentMethod.CardTransfer:
                OrderStatus = OrderStatus.Submitted;
                IsPayed = false;
                OrderAt = DateTime.Now;
                PaymentMethod = paymentMethod;
                break;
            case OrderPaymentMethod.PayOnDoor:
                OrderStatus = OrderStatus.Submitted;
                IsPayed = false;
                OrderAt = DateTime.Now;
                PaymentMethod = paymentMethod;
                break;
        }
    }

    public void SetOrderStatus(OrderStatus orderStatus)
    {
        switch (orderStatus)
        {
            case OrderStatus.OrderBag:
                throw new AppException("Order is in cart so you cant change it", ApiResultStatusCode.BadRequest);
                break;
            case OrderStatus.Submitted:
                break;
            case OrderStatus.Paid:
                throw new AppException("use set payment method", ApiResultStatusCode.BadRequest);
                break;
            case OrderStatus.Processing:
                break;
            case OrderStatus.Delivered:
                DeliveredAt = DateTime.Now;
                break;
            case OrderStatus.Done:
                DoneAt = DateTime.Now;
                break;
            case OrderStatus.Canceled:
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(orderStatus), orderStatus, null);
        }
        OrderStatus = orderStatus;
    }

    public void AddOrderDelivery(Guid addressId, double deliveryCost, Guid shippingId, Guid orderId)
    {
        var orderDelivery = OrderDelivery.Create(addressId, deliveryCost, shippingId, orderId);
        if (OrderDelivery != null)
            orderDelivery.Id = OrderDelivery.Id;
        OrderDelivery = orderDelivery;
    }

    public void AddOrderDelivery(Guid addressId, double deliveryCost, Guid shippingId, Guid orderId, Guid orderDeliveryId)
    {
        var orderDelivery = OrderDelivery.Create(addressId, deliveryCost, shippingId, orderId);
        orderDelivery.Id = orderDeliveryId;
        OrderDelivery = orderDelivery;
    }
    public void SetTotalPrice(double totalProductPrice,
        double packingPrice,
        double servicePrice,
        double deliveryPrice,
        double productDiscountPrice,
        double discountCodePrice,
        double taxesPrice)
    {
        TotalProductsPrice = totalProductPrice;
        PackingPrice = packingPrice;
        ServicePrice = servicePrice;
        DeliveryPrice = deliveryPrice;
        TaxesPrice = taxesPrice;
        DiscountCodePrice = discountCodePrice;
        ProductDiscountPrice = productDiscountPrice;
        DiscountPrice = productDiscountPrice + discountCodePrice;
        TotalPrice = (totalProductPrice + packingPrice + servicePrice + deliveryPrice + taxesPrice) - DiscountPrice;
    }

}

public partial class OrderProduct
{
    public static OrderProduct Create(int count,
        double productFee,
        double productFeeWithDiscount,
        bool hasDiscount,
        double packingFee,
        OrderStatus orderProductStatus,
        Guid productId,
        Guid productCategoryId,
        Guid orderId)
    {
        var productCost = count * productFeeWithDiscount;
        var packingCost = count * packingFee;
        return new OrderProduct(count, productFee, productFeeWithDiscount, hasDiscount, productCost, packingFee, packingCost, orderProductStatus, productId, productCategoryId, orderId);
    }

    public void SetCount(int count)
    {
        Count = count;
        var productCost = ProductFeeWithDiscount * Count;
    }
}

public partial class OrderDelivery
{
    public static OrderDelivery Create(Guid addressId, double deliveryCost, Guid shippingId, Guid orderId)
    {
        return new OrderDelivery(addressId, deliveryCost, shippingId, orderId);
    }

    public void SetTrackingCode(string code)
    {
        this.TrackingCode = code;
    }
}