using Exam.Infrastructure.Data.Entity;
using Exam.Infrastructure.Enums;
using Exam.Infrastructure.Extensions;
using Exam.Share;
using Exam.Share.ViewResponses.Exam;
using Hotline.Application.Exam.Interface.ExamManages;
using Hotline.Repository.SqlSugar;
using Hotline.Repository.SqlSugar.DataPermissions;
using Hotline.Repository.SqlSugar.Exam.Interfaces.ExamManages;
using Hotline.Share.Requests.Exam;
using MapsterMapper;
using SqlSugar;
using XF.Domain.Dependency;
using XF.Domain.Entities;
using Hotline.Application.Exam.QueryExtensions.ExamManages;
using XF.Domain.Exceptions;
using Hotline.Application.Exam.Extensions;
using XF.Domain.Authentications;
using Hotline.Repository.SqlSugar.Exam.Core.Constants;
using Hotline.Exams.TestPapers;
using Hotline.Application.Exam.Proxy;
using Hotline.Repository.SqlSugar.Exam.Interfaces.TestPapers;
using Hotline.Repository.SqlSugar.Exam.Interfaces.Questions;
using Hotline.Users;
using Hotline.Application.Exam.Core.Extensions;
using Hotline.Application.Exam.Core.Utilities;
using Hotline.Exams.ExamManages;
using Hotline.Exams.Questions;
using Hotline.Repository.SqlSugar.Exam.Interfaces.Exams;
using Hotline.Repository.SqlSugar.Exam.Repositories;
using ExamErrorMessage = Hotline.Exams.Validate.ExamErrorMessage;
using ExamQuestion = Hotline.Exams.Questions.ExamQuestion;
using Hotline.Repository.SqlSugar.Exam.Service;
using Hotline.Repository.SqlSugar.Exam.Extensions;

namespace Hotline.Application.Exam.Service.ExamManages
{
    public class ExamManageService : ApiService<ExamManage, AddExamManageDto, UpdateExamManageDto, HotlineDbContext>, IExamManageService, IScopeDependency
    {
        private readonly IExamManageRepository _repository;
        private readonly IExamQuestionScoreRepository _examQuestionScoreRepository;
        private readonly IUserExamRepository _userExamRepository;
        private readonly IDataPermissionFilterBuilder _dataPermissionFilterBuilder;
        private readonly ITestPaperRepository _testPaperRepository;
        private readonly ITestPaperItemRepository _testPaperItemRepository;
        private readonly ITestPaperItemAnswerRepository _testPaperItemAnswerRepository;
        private readonly ITestPaperItemOptionsRepository _testPaperItemOptionsRepository;
        private readonly ITestPaperItemSourcewareRepository _testPaperItemSourcewareRepository;
        private readonly ITestPaperItemKnowladgeRepository _testPaperItemKnowladgeRepository;
        private readonly IExamQuestionRepository _examQuestionRepository;
        private readonly IExamQuestionAnswerRepository _examQuestionAnswerRepository;
        private readonly IExamQuestionOptionsRepository _examQuestionOptionsRepository;
        private readonly IExamQuestionSourcewareRepository _examQuestionSourcewareRepository;
        private readonly IExamQuestionKnowladgeRepository _examQuestionKnowladgeRepository;
        private readonly IServiceProvider _serviceProvider;
        private readonly IMapper _mapper;
        private readonly ISessionContext _sessionContext;
        private TestPaperProxy _testPaperProxy;
        private ExamManageProxy _examManageProxy;
        private AddExamManageDto _addExamManageDto;

        public ExamManageService(IExamManageRepository repository,
            IExamQuestionScoreRepository examQuestionScoreRepository,
            IUserExamRepository userExamRepository,
            ITestPaperRepository testPaperRepository,
            ITestPaperItemRepository testPaperItemRepository,
            ITestPaperItemAnswerRepository testPaperItemAnswerRepository,
            ITestPaperItemOptionsRepository testPaperItemOptionsRepository,
            ITestPaperItemSourcewareRepository testPaperItemSourcewareRepository,
            ITestPaperItemKnowladgeRepository testPaperItemKnowladgeRepository,
            IExamQuestionRepository examQuestionRepository,
            IExamQuestionAnswerRepository examQuestionAnswerRepository,
            IExamQuestionOptionsRepository examQuestionOptionsRepository,
            IExamQuestionSourcewareRepository examQuestionSourcewareRepository,
            IExamQuestionKnowladgeRepository examQuestionKnowladgeRepository,
            IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider,
            IMapper mapper, ISessionContext sessionContext) : base(repository, mapper, sessionContext)
        {
            this._repository = repository;
            this._examQuestionScoreRepository = examQuestionScoreRepository;
            this._userExamRepository = userExamRepository;
            _dataPermissionFilterBuilder = dataPermissionFilterBuilder;
            this._testPaperRepository = testPaperRepository;
            this._testPaperItemRepository = testPaperItemRepository;
            this._testPaperItemAnswerRepository = testPaperItemAnswerRepository;
            this._testPaperItemOptionsRepository = testPaperItemOptionsRepository;
            this._testPaperItemSourcewareRepository = testPaperItemSourcewareRepository;
            this._testPaperItemKnowladgeRepository = testPaperItemKnowladgeRepository;
            this._examQuestionRepository = examQuestionRepository;
            this._examQuestionAnswerRepository = examQuestionAnswerRepository;
            this._examQuestionOptionsRepository = examQuestionOptionsRepository;
            this._examQuestionSourcewareRepository = examQuestionSourcewareRepository;
            this._examQuestionKnowladgeRepository = examQuestionKnowladgeRepository;
            _serviceProvider = serviceProvider;
            this._mapper = mapper;
            this._sessionContext = sessionContext;
        }

        #region public method
        public async Task<ExamManageDto> GetAsync(EntityQueryRequest entityQueryRequest)
        {
            var entity = await _repository.GetAsync(entityQueryRequest.Id);

            if (entity == null) return null;

            var questionDto = _mapper.Map<ExamManageDto>(entity);

          

            if (questionDto != null)
            {
                questionDto.ExamQuestionScoreDtos = await GetExamQuestionScores(entityQueryRequest, entity);
                if (entity.Mode == Share.Enums.Exams.EMethod.Random)
                {
                    questionDto.TestPaperId = entity.ExtractRuleId;

                }

                questionDto.UserExamDtos = await GetUserExams(entityQueryRequest);
            }

            return questionDto;
        }

        public async Task<(int, List<ExamManageViewResponse>)> GetListAsync(ExamManagePagedRequest queryRequest)
        {
            ISugarQueryable<ExamManageViewResponse> queryable = Queryable(queryRequest);

            var result = await queryable.ToListAsync();

            var total = await queryable.CountAsync();

            return (total, result);
        }

        public async Task<PageViewResponse<ExamManageViewResponse>> GetPagedListAsync(ExamManagePagedRequest queryRequest)
        {
            ISugarQueryable<ExamManageViewResponse> queryable = Queryable(queryRequest);

            var list = await queryable.ToPageListAsync(queryRequest.PageIndex, queryRequest.PageSize);
            var total = await queryable.CountAsync();

            var result = new ExamManagePageViewResponse
            {
                Items = list,
                Pagination = new Pagination(queryRequest.PageIndex, queryRequest.PageSize, total)
            };

            return result;
        }

        public override async Task<string> AddAsync(AddExamManageDto actionRequest, CancellationToken cancellationToken)
        {
            CalcuteTotalScore(actionRequest);

            base.StartTran();

            var id = await base.AddAsync(actionRequest, cancellationToken);

            ResolveQuestionId(actionRequest, id);

            ResolveRandomExtractRuleId(actionRequest);

            base.Entity.ExamQuestionScores = await AddExamQuestionScores(actionRequest, cancellationToken);

            base.Entity.UserExams = await AddUserExam(actionRequest, cancellationToken);

            await base.Complete(base.Entity, OperationConstant.Create);

            await GenerateExamQuestion(new GenerateExamTestPaperRequest
            {
                TestPaperId = actionRequest.Mode == Share.Enums.Exams.EMethod.Unified ? actionRequest.TestPaperId : null,
                ExtractRuleId = actionRequest.Mode == Share.Enums.Exams.EMethod.Random ? actionRequest.TestPaperId : null,
                ExamManageId = id
            }, cancellationToken);

            return id;
        }

        private void ResolveRandomExtractRuleId(AddExamManageDto actionRequest)
        {
            if (actionRequest.Mode == Share.Enums.Exams.EMethod.Random)
            {
                base.Entity.ExtractRuleId = actionRequest.TestPaperId;
                base.Entity.TestPaperId = string.Empty;
            }
        }

        public override async Task UpdateAsync(UpdateExamManageDto actionRequest, CancellationToken cancellationToken)
        {
            CalcuteTotalScore(actionRequest);

            base.StartTran();

            await base.UpdateAsync(actionRequest, cancellationToken);

            ResolveQuestionId(actionRequest, actionRequest.Id);

            ResolveRandomExtractRuleId(actionRequest);

            MapAddUpdateExamManage(actionRequest);

            base.Entity.ExamQuestionScores = await ModifyExamQuestionScores(actionRequest, cancellationToken);

            base.Entity.UserExams = await ModifyUserExam(actionRequest, cancellationToken);

            await base.Complete(base.Entity, OperationConstant.Update);

            await GenerateExamQuestion(new GenerateExamTestPaperRequest { 
                TestPaperId = actionRequest.Mode == Share.Enums.Exams.EMethod.Unified? actionRequest.TestPaperId:null,
                ExtractRuleId = actionRequest.Mode == Share.Enums.Exams.EMethod.Random ? actionRequest.TestPaperId : null,
                ExamManageId = actionRequest.Id
            }, cancellationToken);

        }

        private void MapAddUpdateExamManage(UpdateExamManageDto actionRequest)
        {

            _addExamManageDto = _mapper.Map<AddExamManageDto>(actionRequest);

            _addExamManageDto.UserExamDtos = new List<AddUserExamDto>();

            _addExamManageDto.ExamQuestionScoreDtos = new List<AddExamQuestionScoreDto>();

			actionRequest.UserExamDtos.ForEach(x =>
            {
                x.OperationStatus = x.Id != null ? EEOperationStatus.Update : EEOperationStatus.Add;

                if(x.OperationStatus== EEOperationStatus.Add)
                {
                    _addExamManageDto.UserExamDtos.Add(_mapper.Map<AddUserExamDto>(x));
                }

            });
            actionRequest.ExamQuestionScoreDtos.ForEach(x =>
            {
                x.OperationStatus = x.Id != null ? EEOperationStatus.Update : EEOperationStatus.Add;

                if (x.OperationStatus == EEOperationStatus.Add)
                {
                    _addExamManageDto.ExamQuestionScoreDtos.Add(_mapper.Map<AddExamQuestionScoreDto>(x));
                }
            });

        }

        public override async Task DeleteAsync(EntityQueryRequest entityQueryRequest, CancellationToken cancellationToken)
        {
            await base.DeleteAsync(entityQueryRequest, cancellationToken);

            var tmpEntityQueryRequest = ExpressionableUtility.CreateExpression<ExamQuestionScoreBak>()
                .AndIF(entityQueryRequest.Id.IsNotNullOrEmpty(), x => x.ExamManageId == entityQueryRequest.Id)
                .AndIF(entityQueryRequest.Ids.IsNotNullOrEmpty(), x => entityQueryRequest.Ids.Contains(x.ExamManageId))
                .ToEntityQueryRequest<ExamQuestionScoreBak>();

            await DeleteExamQuestionScores(tmpEntityQueryRequest, cancellationToken);

            tmpEntityQueryRequest = ExpressionableUtility.CreateExpression<ExamUserExam>()
                .AndIF(entityQueryRequest.Id.IsNotNullOrEmpty(), x => x.ExamId == entityQueryRequest.Id)
                .AndIF(entityQueryRequest.Ids.IsNotNullOrEmpty(), x => entityQueryRequest.Ids.Contains(x.ExamId))
                .ToEntityQueryRequest<ExamUserExam>();

            await DeleteUserExam(tmpEntityQueryRequest, cancellationToken);

        }

        public async Task GenerateTestPaper(GenerateExamTestPaperRequest generateExamTestPaperRequest, CancellationToken cancellationToken)
        {
            var expression = generateExamTestPaperRequest.GetExpression();
            var examManage = await _repository.GetAsync(expression);
            if (examManage != null)
            {
                var tagQuestionCounts = await GetTagQuestions(examManage);
                var questions = await GetQuestions(tagQuestionCounts);

                _testPaperProxy = new TestPaperProxy(_testPaperRepository,
                    _testPaperItemRepository,
                    _testPaperItemAnswerRepository,
                    _testPaperItemOptionsRepository,
                    _testPaperItemSourcewareRepository,
                    _testPaperItemKnowladgeRepository,
                    _dataPermissionFilterBuilder,
                    _serviceProvider,
                    _mapper,
                    _sessionContext
                    );

                await _testPaperProxy.DeleteTestPaperItems(generateExamTestPaperRequest.TestPaperId, cancellationToken);

                await _testPaperProxy.GenerateQuestion(questions, generateExamTestPaperRequest.TestPaperId, cancellationToken);
            }
        }

        public async Task GenerateExamQuestion(GenerateExamTestPaperRequest generateExamTestPaperRequest, CancellationToken cancellationToken)
        {
            var expression = generateExamTestPaperRequest.GetExpression();
            var examManages = await _repository.Queryable().Where(expression).ToListAsync();
            var examManage = examManages.FirstOrDefault();
            if (examManage != null)
            {
                var questions = new List<ExamQuestion>();
                if (examManage.Mode == Share.Enums.Exams.EMethod.Random)
                {
                    var tagQuestionCounts = await GetTagQuestions(examManage);
                    questions = await GetQuestions(tagQuestionCounts);
                }
                else
                {
                    questions = await GetQuestions(examManage);
                }

                _examManageProxy = new ExamManageProxy(_repository,
                    _examQuestionRepository,
                    _examQuestionAnswerRepository,
                    _examQuestionOptionsRepository,
                    _examQuestionSourcewareRepository,
                    _examQuestionKnowladgeRepository,
                    _dataPermissionFilterBuilder,
                    _serviceProvider,
                    _mapper,
                    _sessionContext
                    );

                await _examManageProxy.DeleteExamQuestions(generateExamTestPaperRequest.ExamManageId, cancellationToken);

                await _examManageProxy.GenerateQuestion(questions, generateExamTestPaperRequest.ExamManageId, cancellationToken);
            }
        }

        public async Task UpdateExamStatus(EntityQueryRequest entityQueryRequest, CancellationToken requestAborted)
        {
            List<ExamManage> examManages = await UpdateExamManageStatus(entityQueryRequest, requestAborted);

            await UdpateUserExam(examManages, requestAborted);

        }
        #endregion

        #region private method

        private void ResolveQuestionId(AddExamManageDto actionRequest, string id)
        {

            actionRequest.UserExamDtos.ForEach(x => x.ExamId = id);

            actionRequest.ExamQuestionScoreDtos.ForEach(x => x.ExamManageId = id);
        }

        private void ResolveQuestionId(UpdateExamManageDto actionRequest, string id)
        {

            actionRequest.UserExamDtos.ForEach(x => x.ExamId = id);

            actionRequest.ExamQuestionScoreDtos.ForEach(x => x.ExamManageId = id);
        }

        private async Task<List<ExamQuestionScoreBak>> AddExamQuestionScores(AddExamManageDto actionRequest, CancellationToken cancellationToken)
        {
            if (actionRequest.ExamQuestionScoreDtos == null) return null;

            actionRequest.ExamQuestionScoreDtos.ResolveOperationStatus();

            var examQuestionScoreDtos = actionRequest.ExamQuestionScoreDtos.Where(x => x.OperationStatus == EEOperationStatus.Add).ToList();

            var examQuestionScores = _mapper.Map<List<ExamQuestionScoreBak>>(examQuestionScoreDtos);

            examQuestionScores.ToInsert(_sessionContext);

            await _examQuestionScoreRepository.ValidateAddAsync(examQuestionScores, cancellationToken);

            return examQuestionScores;
        }

        private async Task<List<ExamUserExam>> AddUserExam(AddExamManageDto actionRequest, CancellationToken cancellationToken)
        {
            if (actionRequest.UserExamDtos == null) return null;

            actionRequest.UserExamDtos.ResolveOperationStatus();

            var userExamDtos = actionRequest.UserExamDtos.Where(x => x.OperationStatus == EEOperationStatus.Add).ToList();

            var userExams = new List<ExamUserExam>();
            //_mapper.Map<List<UserExam>>(userExamDtos);

            userExamDtos.ForEach(x =>
            {
                userExams.Add(_mapper.Map<ExamUserExam>(x));
            });

            userExams.ToInsert(_sessionContext);

            await _userExamRepository.ValidateAddAsync(userExams, cancellationToken);

            return userExams;

        }
        private async Task<List<ExamUserExam>> UpdateUserExam(UpdateExamManageDto actionRequest, List<ExamUserExam> all, CancellationToken cancellationToken)
        {
            if (actionRequest.UserExamDtos == null) return null;

            var userExamDtos = actionRequest.UserExamDtos.Where(x => x.OperationStatus == EEOperationStatus.Update).ToList();

            var ids = userExamDtos.Select(x => x.Id);

            var userExams = all.Where(x => ids.Contains(x.Id)).ToList();

            //userExams = _mapper.Map<List<UpdateUserExamDto>, List<UserExam>>(userExamDtos, userExams);
            userExams.ForEach(item =>
            {
                var userExamDto = userExamDtos.FirstOrDefault(x => x.Id == item.Id);

                if (userExamDto != null)
                    _mapper.Map<UpdateUserExamDto, ExamUserExam>(userExamDto, item);
            });

            userExams.ToUpdate(_sessionContext);

            await _userExamRepository.ValidateUpdateAsync(userExams, cancellationToken);

            return userExams;
        }

        private async Task<List<ExamQuestionScoreBak>> UpdateExamQuestionScores(UpdateExamManageDto actionRequest, List<ExamQuestionScoreBak> all, CancellationToken cancellationToken)
        {
            if (actionRequest.ExamQuestionScoreDtos == null) return null;

            var examQuestionScoreDtos = actionRequest.ExamQuestionScoreDtos.Where(x => x.OperationStatus == EEOperationStatus.Update).ToList();

            var ids = examQuestionScoreDtos.Select(x => x.Id);

            var examQuestionScores = all.Where(x => ids.Contains(x.Id)).ToList();

            //examQuestionScores = _mapper.Map<List<UpdateExamQuestionScoreDto>, List<ExamQuestionScore>>(examQuestionScoreDtos, examQuestionScores);

            examQuestionScores.ForEach(item =>
            {
                var examQuestionScoreDto = examQuestionScoreDtos.FirstOrDefault(x => x.Id == item.Id);
                if (examQuestionScoreDto != null)
                    item = _mapper.Map<UpdateExamQuestionScoreDto, ExamQuestionScoreBak>(examQuestionScoreDto, item);
            });

            examQuestionScores.ToUpdate(_sessionContext);

            await _examQuestionScoreRepository.ValidateUpdateAsync(examQuestionScores, cancellationToken);

            return examQuestionScores;
        }

        private async Task DeleteUserExam(EntityQueryRequest entityQueryRequest, CancellationToken cancellationToken)
        {
            await _userExamRepository.DeleteWithValidateAsync(entityQueryRequest, cancellationToken);
        }

        private async Task DeleteExamQuestionScores(EntityQueryRequest entityQueryRequest, CancellationToken cancellationToken)
        {
            await _examQuestionScoreRepository.DeleteWithValidateAsync(entityQueryRequest, cancellationToken);
        }

        private async Task<List<ExamUserExam>> ModifyUserExam(UpdateExamManageDto actionRequest, CancellationToken cancellationToken)
        {
            if (actionRequest.UserExamDtos == null) return null;

            var all = await _userExamRepository.Queryable().Where(x => x.ExamId == actionRequest.Id).ToListAsync();

            actionRequest.UserExamDtos.ResolveOperationStatus(all);

            var userExams = new List<ExamUserExam>();

            userExams.AddRangeExt(await AddUserExam(_addExamManageDto, cancellationToken));

            userExams.AddRangeExt(await UpdateUserExam(actionRequest, all, cancellationToken));

            var questionOptionsDtos = actionRequest.UserExamDtos.Where(x => x.OperationStatus == EEOperationStatus.Delete);
            var ids = questionOptionsDtos.Select(m => m.Id);
            EntityQueryRequest entityQueryRequest = ResovleDelete<ExamUserExam>(ids);

            await DeleteUserExam(entityQueryRequest, cancellationToken);

            return userExams;

        }

        private async Task<List<ExamQuestionScoreBak>> ModifyExamQuestionScores(UpdateExamManageDto actionRequest, CancellationToken cancellationToken)
        {
            if (actionRequest.ExamQuestionScoreDtos == null) return null;

            var all = await _examQuestionScoreRepository.Queryable().Where(x => x.ExamManageId == actionRequest.Id).ToListAsync();

            var examQuestionScores = new List<ExamQuestionScoreBak>();

            examQuestionScores.AddRangeExt(await AddExamQuestionScores(_addExamManageDto, cancellationToken));

            examQuestionScores.AddRangeExt(await UpdateExamQuestionScores(actionRequest, all, cancellationToken));

            var examQuestionScoreDtos = actionRequest.ExamQuestionScoreDtos.Where(x => x.OperationStatus == EEOperationStatus.Delete);
            var ids = examQuestionScoreDtos.Select(m => m.Id);
            EntityQueryRequest entityQueryRequest = ResovleDelete<ExamQuestionScoreBak>(ids);

            await DeleteExamQuestionScores(entityQueryRequest, cancellationToken);

            return examQuestionScores;
        }

        private EntityQueryRequest ResovleDelete<T>(IEnumerable<string> ids) where T : class, IEntity<string>, new()
        {
            Expressionable<T> expressionable = ExpressionableUtility.CreateExpression<T>();
            expressionable.AndIF(ids.Any(), x => ids.Contains(x.Id));

            var entityQueryRequest = new EntityQueryRequest
            {
                Expression = ids.Any() ? expressionable.ToExpression() : null
            };
            return entityQueryRequest;
        }

        private async Task<List<UserExamDto>> GetUserExams(EntityQueryRequest entityQueryRequest)
        {
            var userRepository = new ExamRepository<User>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var userExams = _userExamRepository.Queryable().Where(x => x.ExamId == entityQueryRequest.Id);
            var userTable = userRepository.Queryable();


            var userExamDtos = userExams.InnerJoin(userTable,(e,u)=>e.UserId == u.Id).Select((e, u) => new UserExamDto
            {
                Id = e.Id,
                Name = u.Name,
                ExamId = e.ExamId,
                UserId = e.UserId,
                FullOrgName = u.FullOrgName
            });

            return await userExamDtos.ToListAsync();
        }

        private async Task<List<ExamQuestionScoreDto>> GetExamQuestionScores(EntityQueryRequest entityQueryRequest,ExamManage examManage)
        {
            var examQuestionScores = _examQuestionScoreRepository.Queryable().Where(x => x.ExamManageId == entityQueryRequest.Id);

            var examQuestionScoreDtos = examQuestionScores.Select(q => new ExamQuestionScoreDto
            {
                Id = q.Id,
                QuestionType = q.QuestionType,
                ExamManageId = q.ExamManageId,
                Score = q.Score
            });

            if(examManage.Mode == Share.Enums.Exams.EMethod.Random)
            {
                var tagQuestionRepository = new ExamRepository<ExamTagQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
                var tagQuestionTable = tagQuestionRepository.Queryable().Where(x => x.RuleId == examManage.ExtractRuleId);

                var result = examQuestionScoreDtos.InnerJoin(tagQuestionTable, (e, t) => e.QuestionType == t.QuestionType).Select((e, t) => new ExamQuestionScoreDto
                {
                    Id = e.Id,
                    QuestionType = e.QuestionType,
                    ExamManageId = e.ExamManageId,
                    Score = e.Score,
                    Count = t.Count
                }).Distinct();
                return await result.ToListAsync();
            }
            else
            {
                var testPaperItemRepository = new ExamRepository<ExamTestPaperItem>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
                var testPaperItemTable = testPaperItemRepository.Queryable().Where(x => x.TestPaperId == examManage.TestPaperId);

                var result = examQuestionScoreDtos.InnerJoin(testPaperItemTable, (e, t) => e.QuestionType == t.QuestionType)
                    .GroupBy((e, t) => new
                    {
                        Id = e.Id,
                        QuestionType = e.QuestionType,
                        ExamManageId = e.ExamManageId,
                        Score = e.Score,
                    })
                    .Select((e, t) => new ExamQuestionScoreDto
                {
                    Id = e.Id,
                    QuestionType = e.QuestionType,
                    ExamManageId = e.ExamManageId,
                    Score = e.Score,
                    Count = SqlFunc.AggregateCount(t.Id)
                });
                return await result.ToListAsync();
            }           
        }
        private void CalcuteTotalScore(AddExamManageDto actionRequest)
        {
            if (actionRequest.ExamQuestionScoreDtos == null) return;

            var examQuestionScoreDtos = actionRequest.ExamQuestionScoreDtos.Where(x => x.OperationStatus != EEOperationStatus.Delete);

            var totalScore = examQuestionScoreDtos.Sum(x => x.Count * x.Score);
            if (totalScore != actionRequest.TotalScore)
            {
                throw new UserFriendlyException(ExamErrorMessage.ServiceError, string.Format(ExamErrorMessage.IsNotEqual, "试题分数总和", typeof(AddExamManageDto).GetDescription(nameof(AddExamManageDto.TotalScore))));
            }
        }



        private ISugarQueryable<ExamManageViewResponse> Queryable(ExamManagePagedRequest queryRequest)
        {
            var expression = queryRequest.GetExpression();
            var questionTable = _repository.Queryable().Where(expression);

            var queryable = questionTable.OrderBy(e => e.CreationTime).Select(e => new ExamManageViewResponse
            {
                Id = e.Id,
                Code = e.Code,
                Count = e.Count,
                CutoffScore = e.CutoffScore,
                EndTime = e.EndTime,
                ExamStatus = e.ExamStatus,
                ExamType = e.ExamType,
                Mode = e.Mode,
                Name = e.Name,
                Remark = e.Name,
                SortIndex = e.SortIndex,
                StartTime = e.StartTime,
                TimeSpan = e.TimeSpan,
                TotalScore = e.TotalScore,
            });
            return queryable;
        }


        private async Task<List<ExamQuestion>> GetQuestions(List<ExamTagQuestion> tagQuestionCounts)
        {
            var questionRepository = new ExamRepository<ExamQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var questionTagRepository = new ExamRepository<ExamQuestionTag>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var questionTable = questionRepository.Queryable();
            var questionTagTable = questionTagRepository.Queryable();

            if (tagQuestionCounts != null && tagQuestionCounts.Any())
            {
                var questionQuerables = new List<ISugarQueryable<ExamQuestion>>();
                tagQuestionCounts.ForEach(item =>
                {
                    ISugarQueryable<ExamQuestion> queryable = questionRepository.Queryable().InnerJoin(questionTagTable, (q, t) => q.Id == t.QuestionId)
                        .Where((q, t) => q.QuestionType == item.QuestionType && t.TagId == item.TagId).Take(item.Count).Select((q, t) => q);

                    questionQuerables.Add(queryable);
                });

                var queryResult = questionRepository.UnionAll(questionQuerables.ToArray());

                return await queryResult.ToListAsync();
            }
            else
            {
                return null;
            }

        }

        private async Task<List<ExamQuestion>> GetQuestions(ExamManage examManage)
        {
            var questionRepository = new ExamRepository<ExamQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var questionTable = questionRepository.Queryable();
            var testPaperItemTable = _testPaperItemRepository.Queryable().Where(x => x.TestPaperId == examManage.TestPaperId);

            var questions = questionTable.InnerJoin(testPaperItemTable, (q, t) => q.Id == t.QuestionId)
                .Select((q, t) => q);

            return await questions.ToListAsync();
        }

        private async Task<List<ExamTagQuestion>> GetTagQuestions(ExamManage examManage)
        {
            var extractRuleRepository = new ExamRepository<ExamExtractRule>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var ruleTagRepository = new ExamRepository<ExamRuleTag>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var tagQuestionRepository = new ExamRepository<ExamTagQuestion>(_uow, _dataPermissionFilterBuilder, _serviceProvider);


            var extractRuleTable = extractRuleRepository.Queryable().Where(x => x.Id == examManage.ExtractRuleId && x.RuleType == examManage.ExamType);
            var ruleTagTable = ruleTagRepository.Queryable();
            var tagQuestionTable = tagQuestionRepository.Queryable();

            var tagQuestions = await tagQuestionTable
                .InnerJoin(ruleTagTable, (q, rt) => q.TagId == rt.TagId)
                .InnerJoin(extractRuleTable, (q, rt, x) => rt.RuleId == x.Id)
                .Select((q, rt, x) => q).ToListAsync();

            return tagQuestions;

        }


        private async Task UdpateUserExam(List<ExamManage> examManages, CancellationToken requestAborted)
        {
            var examIds = examManages.Select(x => x.Id).ToList();
            var userExams = await _userExamRepository.Queryable().Where(x => examIds.Contains(x.ExamId)).ToListAsync();

            userExams.ForEach(item =>
            {
                item.ExamStatus = item.ExamStatus== Share.Enums.Exams.EExamStatus.NoStart? Share.Enums.Exams.EExamStatus.Absent: item.ExamStatus;
            });

            userExams.ToUpdate(_sessionContext);

            await _userExamRepository.UpdateWithValidateAsync(userExams, requestAborted);
        }

        private async Task<List<ExamManage>> UpdateExamManageStatus(EntityQueryRequest entityQueryRequest, CancellationToken requestAborted)
        {
            var queryable = _repository.Queryable()
                .WhereIF(entityQueryRequest != null && entityQueryRequest.Ids != null, x => entityQueryRequest.Ids.Contains(x.Id))
                .Where(x => x.EndTime < DateTime.Now && x.ExamStatus != Share.Enums.Exams.EExamStatus.Complete);
            var examManages = await queryable.ToListAsync();

            examManages.ForEach(item =>
            {
                item.ExamStatus = Share.Enums.Exams.EExamStatus.Complete;
            });

            examManages.ToUpdate(_sessionContext);

            await _repository.UpdateWithValidateAsync(examManages, requestAborted);

            return examManages;
        }
        #endregion
    }
}
