using CarCenterContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using CarCenterDataBaseImplement.Models;
using Microsoft.EntityFrameworkCore;
using CarCenterContracts.SearchModels;
using CarCenterContracts.BindingModels;
using CarCenterContracts.StoragesContracts;

namespace CarCenterDataBaseImplement.Implements
{
    public class CarStorage : ICarStorage
    {
        public List<CarViewModel> GetFullList()
        {
            using var context = new CarCenterDataBase();

            return context.Cars
            .Include(x => x.EquipmentCars)
            .ThenInclude(x => x.Equipment)
            .Include(x => x.InspectionCar)
            .ThenInclude(x => x.Inspection)
            .Include(x => x.Administrator)
            .Select(x => x.GetViewModel)
            .ToList();
        }

        public CarViewModel? GetElement(CarSearchModel model)
        {
            if (string.IsNullOrEmpty(model.BrandCar) && !model.Id.HasValue)
            {
                return null;
            }

            using var context = new CarCenterDataBase();

            return context.Cars
                .Include(x => x.EquipmentCars)
                .ThenInclude(x => x.Equipment)
                .Include(x => x.InspectionCar)
                .ThenInclude(x => x.Inspection)
                .FirstOrDefault(x => (!string.IsNullOrEmpty(model.BrandCar) && x.BrandCar == model.BrandCar) || (model.Id.HasValue && x.Id == model.Id))?
                .GetViewModel;
        }

        public List<CarViewModel> GetFilteredList(CarSearchModel model)
        {
            if (string.IsNullOrEmpty(model.BrandCar) && !model.AdministratorId.HasValue)
            {
                return new();
            }

            using var context = new CarCenterDataBase();

            if (model.AdministratorId.HasValue)
            {
                return context.Cars
                .Include(x => x.EquipmentCars)
                .ThenInclude(x => x.Equipment)
                .Include(x => x.InspectionCar)
                .ThenInclude(x => x.Inspection)
                .Include(x => x.Administrator)
                    .Where(x => x.AdministratorId == model.AdministratorId)
                    .Select(x => x.GetViewModel)
                    .ToList();
            }

            return context.Cars
                .Include(x => x.EquipmentCars)
                .ThenInclude(x => x.Equipment)
                .Include(x => x.InspectionCar)
                .ThenInclude(x => x.Inspection)
                .Include(x => x.Administrator)
                .Where(x => x.BrandCar.Contains(model.BrandCar))
                .Select(x => x.GetViewModel)
                .ToList();
        }

        public CarViewModel? Insert(CarBindingModel model)
        {
            using var context = new CarCenterDataBase();

            var newCar = Car.Create(model);

            if (newCar == null)
            {
                return null;
            }

            context.Cars.Add(newCar);
            context.SaveChanges();

            return newCar.GetViewModel;
        }

        public CarViewModel? Update(CarBindingModel model)
        {
            using var context = new CarCenterDataBase();

            var car = context.Cars.FirstOrDefault(x => x.Id == model.Id);

            if (car == null)
            {
                return null;
            }

            car.Update(model);
            context.SaveChanges();

            return car.GetViewModel;
        }

        public CarViewModel? Delete(CarBindingModel model)
        {
            using var context = new CarCenterDataBase();

            var element = context.Cars.FirstOrDefault(rec => rec.Id == model.Id);

            if (element != null)
            {
                context.Cars.Remove(element);
                context.SaveChanges();

                return element.GetViewModel;
            }

            return null;
        }

        public List<ReportPreSaleWorkCarViewModel> GetReportCarPreSaleWorksList(ListPreSaleWorksSearchModel model)
        {
            if (model.carsIds == null)
            {
                return new();
            }
            using var context = new CarCenterDataBase();
            return context.Cars
                .Where(car => model.carsIds.Contains(car.Id))
                 .Select(car => new ReportPreSaleWorkCarViewModel
                 {
                     BrandCar = car.BrandCar,
                     PreSaleWorks = context.PreSaleWorks
                    .Include(preSaleWork => preSaleWork.Equipments)
                    .ThenInclude(equipment => equipment.Cars)
                    .Where(preSaleWork => preSaleWork.Equipments
                    .SelectMany(equipment => equipment.Cars)
                    .Any(rd => rd.CarId == car.Id))
                    .Select(preSaleWork => preSaleWork.GetViewModel)
                    .ToList()
                      })
                   .ToList();
              }


        public List<ReportEquipmentsEmployeesViewModel> GetReportEquipmentsEmployees(ReportEquipmentsEmployeesSearchModel model)
        {
            using var context = new CarCenterDataBase();
            var per = context.Cars
                .Select(car => new ReportEquipmentsEmployeesViewModel()
              {
                  BrandCar = car.BrandCar,
                  Equipments = context.Equipments
                  .Where(equipment => equipment.DateCreateEquipment <= model.DateTo &&
                    equipment.DateCreateEquipment >= model.DateFrom && equipment.Cars.Any(m => m.CarId == car.Id))
                  .Select(equipment => equipment.GetViewModel)
                  .ToList(),
                   Employees = context.Inspections
                   .Include(service => service.Employee)
                   .Where(service => service.Employee != null && service.Cars.Any(m => m.CarId == car.Id))
                   .Select(service => service.Employee.GetViewModel)
                   .ToList(),
                })
              .ToList();
            return per;
        }
    }
}
