using BarContracts.BindingModels;
using BarContracts.BusinessLogicContracts;
using BarContracts.SearchModels;
using BarContracts.StoragesContracts;
using BarContracts.ViewModels;
using BarDataModels.Enums;
using Microsoft.Extensions.Logging;

namespace BarBusinessLogic.BusinessLogics
{
    public class OrderLogic : IOrderLogic
    {
        private readonly ILogger _logger;

        private readonly IOrderStorage _orderStorage;

        public OrderLogic(ILogger<CocktailLogic> Logger, IOrderStorage OrderStorage)
        {
            _logger = Logger;
            _orderStorage = OrderStorage;
        }

        public List<OrderViewModel>? ReadList(OrderSearchModel? Model)
        {
            _logger.LogInformation("ReadList. Id:{Id}", Model?.Id);
            var List = Model is null ? _orderStorage.GetFullList() : _orderStorage.GetFilteredList(Model);

            if (List is null)
            {
                _logger.LogWarning("ReadList return null list");
                return null;
            }

            _logger.LogInformation("ReadList. Count: {Count}", List.Count);
            return List;
        }

        public bool CreateOrder(OrderBindingModel Model)
        {
            CheckModel(Model);

            if (Model.Status != OrderStatus.Undefined)
            {
                _logger.LogWarning("Invalid order status");
                return false;
            }

            Model.Status = OrderStatus.Accepted;

            if (_orderStorage.Insert(Model) is null)
            {
                _logger.LogWarning("Insert operation failed");
                return false;
            }

            return true;
        }

        private bool ChangeOrderStatus(OrderBindingModel Model, OrderStatus NewStatus)
        {
            CheckModel(Model, false);

            var Order = _orderStorage.GetElement(new OrderSearchModel { Id = Model.Id });

            if (Order == null)
            {
                _logger.LogWarning("Change status operation failed. Order not found");
                return false;
            }

            if (Order.Status + 1 != NewStatus)
            {
                _logger.LogWarning("Change status operation failed. Incorrect new status: {NewStatus}. Current status: {currStatus}",
                    NewStatus, Order.Status);
                return false;
            }

            Model.CocktailId = Order.CocktailId;
            Model.Count = Order.Count;
            Model.Sum = Order.Sum;
            Model.DateCreate = Order.DateCreate;
            Model.Status = NewStatus;

            if (Model.Status == OrderStatus.Ready)
                Model.DateImplement = DateTime.Now;
            else
                Model.DateImplement = Order.DateImplement;

            if (_orderStorage.Update(Model) == null)
            {
                _logger.LogWarning("Change status operation failed");
                return false;
            }

            return true;
        }

        public bool TakeOrderInWork(OrderBindingModel Model)
        {
            return ChangeOrderStatus(Model, OrderStatus.BeingProcessed);
        }

        public bool FinishOrder(OrderBindingModel Model)
        {
            return ChangeOrderStatus(Model, OrderStatus.Ready);
        }

        public bool DeliveryOrder(OrderBindingModel Model)
        {
            return ChangeOrderStatus(Model, OrderStatus.Delivered);
        }

        private void CheckModel(OrderBindingModel Model, bool WithParams = true)
        {
            if (Model == null)
                throw new ArgumentNullException(nameof(Model));

            if (!WithParams)
                return;

            if (Model.Count <= 0)
                throw new ArgumentNullException("Количество напитков в заказе быть больше 0", nameof(Model.Count));

            if (Model.Sum <= 0)
                throw new ArgumentNullException("Стоимость заказа должна быть больше 0", nameof(Model.Sum));

            _logger.LogInformation("Order. CocktailId:{CocktailId}. Count:{Count}. Sum:{Sum}. " +
                "Status:{Status}. DateCreate:{DateCreate}. DateImplement:{DateImplement}. Id: {Id}",
                Model.CocktailId, Model.Count, Model.Sum, Model.Status, Model.DateCreate,
                Model.DateImplement, Model.Id);
        }
    }
}
