using BankContracts.BindingModels;
using BankContracts.SearchModels;
using BankContracts.StoragesContracts;
using BankContracts.ViewModels;
using BankDatabaseImplement.Models;
using Microsoft.EntityFrameworkCore;

namespace BankDatabaseImplement.Implements
{
    public class OperationStorage : IOperationStorage
    {
        private void CheckSearchModel(OperationSearchModel model)
        {
            if (model == null)
                throw new ArgumentNullException("Передаваемая модель для поиска равна нулю", nameof(model));
            if (!model.Id.HasValue && !model.EmployeeId.HasValue && model.PurchasesIds == null)
                throw new ArgumentException("Все передаваемые поля поисковой модели оказались пусты или равны null");
        }

        public OperationViewModel? Delete(OperationBindingModel model)
        {
            using var context = new BankDB();
            var element = context.Operations.FirstOrDefault(x => x.Id == model.Id);
            if (element != null)
            {
                context.Operations.Remove(element);
                context.SaveChanges();
                return element.GetViewModel;
            }
            return null;
        }

        public OperationViewModel? GetElement(OperationSearchModel model)
        {
            CheckSearchModel(model);
            if (!model.Id.HasValue)
            {
                return null;
            }
            using var context = new BankDB();
            return context.Operations
                .Include(x => x.Employee)
                .FirstOrDefault(x => model.Id.HasValue && x.Id == model.Id)?.GetViewModel;
        }

        public List<OperationViewModel> GetFilteredList(OperationSearchModel model)
        {
            CheckSearchModel(model);
            if (model.Id.HasValue)
            {
                var res = GetElement(model);
                return res != null ? new() { res } : new();
            }
            using var context = new BankDB();

            var query = context.Operations.Include(x => x.Employee);
            if (model.EmployeeId.HasValue)
            {

                return query
                    .Where(x => model.EmployeeId == x.EmployeeId)
                    .Select(x => x.GetViewModel)
                    .ToList();
            }

            if (model.PurchasesIds != null)
                return query
                    .Include(x => x.Purchases)!
                    .ThenInclude(x => x.Purchase)
                    .ThenInclude(x => x.Operations)
                    .Where(x => x.Purchases.Any(y => model.PurchasesIds.Contains(y.PurchaseId)))
                    .Select(x => x.GetViewModel)
                    .ToList();
            return new();
        }

        public List<OperationViewModel> GetFullList()
        {
            using var context = new BankDB();
            return context.Operations.Include(x => x.Employee)
                .Select(x => x.GetViewModel)
                .ToList();
        }

        public OperationViewModel? Insert(OperationBindingModel model)
        {
            var newOperation = Operation.Create(model);
            if (newOperation == null)
            {
                return null;
            }
            using var context = new BankDB();
            context.Operations.Add(newOperation);
            context.SaveChanges();
            return newOperation.GetViewModel;
        }

        public OperationViewModel? Update(OperationBindingModel model)
        {
            using var context = new BankDB();
            var operation = context.Operations.FirstOrDefault(x => x.Id == model.Id);
            if (operation == null)
            {
                return null;
            }
            operation.Update(model);
            context.SaveChanges();
            return operation.GetViewModel;
        }
    }
}
