using System;
using System.Linq.Expressions;
using Abp.EntityFrameworkCore;
using Abp.Events.Bus.Entities;
using Abp.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;

namespace YGNT.Infrastructure.AbpEntity
{
    public class BaseDbContext : AbpDbContext
    {
        /// <summary>Constructor.</summary>
        public BaseDbContext(DbContextOptions options) : base(options)
        {
        }

        protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
        {
            if (typeof(IDelete).IsAssignableFrom(typeof(TEntity)))
            {
                return true;
            }
            return base.ShouldFilterEntity<TEntity>(entityType);
        }

        protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
        {
            Expression<Func<TEntity, bool>> expression = base.CreateFilterExpression<TEntity>();
            if (typeof(IDelete).IsAssignableFrom(typeof(TEntity)))
            {
                Expression<Func<TEntity, bool>> softDeleteFilter = e => ((IDelete)e).DelStatus != 2;
                expression = expression == null ? softDeleteFilter : CombineExpressions(expression, softDeleteFilter);
            }
            return expression;
        }

        protected override void ApplyAbpConceptsForModifiedEntity(EntityEntry entry, long? userId, EntityChangeReport changeReport)
        {
            if (entry.Entity is IDelete && entry.Entity.As<IDelete>().DelStatus == 2)
            {
                SetDeletionAuditProperties(entry.Entity, userId);
                changeReport.ChangedEntities.Add(new EntityChangeEntry(entry.Entity, EntityChangeType.Deleted));
            }
            base.ApplyAbpConceptsForModifiedEntity(entry, userId, changeReport);
        }

        protected override void CancelDeletionForSoftDelete(EntityEntry entry)
        {
            base.CancelDeletionForSoftDelete(entry);
            if (!(entry.Entity is IDelete))
            {
                return;
            }
            entry.Reload();
            entry.State = EntityState.Modified;
            entry.Entity.As<IDelete>().DelStatus = 2;
        }
    }
}