using Microsoft.EntityFrameworkCore;
using SushiBarContracts.BindingModels;
using SushiBarContracts.SearchModels;
using SushiBarContracts.StoragesContracts;
using SushiBarContracts.ViewModels;
using SushiBarDatabaseImplement.Models;


namespace SushiBarDatabaseImplement.Implements
{
    public class ShopStorage : IShopStorage
    {
        public List<ShopViewModel> GetFullList()
        {
            using var context = new SushiBarDatabase();
            return context.Shops.Include(x => x.Sushis).ThenInclude(x => x.Sushi).ToList().
                Select(x => x.GetViewModel).ToList();
        }

        public List<ShopViewModel> GetFilteredList(ShopSearchModel model)
        {
            if (string.IsNullOrEmpty(model.ShopName))
            {
                return new();
            }
            using var context = new SushiBarDatabase();
            return context.Shops.Include(x => x.Sushis).ThenInclude(x => x.Sushi).Where(x => x.ShopName.Contains(model.ShopName)).
                ToList().Select(x => x.GetViewModel).ToList();
        }

        public ShopViewModel? GetElement(ShopSearchModel model)
        {
            if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue)
            {
                return new();
            }
            using var context = new SushiBarDatabase();
            return context.Shops.Include(x => x.Sushis).ThenInclude(x => x.Sushi)
                .FirstOrDefault(x =>
                (!string.IsNullOrEmpty(model.ShopName) && x.ShopName == model.ShopName) ||
                (model.Id.HasValue && x.Id == model.Id))?.GetViewModel;
        }

        public ShopViewModel? Insert(ShopBindingModel model)
        {
            using var context = new SushiBarDatabase();
            var newShop = Shop.Create(context, model);
            if (newShop == null)
            {
                return null;
            }
            context.Shops.Add(newShop);
            context.SaveChanges();
            return newShop.GetViewModel;
        }

        public ShopViewModel? Update(ShopBindingModel model)
        {
            using var context = new SushiBarDatabase();
            using var transaction = context.Database.BeginTransaction();
            try
            {
                var shop = context.Shops.FirstOrDefault(x => x.Id == model.Id);
                if (shop == null)
                {
                    return null;
                }
                shop.Update(model);
                context.SaveChanges();
                shop.UpdateSushis(context, model);
                transaction.Commit();
                return shop.GetViewModel;
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
        }

        public ShopViewModel? Delete(ShopBindingModel model)
        {
            using var context = new SushiBarDatabase();
            var shop = context.Shops.Include(x => x.Sushis).FirstOrDefault(x => x.Id == model.Id);
            if (shop != null)
            {
                context.Shops.Remove(shop);
                context.SaveChanges();
                return shop.GetViewModel;
            }
            return null;
        }

        public bool RestockingShops(SupplyBindingModel model)
        {
            using var context = new SushiBarDatabase();
            var transaction = context.Database.BeginTransaction();
            var Shops = context.Shops.Include(x => x.Sushis).ThenInclude(x => x.Sushi).ToList().
                Where(x => x.SushiMaxCount > x.ShopSushis.Select(x => x.Value.Item2).Sum()).ToList();
            if (model == null)
            {
                return false;
            }
            try
            {
                foreach (Shop shop in Shops)
                {
                    int difference = shop.SushiMaxCount - shop.ShopSushis.Select(x => x.Value.Item2).Sum();
                    int refill = Math.Min(difference, model.Count);
                    model.Count -= refill;
                    if (shop.ShopSushis.ContainsKey(model.SushiId))
                    {
                        var datePair = shop.ShopSushis[model.SushiId];
                        datePair.Item2 += refill;
                        shop.ShopSushis[model.SushiId] = datePair;
                    }
                    else
                    {
                        var sushi = context.Sushis.First(x => x.Id == model.SushiId);
                        shop.ShopSushis.Add(model.SushiId, (sushi, refill));
                    }
                    shop.SushisDictionatyUpdate(context);
                    if (model.Count == 0)
                    {
                        transaction.Commit();
                        return true;
                    }
                }
                transaction.Rollback();
                return false;
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
        }

        public bool Sale(SupplySearchModel model)
        {
            using var context = new SushiBarDatabase();
            var transaction = context.Database.BeginTransaction();
            try
            {
                var shops = context.Shops.Include(x => x.Sushis).ThenInclude(x => x.Sushi).ToList().
                    Where(x => x.ShopSushis.ContainsKey(model.SushiId.Value)).OrderByDescending(x => x.ShopSushis[model.SushiId.Value].Item2).ToList();

                foreach (var shop in shops)
                {
                    int residue = model.Count.Value - shop.ShopSushis[model.SushiId.Value].Item2;
                    if (residue > 0)
                    {
                        shop.ShopSushis.Remove(model.SushiId.Value);
                        shop.SushisDictionatyUpdate(context);
                        context.SaveChanges();
                        model.Count = residue;

                    }
                    else
                    {
                        if (residue == 0)
                            shop.ShopSushis.Remove(model.SushiId.Value);
                        else
                        {
                            var dataPair = shop.ShopSushis[model.SushiId.Value];
                            dataPair.Item2 = -residue;
                            shop.ShopSushis[model.SushiId.Value] = dataPair;
                        }

                        shop.SushisDictionatyUpdate(context);
                        transaction.Commit();
                        return true;
                    }
                }
                transaction.Rollback();
                return false;
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
        }

    }
}
