using Hotline.Exams.TestPapers;
using Hotline.Repository.SqlSugar;
using Hotline.Repository.SqlSugar.DataPermissions;
using Hotline.Repository.SqlSugar.Exam.Interfaces.Questions;
using Hotline.Repository.SqlSugar.Exam.Interfaces.TestPapers;
using MapsterMapper;
using SqlSugar;
using System.Threading;
using Hotline.Exams.Questions;
using Hotline.Repository.SqlSugar.Exam.Repositories;
using XF.Domain.Authentications;
using XF.Domain.Repository;
using Hotline.Repository.SqlSugar.Exam.Extensions;

namespace Hotline.Application.Exam.Proxy
{
    public class TestPaperProxy
    {
        private readonly ITestPaperRepository _repository;
        private readonly ITestPaperItemRepository _testPaperItemRepository;
        private readonly ITestPaperItemAnswerRepository _testPaperItemAnswerRepository;
        private readonly ITestPaperItemOptionsRepository _testPaperItemOptionsRepository;
        private readonly ITestPaperItemSourcewareRepository _testPaperItemSourcewareRepository;
        private readonly ITestPaperItemKnowladgeRepository _testPaperItemKnowladgeRepository;
        private readonly IDataPermissionFilterBuilder _dataPermissionFilterBuilder;
        private readonly IServiceProvider _serviceProvider;
        private readonly IMapper _mapper;
        private readonly ISessionContext _sessionContext;
        private readonly ISugarUnitOfWork<HotlineDbContext> _uow;
        public TestPaperProxy(ITestPaperRepository repository,
            ITestPaperItemRepository testPaperItemRepository,
            ITestPaperItemAnswerRepository testPaperItemAnswerRepository,
            ITestPaperItemOptionsRepository testPaperItemOptionsRepository,
            ITestPaperItemSourcewareRepository testPaperItemSourcewareRepository,
            ITestPaperItemKnowladgeRepository testPaperItemKnowladgeRepository,
            IDataPermissionFilterBuilder dataPermissionFilterBuilder,
            IServiceProvider serviceProvider,
            IMapper mapper,ISessionContext sessionContext)
        {
            this._repository = repository;
            this._testPaperItemRepository = testPaperItemRepository;
            this._testPaperItemAnswerRepository = testPaperItemAnswerRepository;
            this._testPaperItemOptionsRepository = testPaperItemOptionsRepository;
            this._testPaperItemSourcewareRepository = testPaperItemSourcewareRepository;
            this._testPaperItemKnowladgeRepository = testPaperItemKnowladgeRepository;
            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<ExamTestPaperItem> testPaperItems = await SyncQuestion(questions, testPaperId, cancellationToken);

            var testPaperItemOptionses = await SyncQuestionOptions(testPaperItems, cancellationToken);
            var testPaperItemSourcewares = await SyncQuestionSourcewares(testPaperItems, cancellationToken);
            var testPaperItemKnowladges = await SyncQuestionKnowladge(testPaperItems, cancellationToken);
            var testPaperItemAnswers = await SyncQuestionAnswer(testPaperItems, cancellationToken);

            testPaperItems.ForEach(item =>
            {
                item.TestPaperItemOptionses = testPaperItemOptionses.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.TestPaperItemOptionses.ForEach(x =>
                {
                    x.TestPaperItemId = item.Id;
                });
                item.TestPaperItemSourcewares = testPaperItemSourcewares.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.TestPaperItemSourcewares.ForEach(x =>
                {
                    x.TestPaperItemId = item.Id;
                });
                item.TestPaperItemKnowlagdes = testPaperItemKnowladges.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.TestPaperItemKnowlagdes.ForEach(x =>
                {
                    x.TestPaperItemId = item.Id;
                });
                item.TestPaperItemAnswers = testPaperItemAnswers.Where(x => item.QuestionId == x.QuestionId).ToList();
                item.TestPaperItemAnswers.ForEach(x =>
                {
                    x.TestPaperItemId = item.Id;
                });
            });

            await _testPaperItemRepository.AddNav(testPaperItems)
                .Include(x => x.TestPaperItemAnswers)
                .Include(x => x.TestPaperItemKnowlagdes)
                .Include(x => x.TestPaperItemOptionses)
                .Include(x => x.TestPaperItemSourcewares)
                .ExecuteCommandAsync();
        }
       
        
        public async Task DeleteTestPaperItems(string testPaperId, CancellationToken cancellationToken)
        {
            var testPaperItemIds = await _testPaperItemRepository.Queryable().Where(x => x.TestPaperId == testPaperId).Select(x=>x.Id).ToListAsync();

            await _testPaperItemRepository.RemoveAsync(x => testPaperItemIds.Contains(x.Id));

            await _testPaperItemAnswerRepository.RemoveAsync(x => testPaperItemIds.Contains(x.TestPaperItemId));

            await _testPaperItemKnowladgeRepository.RemoveAsync(x => testPaperItemIds.Contains(x.TestPaperItemId));

            await _testPaperItemOptionsRepository.RemoveAsync(x => testPaperItemIds.Contains(x.TestPaperItemId));

            await _testPaperItemSourcewareRepository.RemoveAsync(x => testPaperItemIds.Contains(x.TestPaperItemId));
        }

        #endregion

        #region private method


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

            var testPaperItemAnswers = new List<ExamTestPaperItemAnswer>();

            questionAnswers.ForEach(item =>
            {
                var testPaperItemAnswer = _mapper.Map<ExamTestPaperItemAnswer>(item);
                var testPaperItem = testPaperItems.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                testPaperItemAnswer.QuestionAnswerId = item.Id;
                testPaperItemAnswer.TestPaperItemId = testPaperItem?.Id ?? string.Empty;
                testPaperItemAnswers.Add(testPaperItemAnswer);
            });

            testPaperItemAnswers.ToInsert(_sessionContext);

            await _testPaperItemAnswerRepository.ValidateAddAsync(testPaperItemAnswers, cancellationToken);

            return testPaperItemAnswers;
        }

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

            var testPaperItemKnowladges = new List<ExamTestPaperItemKnowladge>();

            questionKnowladges.ForEach(item =>
            {
                var testPaperItemKnowladge = _mapper.Map<ExamTestPaperItemKnowladge>(item);
                var testPaperItem = testPaperItems.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                testPaperItemKnowladge.KnowladgeId = item.Id;
                testPaperItemKnowladge.TestPaperItemId = testPaperItem?.Id ?? string.Empty;
                testPaperItemKnowladges.Add(testPaperItemKnowladge);
            });

            testPaperItemKnowladges.ToInsert(_sessionContext);

            await _testPaperItemKnowladgeRepository.ValidateAddAsync(testPaperItemKnowladges, cancellationToken);

            return testPaperItemKnowladges;
        }

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

            var testPaperItemSourcewares = new List<ExamTestPaperItemSourceware>();

            questionSourcewares.ForEach(item =>
            {
                var testPaperItemSourceware = _mapper.Map<ExamTestPaperItemSourceware>(item);
                var testPaperItem = testPaperItems.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                testPaperItemSourceware.SourcewareId = item.Id;
                testPaperItemSourceware.TestPaperItemId = testPaperItem?.Id ?? string.Empty;
                testPaperItemSourcewares.Add(testPaperItemSourceware);
            });

            testPaperItemSourcewares.ToInsert(_sessionContext);

            await _testPaperItemSourcewareRepository.ValidateAddAsync(testPaperItemSourcewares, cancellationToken);

            return testPaperItemSourcewares;
        }

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

            var testPaperItemOptions = new List<ExamTestPaperItemOptions>();

            questionOptions.ForEach(item =>
            {
                var testPaperItemOption = _mapper.Map<ExamTestPaperItemOptions>(item);
                var testPaperItem = testPaperItems.FirstOrDefault(x => x.QuestionId == item.QuestionId);
                testPaperItemOption.QuestionOptionId = item.Id;
                testPaperItemOption.TestPaperItemId = testPaperItem?.Id ?? string.Empty;
                testPaperItemOptions.Add(testPaperItemOption);
            });

            testPaperItemOptions.ToInsert(_sessionContext);

            await _testPaperItemOptionsRepository.ValidateAddAsync(testPaperItemOptions, cancellationToken);

            return testPaperItemOptions;
        }

        private async Task<List<ExamTestPaperItem>> SyncQuestion(List<ExamQuestion> questions, string testPaperId, CancellationToken cancellationToken)
        {

            var testPaperItems = new List<ExamTestPaperItem>();

            questions.ForEach(item =>
            {
                var testPaperItem = _mapper.Map<ExamTestPaperItem>(item);
                testPaperItem.TestPaperId = testPaperId;
                testPaperItem.QuestionId = item.Id;
                testPaperItems.Add(testPaperItem);
            });

            testPaperItems.ToInsert(_sessionContext);

            await _testPaperItemRepository.ValidateAddAsync(testPaperItems, cancellationToken);

            return testPaperItems;
        }
        #endregion
    }
}
