using System.Linq.Expressions;
using Exam.Infrastructure.Data.Entity;
using Exam.Infrastructure.Extensions;
using Exam.Infrastructure.Validation.Exceptions;
using Exam.Infrastructure.Validation.Extensions;
using Exam.Infrastructure.Validation.Validation;
using FluentValidation;
using Hotline.Exams.Validate;
using Hotline.Repository.SqlSugar.DataPermissions;
using Hotline.Repository.SqlSugar.Exam.Interface;
using SqlSugar;
using XF.Domain.Entities;
using XF.Domain.Exceptions;

namespace Hotline.Repository.SqlSugar.Exam.Repositories
{
    public class ExamRepository<TEntity> : BaseRepository<TEntity>, IExamRepository<TEntity, HotlineDbContext> where TEntity : class, IEntity<string>, IHasCreationTime, IDataPermission, new()
    {
        public ExamRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
        {
            _uow = uow;
        }

        private readonly ISugarUnitOfWork<HotlineDbContext> _uow;
        public ISugarUnitOfWork<HotlineDbContext> UOW
        {
            get
            {
                return _uow;
            }
        }

        public AbstractValidator<TEntity> Validator { get; set; }

        #region public method
        public async Task<string> AddWithValidateAsync(TEntity entity, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entity,ValidatorTypeConstants.Create);

            return await base.AddAsync(entity, cancellationToken);
        }

        public async Task AddWithValidateAsync(List<TEntity> entities, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entities, ValidatorTypeConstants.Create);

            await base.AddRangeAsync(entities, cancellationToken);
        }

        public async Task ValidateAddAsync(List<TEntity> entities, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entities, ValidatorTypeConstants.Create);
        }

        public async Task ValidateUpdateAsync(List<TEntity> entities, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entities, ValidatorTypeConstants.Modify);
        }

        public async Task ValidateDeleteAsync(EntityQueryRequest entityQueryRequest, CancellationToken cancellationToken)
        {
            if (entityQueryRequest.Ids != null && entityQueryRequest.Ids.Any())
            {
                var entities = await base.QueryAsync(x => entityQueryRequest.Ids.Contains(x.Id));

                await DoValidationAsync(entities, ValidatorTypeConstants.Remove);

            }
            else if (entityQueryRequest.Id.IsNotNullOrEmpty())
            {
                var entity = new TEntity();
                entity.Id = entityQueryRequest.Id;

                await DoValidationAsync(entity, ValidatorTypeConstants.Remove);
            }
            else
            {
                if (entityQueryRequest.Expression == null) return;

                var entities = await base.QueryAsync((Expression<Func<TEntity, bool>>)entityQueryRequest.Expression);

                await DoValidationAsync(entities, ValidatorTypeConstants.Remove);

            }
        }

        public async Task DeleteWithValidateAsync(EntityQueryRequest entityQueryRequest, CancellationToken cancellationToken)
        {          

            if (entityQueryRequest.Ids != null && entityQueryRequest.Ids.Any())
            {
                var entities = await base.QueryAsync(x => entityQueryRequest.Ids.Contains(x.Id));

                await DoValidationAsync(entities, ValidatorTypeConstants.Remove);

                await base.RemoveRangeAsync(entities, cancellationToken);
            }
            else if(entityQueryRequest.Id.IsNotNullOrEmpty())
            {
                var entity = new TEntity();
                entity.Id = entityQueryRequest.Id;

                await DoValidationAsync(entity, ValidatorTypeConstants.Remove);

                await base.RemoveAsync(entityQueryRequest.Id);
            }
            else
            {
                if (entityQueryRequest.Expression == null) return;

                var entities = await base.QueryAsync((Expression<Func<TEntity, bool>>)entityQueryRequest.Expression);

                await DoValidationAsync(entities, ValidatorTypeConstants.Remove);

                await base.RemoveAsync((Expression<Func<TEntity, bool>>)entityQueryRequest.Expression, false, cancellationToken);
            }
        }

        public async Task UpdateWithValidateAsync(TEntity entity, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entity, ValidatorTypeConstants.Modify);

            await base.UpdateAsync(entity, cancellationToken);
        }

        public async Task UpdateWithValidateAsync(List<TEntity> entities, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entities, ValidatorTypeConstants.Modify);

            await base.UpdateRangeAsync(entities, cancellationToken);
        }
        #endregion

        #region protected method
        /// <summary>
        /// 验证
        /// </summary>
        /// <param name="entity"></param>
        /// <exception cref="NotImplementedException"></exception>
        protected async Task DoValidationAsync(TEntity entity, string validatorType)
        {
            if (Validator == null)
                throw new NotImplementedException("验证器未初始化");

            var validatorResult = await Validator.DoValidateAsync(entity, validatorType);
            if (!validatorResult.IsValid)
            {
                var errorMessages = validatorResult.ErrorItems.Select(x => x.ErrorMessage);
                //throw new UserFriendlyException(ExamErrorMessage.RequestFail,string.Join(";", errorMessages));
                throw UserFriendlyException.SameMessage(string.Join(";", errorMessages));
            }
        }

        /// <summary>
        /// 验证
        /// </summary>
        /// <param name="entity"></param>
        /// <exception cref="NotImplementedException"></exception>
        protected async Task DoValidationAsync(List<TEntity> entities, string validatorType)
        {
            if (Validator == null)
                throw new NotImplementedException("验证器未初始化");

            var domainException = new DomainException();
            foreach (var entity in entities)
            {
                var validatorResult = await Validator.DoValidateAsync(entity, validatorType);
                if (!validatorResult.IsValid)
                {
                    domainException.AddErrors(validatorResult);
                }
            }
            if (domainException.ValidationErrors.ErrorItems.Any())
            {
                var errorMessages = domainException.ValidationErrors.ErrorItems.Select(x => x.ErrorMessage);
                throw new UserFriendlyException(ExamErrorMessage.RequestFail, string.Join(";", errorMessages));
            }
        }

        public async Task ValidateAddAsync(TEntity entity, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entity, ValidatorTypeConstants.Create);
        }

        public async Task ValidateUpdateAsync(TEntity entity, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entity, ValidatorTypeConstants.Modify);
        }

        public async Task ValidateDeleteAsync(TEntity entity, CancellationToken cancellationToken)
        {
            await DoValidationAsync(entity, ValidatorTypeConstants.Remove);
        }
        #endregion
    }
}
