using Hotline.Repository.SqlSugar;
using Hotline.Repository.SqlSugar.DataPermissions;
using Hotline.Repository.SqlSugar.Exam.Extensions;
using Hotline.Repository.SqlSugar.Exam.Interfaces.ExamManages;
using Hotline.Repository.SqlSugar.Exam.Interfaces.Exams;
using Hotline.Repository.SqlSugar.Exam.Interfaces.Questions;
using Hotline.Repository.SqlSugar.Exam.Repositories;
using MapsterMapper;
using SqlSugar;
using XF.Domain.Authentications;
using ExamQuestion = Hotline.Exams.Questions.ExamQuestion;
using ExamQuestionAnswer = Hotline.Exams.Questions.ExamQuestionAnswer;
using ExamQuestionKnowladge = Hotline.Exams.Questions.ExamQuestionKnowladge;
using ExamQuestionOptions = Hotline.Exams.Questions.ExamQuestionOptions;
using ExamQuestionSourceware = Hotline.Exams.Questions.ExamQuestionSourceware;

namespace Hotline.Application.Exam.Proxy
{
    public class ExamManageProxy
    {
        private readonly IExamManageRepository _repository;
        private readonly IExamQuestionRepository _examQuestionRepository;
        private readonly IExamQuestionAnswerRepository _examQuestionAnswerRepository;
        private readonly IExamQuestionOptionsRepository _examQuestionOptionsRepository;
        private readonly IExamQuestionSourcewareRepository _examQuestionSourcewareRepository;
        private readonly IExamQuestionKnowladgeRepository _examQuestionKnowladgeRepository;
        private readonly IDataPermissionFilterBuilder _dataPermissionFilterBuilder;
        private readonly IServiceProvider _serviceProvider;
        private readonly IMapper _mapper;
        private readonly ISessionContext _sessionContext;
		private readonly ISugarUnitOfWork<HotlineDbContext> _uow;

		public ExamManageProxy(IExamManageRepository repository,
            IExamQuestionRepository examQuestionRepository,
            IExamQuestionAnswerRepository examQuestionAnswerRepository,
            IExamQuestionOptionsRepository examQuestionOptionsRepository,
            IExamQuestionSourcewareRepository examQuestionSourcewareRepository,
            IExamQuestionKnowladgeRepository examQuestionKnowladgeRepository,
            IDataPermissionFilterBuilder dataPermissionFilterBuilder,
            IServiceProvider serviceProvider,
            IMapper mapper, ISessionContext sessionContext)
        {
            this._repository = repository;
            this._examQuestionRepository = examQuestionRepository;
            this._examQuestionAnswerRepository = examQuestionAnswerRepository;
            this._examQuestionOptionsRepository = examQuestionOptionsRepository;
            this._examQuestionSourcewareRepository = examQuestionSourcewareRepository;
            this._examQuestionKnowladgeRepository = examQuestionKnowladgeRepository;
            this._dataPermissionFilterBuilder = dataPermissionFilterBuilder;
            this._serviceProvider = serviceProvider;
            this._mapper = mapper;
            this._sessionContext = sessionContext;
            this._uow = repository.UOW;
        }

        #region public method
        public async Task GenerateQuestion(List<ExamQuestion> questions, string testPaperId, CancellationToken cancellationToken)
        {
            List<Exams.ExamManages.ExamQuestionBak> examQuestions = await SyncQuestion(questions, testPaperId, cancellationToken);

            var examQuestionOptionses = await SyncQuestionOptions(examQuestions, cancellationToken);
            var examQuestionSourcewares = await SyncQuestionSourcewares(examQuestions, cancellationToken);
            var examQuestionKnowladges = await SyncQuestionKnowladge(examQuestions, cancellationToken);
            var examQuestionAnswers = await SyncQuestionAnswer(examQuestions, cancellationToken);

            examQuestions.ForEach(item =>
            {
                item.ExamQuestionOptionses = examQuestionOptionses.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.ExamQuestionOptionses.ForEach(x =>
                {
                    x.ExamQuestionId = item.Id;
                });
                item.ExamQuestionSourcewares = examQuestionSourcewares.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.ExamQuestionSourcewares.ForEach(x =>
                {
                    x.ExamQuestionId = item.Id;
                });
                item.ExamQuestionKnowladges = examQuestionKnowladges.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.ExamQuestionKnowladges.ForEach(x =>
                {
                    x.ExamQuestionId = item.Id;
                });
                
                item.ExamQuestionAnswers = examQuestionAnswers.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.ExamQuestionAnswers.ForEach(x =>
                {
                    x.ExamQuestionId = item.Id;
                });
            });

            await _examQuestionRepository.AddNav(examQuestions)
                .Include(x => x.ExamQuestionAnswers)
                .Include(x => x.ExamQuestionKnowladges)
                .Include(x => x.ExamQuestionOptionses)
                .Include(x => x.ExamQuestionSourcewares)
                .ExecuteCommandAsync();
        }


        public async Task DeleteExamQuestions(string testPaperId, CancellationToken cancellationToken)
        {
            var examQuestionIds = await _examQuestionRepository.Queryable().Where(x => x.ExamId == testPaperId).Select(x => x.Id).ToListAsync();

            await _examQuestionRepository.RemoveAsync(x => examQuestionIds.Contains(x.Id));

            await _examQuestionAnswerRepository.RemoveAsync(x => examQuestionIds.Contains(x.ExamQuestionId));

            await _examQuestionKnowladgeRepository.RemoveAsync(x => examQuestionIds.Contains(x.ExamQuestionId));

            await _examQuestionOptionsRepository.RemoveAsync(x => examQuestionIds.Contains(x.ExamQuestionId));

            await _examQuestionSourcewareRepository.RemoveAsync(x => examQuestionIds.Contains(x.ExamQuestionId));
        }

        #endregion

        #region private method


        private async Task<List<Exams.ExamManages.ExamQuestionAnswerBak>> SyncQuestionAnswer(List<Exams.ExamManages.ExamQuestionBak> examQuestions, CancellationToken cancellationToken)
        {
            var questionAnswersRepository = new ExamRepository<ExamQuestionAnswer>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var questionIds = examQuestions.Select(x => x.QuestionId);
            var questionAnswers = await questionAnswersRepository.Queryable().Where(x => questionIds.Contains(x.QuestionId)).ToListAsync();

            var examQuestionAnswers = new List<Exams.ExamManages.ExamQuestionAnswerBak>();

            questionAnswers.ForEach(item =>
            {
                var examQuestionAnswer = _mapper.Map<Exams.ExamManages.ExamQuestionAnswerBak>(item);
                var examQuestion = examQuestions.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                examQuestionAnswer.QuestionAnswerId = item.Id;
                examQuestionAnswer.ExamQuestionId = examQuestion?.Id ?? string.Empty;
                examQuestionAnswers.Add(examQuestionAnswer);
            });

            examQuestionAnswers.ToInsert(_sessionContext);

            await _examQuestionAnswerRepository.ValidateAddAsync(examQuestionAnswers, cancellationToken);

            return examQuestionAnswers;
        }

        private async Task<List<Exams.ExamManages.ExamQuestionKnowladgeBak>> SyncQuestionKnowladge(List<Exams.ExamManages.ExamQuestionBak> examQuestions, CancellationToken cancellationToken)
        {
            var questionKnowladgesRepository = new ExamRepository<ExamQuestionKnowladge>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var questionIds = examQuestions.Select(x => x.QuestionId);
            var questionKnowladges = await questionKnowladgesRepository.Queryable().Where(x => questionIds.Contains(x.QuestionId)).ToListAsync();

            var examQuestionKnowladges = new List<Exams.ExamManages.ExamQuestionKnowladgeBak>();

            questionKnowladges.ForEach(item =>
            {
                var examQuestionKnowladge = _mapper.Map<Exams.ExamManages.ExamQuestionKnowladgeBak>(item);
                var examQuestion = examQuestions.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                examQuestionKnowladge.KnowladgeId = item.Id;
                examQuestionKnowladge.ExamQuestionId = examQuestion?.Id ?? string.Empty;
                examQuestionKnowladges.Add(examQuestionKnowladge);
            });

            examQuestionKnowladges.ToInsert(_sessionContext);

            await _examQuestionKnowladgeRepository.ValidateAddAsync(examQuestionKnowladges, cancellationToken);

            return examQuestionKnowladges;
        }

        private async Task<List<Exams.ExamManages.ExamQuestionSourcewareBak>> SyncQuestionSourcewares(List<Exams.ExamManages.ExamQuestionBak> examQuestions, CancellationToken cancellationToken)
        {
            var questionSourcewaresRepository = new ExamRepository<ExamQuestionSourceware>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var questionIds = examQuestions.Select(x => x.QuestionId);
            var questionSourcewares = await questionSourcewaresRepository.Queryable().Where(x => questionIds.Contains(x.QuestionId)).ToListAsync();

            var examQuestionSourcewares = new List<Exams.ExamManages.ExamQuestionSourcewareBak>();

            questionSourcewares.ForEach(item =>
            {
                var examQuestionSourceware = _mapper.Map<Exams.ExamManages.ExamQuestionSourcewareBak>(item);
                var examQuestion = examQuestions.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                examQuestionSourceware.SourcewareId = item.Id;
                examQuestionSourceware.ExamQuestionId = examQuestion?.Id ?? string.Empty;
                examQuestionSourcewares.Add(examQuestionSourceware);
            });

            examQuestionSourcewares.ToInsert(_sessionContext);

            await _examQuestionSourcewareRepository.ValidateAddAsync(examQuestionSourcewares, cancellationToken);

            return examQuestionSourcewares;
        }

        private async Task<List<Exams.ExamManages.ExamQuestionOptionsBak>> SyncQuestionOptions(List<Exams.ExamManages.ExamQuestionBak> examQuestions, CancellationToken cancellationToken)
        {
            var questionOptionsRepository = new ExamRepository<ExamQuestionOptions>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var questionIds = examQuestions.Select(x => x.QuestionId);
            var questionOptions = await questionOptionsRepository.Queryable().Where(x => questionIds.Contains(x.QuestionId)).ToListAsync();

            var examQuestionOptions = new List<Exams.ExamManages.ExamQuestionOptionsBak>();

            questionOptions.ForEach(item =>
            {
                var examQuestionOption = _mapper.Map<Exams.ExamManages.ExamQuestionOptionsBak>(item);
                var examQuestion = examQuestions.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                examQuestionOption.QuestionOptionId = item.Id;
                examQuestionOption.ExamQuestionId = examQuestion?.Id ?? string.Empty;
                examQuestionOptions.Add(examQuestionOption);
            });

            examQuestionOptions.ToInsert(_sessionContext);

            await _examQuestionOptionsRepository.ValidateAddAsync(examQuestionOptions, cancellationToken);

            return examQuestionOptions;
        }

        private async Task<List<Exams.ExamManages.ExamQuestionBak>> SyncQuestion(List<ExamQuestion> questions, string testPaperId, CancellationToken cancellationToken)
        {

            var examQuestions = new List<Exams.ExamManages.ExamQuestionBak>();

            questions.ForEach(item =>
            {
                var examQuestion = _mapper.Map<Exams.ExamManages.ExamQuestionBak>(item);
                examQuestion.ExamId = testPaperId;
                examQuestion.QuestionId = item.Id;
                examQuestions.Add(examQuestion);
            });

            examQuestions.ToInsert(_sessionContext);

            await _examQuestionRepository.ValidateAddAsync(examQuestions, cancellationToken);

            return examQuestions;
        }
        #endregion
    }
}
