﻿// MIT License. Copyright (c) 2016 Maxim Kuzmin. Contacts: https://github.com/maxim-kuzmin

// Author: Maxim Kuzmin

using Makc2017.Core.Data;
using Makc2017.Core.Extensions.Tasking.OfTask;
using Makc2017.Core.Module.Extensions.OfQueryList;
using Makc2017.Data;
using Makc2017.Data.Entity;
using Makc2017.Data.Entity.Objects;
using Makc2017.Data.Loaders;
using Makc2017.Data.Objects;
using Makc2017.Modules.DummyOneToMany.Data.Entity.Extensions.OfQueryItem;
using Makc2017.Modules.DummyOneToMany.Data.Entity.Extensions.OfQueryList;
using Makc2017.Modules.DummyOneToMany.Filters;
using Makc2017.Modules.DummyOneToMany.Models;
using Microsoft.EntityFrameworkCore;
using System.Linq;
using System.Threading.Tasks;

namespace Makc2017.Modules.DummyOneToMany
{
    /// <summary>
    /// Модули. Модуль "DummyOneToMany". Репозиторий.
    /// </summary>
    internal class ModuleDummyOneToManyRepository
    {
        #region Properties

        private ModuleDummyOneToManyConfig Config { get; set; }

        private CoreDataHelper Helper { get; set; }

        private DbContextOptions DbContextOptions { get; set; }

        #endregion Properties

        #region Constructors

        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="config">Конфигурация.</param>
        /// <param name="dataProvider">Поставщик данных.</param>
        /// <param name="dataConfig">Конфигурация данных.</param>
        public ModuleDummyOneToManyRepository(
            ModuleDummyOneToManyConfig config,
            ICoreDataProvider dataProvider,
            DataConfig dataConfig
            )
        {
            Config = config;

            Helper = new CoreDataHelper(dataProvider);

            var connectionString = dataConfig.GetConnectionStringByName(Config.DbConnectionStringName);

            DbContextOptions = new DbContextOptionsBuilder().UseSqlServer(connectionString).Options;
        }

        #endregion Constructors

        #region Public methods

        /// <summary>
        /// Получить элемент.
        /// </summary>
        /// <param name="filter">Фильтр.</param>
        /// <returns>Задача с полученными данными.</returns>
        public async Task<ModuleDummyOneToManyModelItem> GetItem(ModuleDummyOneToManyFilterItem filter)
        {
            ModuleDummyOneToManyModelItem result = null;

            DataEntityObjectDummyOneToMany entityDummyOneToMany = null;

            using (var source = CreateDbContext())
            {
                entityDummyOneToMany = await source.DummyOneToMany
                    .ApplyFiltering(filter)
                    .FirstOrDefaultAsync()
                    .WithCurrentCulture(false);
            }

            if (entityDummyOneToMany != null)
            {
                result = CreateItem(entityDummyOneToMany);
            }

            return result;
        }

        /// <summary>
        /// Получить список.
        /// </summary>
        /// <param name="filter">Фильтр.</param>
        /// <returns>Задача с полученными данными.</returns>
        public async Task<ModuleDummyOneToManyModelList> GetList(ModuleDummyOneToManyFilterList filter)
        {
            var result = new ModuleDummyOneToManyModelList();

            using (var sourceOfItems = CreateDbContext())
            using (var sourceOfTotalCount = CreateDbContext())
            {
                var queryOfItems = sourceOfItems.DummyOneToMany
                    .ApplyFiltering(filter)
                    .ApplySorting(filter)
                    .ApplyPagination(filter);

                var queryOfTotalCount = sourceOfTotalCount.DummyOneToMany
                    .ApplyFiltering(filter);

                var taskOfItems = queryOfItems.ToArrayAsync();
                var taskOfTotalCount = queryOfTotalCount.CountAsync();

                await Task.WhenAll(taskOfItems, taskOfTotalCount).WithCurrentCulture(false);

                result.Items = taskOfItems.Result.Select(x => CreateItem(x)).ToArray();
                result.TotalCount = taskOfTotalCount.Result;
            }

            return result;
        }

        /// <summary>
        /// Сохранить элемент.
        /// </summary>
        /// <param name="data">Данные для сохранения.</param>
        /// <returns>Задача с сохранёнными данными.</returns>
        public async Task<ModuleDummyOneToManyModelItem> SaveItem(ModuleDummyOneToManyModelItem data)
        {
            var result = new ModuleDummyOneToManyModelItem();

            if (data.ObjectDummyOneToMany != null)
            {
                result.ObjectDummyOneToMany = await SaveObjectDummyOneToMany(
                    data.ObjectDummyOneToMany
                    ).WithCurrentCulture(false);
            }

            return result;
        }

        public async Task DeleteItem(ModuleDummyOneToManyFilterItem filter)
        {
            using (var source = CreateDbContext())
            {
                var obj = source.DummyOneToMany.First(x => x.Id == filter.Id);

                source.DummyOneToMany.Remove(obj);

                await source.SaveChangesAsync().WithCurrentCulture(false);
            }
        }

        #endregion Public methods

        #region Private methods

        private ModuleDummyOneToManyModelItem CreateItem(DataEntityObjectDummyOneToMany entity)
        {
            var result = new ModuleDummyOneToManyModelItem();

            result.ObjectDummyOneToMany = entity.CreateObjectDummyOneToMany();

            return result;
        }

        private async Task<DataObjectDummyOneToMany> SaveObjectDummyOneToMany(
            DataObjectDummyOneToMany obj
            )
        {
            DataObjectDummyOneToMany result = null;

            using (var source = CreateDbContext())
            {
                if (obj.Id > 0)
                {
                    result = source.DummyOneToMany.First(x => x.Id == obj.Id);

                    var loader = new DataLoaderDummyOneToMany(result);

                    loader.LoadDataFrom(obj);
                }
                else
                {
                    result = source.DummyOneToMany.Add(DataEntityObjectDummyOneToMany.Create(obj)).Entity;
                }

                await source.SaveChangesAsync().WithCurrentCulture(false);
            }

            return result;
        }

        private DataEntityDbContext CreateDbContext()
        {
            var result = new DataEntityDbContext(DbContextOptions);

            result.Database.SetCommandTimeout(Config.DbCommandTimeout);

            return result;
        }

        #endregion Private methods
    }
}