using System.Collections.Generic;
using System.Linq;
using Unity;
using VCommon.Ioc;
using VCommon.VApplication.Authorization;
using VCommon.VEntity;
using VCommon.VEntityFrameworkCore;

namespace VCommon.VApplication.EntityFrameworkCore
{
    public class VAppEfRepository<TDbContext, TEntity> : VEfRepositoryBase<TDbContext, TEntity> where TEntity : VEntityBase where TDbContext : VAppDbContextBase
    {
        [Dependency]
        public IVSession VSession { get; set; }

        [Dependency]
        public IIocManager IocManager { get; set; }

        private readonly Dictionary<string, bool> _filterState = new()
        {
            { VAppEfDataFilters.MayHaveTenant, true },
            { VAppEfDataFilters.MustHaveTenant, true },
            { VAppEfDataFilters.MustHaveOrg, true },
        };

        public override VEfRepositoryBase<TDbContext, TForkEntity> ForkRepository<TForkEntity>()
        {
            return new VAppEfRepository<TDbContext, TForkEntity> { DbContext = DbContext };
        }

        protected override TDbContext ResolveDbContextInstance() => IocManager.Resolve<TDbContext>();

        protected override IQueryable<TEntity> ProcessFilters(IQueryable<TEntity> input)
        {
            if (_filterState[VAppEfDataFilters.MayHaveTenant] && typeof(TEntity).IsAssignableTo(typeof(IMayHaveTenant)))
            {
                input = input.Where(p => ((IMayHaveTenant)p).TenantId == VSession.TenantId);
            }

            if (_filterState[VAppEfDataFilters.MustHaveTenant] && typeof(TEntity).IsAssignableTo(typeof(IMustHaveTenant)))
            {
                input = input.Where(p => ((IMustHaveTenant)p).TenantId == VSession.TenantId);
            }

            if (_filterState[VAppEfDataFilters.MustHaveOrg]
                && typeof(TEntity).IsAssignableTo(typeof(IMustHaveOrg))
                && IocManager.TryResolve(out IOrgManager orgManager) && orgManager.Enabled)
            {
                var visionOrg = orgManager.GetUserVisionOrg(VSession.TenantId, VSession.UserId);
                input = input.Where(p => visionOrg.Contains(((IMustHaveOrg)p).OrgId));
            }

            return base.ProcessFilters(input);
        }

        public override TEntity Add(TEntity entity)
        {
            if (IsFilterEnabled(VAppEfDataFilters.MustHaveTenant) && entity is IMustHaveTenant mte) mte.TenantId = VSession.GetTenantId();

            if (_filterState[VAppEfDataFilters.MustHaveOrg]
                && typeof(TEntity).IsAssignableTo(typeof(IMustHaveOrg))
                && IocManager.TryResolve(out IOrgManager orgManager) && orgManager.Enabled)
            {
                var visionOrg = orgManager.GetUserVisionOrg(VSession.TenantId, VSession.UserId);
                if (false == visionOrg.Contains(((IMustHaveOrg)entity).OrgId)) throw new VApplicationAuthException("拒绝访问：您没有权限访问该组织", AuthReason.AccessDenied);
            }

            return base.Add(entity);
        }

        public override void EnableFilter(string filterName)
        {
            if (_filterState.ContainsKey(filterName)) _filterState[filterName] = true;
            else base.EnableFilter(filterName);
        }

        public override void DisableFilter(string filterName)
        {
            if (_filterState.ContainsKey(filterName)) _filterState[filterName] = false;
            else base.EnableFilter(filterName);
        }

        public override bool IsFilterEnabled(string filterName)
        {
            return _filterState.ContainsKey(filterName)
                ? _filterState[filterName]
                : base.IsFilterEnabled(filterName);
        }
    }
}
