using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Data.Entity;
using System.Data.Entity.Infrastructure;

using Model.Entities.Base;
using Model.Entities.Files;
using Model.UnitsOfWork;


namespace Model.Entities.Base
{
    public abstract class BaseRepository<T> where T : BaseEntity
    {

        protected readonly UOW UOW;
        protected Context context => UOW.context;

        //Иницилизация репозитория данного типа при первом запуске
        public abstract void RepoInit();
        public BaseRepository(UOW UOW)
        {
            //this.context = context;
            this.UOW = UOW;
        }


        protected DbSet<T> Set => context.Set<T>();
        public IQueryable<T> All => Set.AsQueryable();
        public IQueryable<T> All_NoTrack => Set.AsNoTracking().AsQueryable();

        public List<T> All_List => Set.ToList();
        public List<T> All_NoTrack_List => Set.AsNoTracking().ToList();


        public DbEntityEntry<T> GetEntry(T elem)
        {
            return context.Entry<T>(elem);
        }
        /// <summary>
        /// Используется чтобы запросить из базы сущность до модификации
        /// Есть некоторын проблемы с подрузкой связанных свойств см. Base_FS_Repository
        /// Общий вопрос: каким образом получить сущность до изменений (С запросом или без запроса к базе)?
        /// Context Entry позволяет отследить список измененнных свойсв связанных с базой, но не вычисляемых свойств.
        /// </summary>
        /// <param name="elem"></param>
        /// <returns></returns>
        //public virtual T GetFromDBNoChange(T elem)
        //{
        //    using (var context = new Context())
        //    {
        //        return context.Set<T>().
        //            FirstOrDefault(e => e.ID == elem.ID);
        //    }
        //}



        protected abstract void Validation_Create(T elem);
        public virtual T Create(T elem)
        {
            Validation_Create(elem);

            var res = Set.Add(elem);
            context.SaveChanges();

            return res;
        }


        protected abstract void Validation_Update(T old, T elem);
        public virtual void Update(T elem)
        {
            using (var ReadContext = new Context())
            {
                var change_entity = context.Set<T>().AsNoTracking().
                    FirstOrDefault(e => e.ID == elem.ID);

                if (change_entity == null)
                    throw new Exception("old value not found");

                Validation_Update(change_entity, elem);
            }

            context.SaveChanges();
        }


        protected abstract void Validation_Delete(T elem);
        public virtual void Delete(T elem)
        {
            Validation_Delete(elem);

            Set.Remove(elem);
            context.SaveChanges();
        }
        

    }
}
