using Exam.Infrastructure.Data.Entity;
using Exam.Infrastructure.Validation.Validation;
using Exam.Share.Dtos.Trains;
using Exam.Share.ViewResponses.Train;
using Hotline.Application.Exam.Core.Extensions;
using Hotline.Application.Exam.Interface.Train;
using Hotline.Application.Exam.QueryExtensions.Trains;
using Hotline.Exams.Practices;
using Hotline.Exams.Sourcewares;
using Hotline.Exams.Trains;
using Hotline.Repository.SqlSugar;
using Hotline.Repository.SqlSugar.DataPermissions;
using Hotline.Repository.SqlSugar.Exam.Interfaces.Trains;
using Hotline.Share.Dtos.Questions;
using Hotline.Share.Dtos.Trains;
using Hotline.Share.Requests.Exam;
using Hotline.Share.Requests.Train;
using Hotline.Share.ViewResponses.Trains;
using Hotline.Users;
using MapsterMapper;
using Train.Application.Interface.Train;
using XF.Domain.Authentications;
using XF.Domain.Dependency;
using XF.Domain.Exceptions;
using Hotline.Share.Exams.Extensions;
using NPOI.SS.Formula.Functions;
using Hotline.Repository.SqlSugar.Exam.Repositories.Trains;
using static NPOI.HSSF.Util.HSSFColor;
using DocumentFormat.OpenXml.Drawing.Charts;
using Hotline.Repository.SqlSugar.Exam.Repositories;
using JiebaNet.Segmenter.Common;
using Hotline.Repository.SqlSugar.Exam.Service;
using Hotline.Repository.SqlSugar.Exam.Extensions;
using DocumentFormat.OpenXml.Office2010.Excel;
using SqlSugar;

namespace Hotline.Application.Exam.Service.Trains
{
    public class TrainRecordService : ApiService<ExamTrainRecord, AddTrainRecordDto, UpdateTrainRecordDto, HotlineDbContext>, ITrainRecordService, IScopeDependency
    {
        private readonly ITrainRecordRepository _repository;
        private readonly ITrainRecordAnswerRepository _trainRecordAnswerRepository;
        private readonly ITrainRecordItemRepository _trainRecordItemRepository;
        private readonly ITrainKnowladgeRepository _trainKnowladgeRepository;
        private readonly IMapper _mapper;
        private readonly IDataPermissionFilterBuilder _dataPermissionFilterBuilder;
        private readonly IServiceProvider _serviceProvider;
        private readonly ISessionContext _sessionContext;

        public TrainRecordService(ITrainRecordRepository repository,
            ITrainRecordAnswerRepository trainRecordAnswerRepository,
            ITrainRecordItemRepository trainRecordItemRepository,
            ITrainKnowladgeRepository trainKnowladgeRepository,
            IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider,
            ISessionContext sessionContext,
            IMapper mapper) : base(repository, mapper, sessionContext)
        {
            this._repository = repository;
            this._trainRecordAnswerRepository = trainRecordAnswerRepository;
            this._trainRecordItemRepository = trainRecordItemRepository;
            this._trainKnowladgeRepository = trainKnowladgeRepository;
            this._mapper = mapper;
            this._dataPermissionFilterBuilder = dataPermissionFilterBuilder;
            this._serviceProvider = serviceProvider;
            this._sessionContext = sessionContext;
        }

        #region public method
        public async Task CompleteTrainRecordAsync(CompleteTrainRecordDto completeTrainRecordDto, CancellationToken cancellationToken)
        {
            var trainRecord = await _repository.GetAsync(x => x.Id == completeTrainRecordDto.Id);
            trainRecord = _mapper.Map<CompleteTrainRecordDto, ExamTrainRecord>(completeTrainRecordDto, trainRecord);
            trainRecord.ToUpdate(_sessionContext);

            await _repository.UpdateWithValidateAsync(trainRecord, cancellationToken);
        }

        public async Task CompleteTrainKnowladgeAsync(CompleteTrainKnowladgeDto completeTrainPracticeDto, CancellationToken cancellationToken)
        {
            var trainKnowladge = _mapper.Map<ExamTrainKnowladge>(completeTrainPracticeDto);

            trainKnowladge.ToUpdate(_sessionContext);

            await _trainKnowladgeRepository.UpdateWithValidateAsync(trainKnowladge, cancellationToken);

        }

        public async Task<TrainRecordDto> GetAsync(EntityQueryRequest entityQueryRequest)
        {
            var trainRecord = await _repository.GetAsync(entityQueryRequest.Id);

            var trainRecordDto = _mapper.Map<TrainRecordDto>(trainRecord);

            trainRecordDto.KnowladgeDtos = await GetKnowladges(entityQueryRequest);

            trainRecordDto.QuestionDtos = await GetQuestions(entityQueryRequest);

            return trainRecordDto;

        }

        public async Task<(int, List<TrainRecordViewResponse>)> GetListAsync(TrainRecordPagedRequest queryRequest)
        {
            SqlSugar.ISugarQueryable<TrainRecordViewResponse> queryResult = QueryResult(queryRequest);

            var total = await queryResult.CountAsync();
            var items = await queryResult.ToListAsync();

            return (total, items);
        }

        public async Task<PageViewResponse<TrainRecordViewResponse>> GetPagedListAsync(TrainRecordPagedRequest queryRequest)
        {
            SqlSugar.ISugarQueryable<TrainRecordViewResponse> queryResult = QueryResult(queryRequest);

            var total = await queryResult.CountAsync();
            var items = await queryResult.ToPageListAsync(queryRequest.PageIndex, queryRequest.PageSize);

            return new TrainRecordPageViewResponse
            {
                Items = items,
                Pagination = new Pagination(queryRequest.PageIndex, queryRequest.PageSize, total)
            };

        }

        public async Task<TrainPracticeDto> TrainAsync(AddTrainDto addTrainDto, CancellationToken cancellationToken)
        {
            await GetTrainPracticeKnowladge(addTrainDto, cancellationToken);

            await AddTrainRecordItem(addTrainDto, cancellationToken);

            await AddTrainRecordAnswer(addTrainDto, cancellationToken);

            //var trainPracticeOptionsDtos = await GetTrainQuestionOptions(addTrainDto);

            return null;
        }

        private async Task GetTrainPracticeKnowladge(AddTrainDto addTrainDto, CancellationToken cancellationToken)
        {
            var trainPracticeKnowladeRepository = new TrainPracticeKnowladgeRepository(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPracticeKnowladge = await trainPracticeKnowladeRepository.GetAsync(x => x.TrainPracticeId == addTrainDto.TrainPracticeId);

            if (trainPracticeKnowladge != null)
            {
                addTrainDto.TrainKnowladgeId = trainPracticeKnowladge.Id;
                addTrainDto.QuestionId = trainPracticeKnowladge.QuestionId;
            }
        }

        public async Task<TrainPracticeDto> GetTrainPracticeAsync(TrainPracticeRequest trainPracticeRequest)
        {
            SqlSugar.ISugarQueryable<ExamTrainPractice> trainPractices = GetTrainPractices(trainPracticeRequest);

            var trainPractice = await trainPractices.FirstAsync();

            if (trainPractice == null) return null;

            var trainPracticeDto = _mapper.Map<TrainPracticeDto>(trainPractice);

            trainPracticeRequest.TrainPracticeId = trainPractice.Id;

            trainPracticeDto.TrainPracticeOptionsDtos = await GetTrainQuestionOptions(trainPracticeRequest);

            trainPracticeDto.TrainPracticeSourcewareDtos = await GetTrainPracticeSourcewares(trainPracticeRequest);

            trainPracticeDto.TrainPracticeKnowladgeDtos = await GetTrainPracticeKnowladges(trainPracticeRequest);

            trainPracticeDto.AddTrainRecordAnswerDto = await GetTrainRecordAnswer(trainPracticeRequest);

            return trainPracticeDto;
        }

        private async Task<AddTrainRecordAnswerDto?> GetTrainRecordAnswer(TrainPracticeRequest trainPracticeRequest)
        {
            var trainRecordAnswerRepository = new ExamRepository<ExamTrainRecordAnswer>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var queryable = trainRecordAnswerRepository.Queryable()
               .InnerJoin<ExamTrainRecord>((t, x) => t.TrainRecordId == x.Id)
               .InnerJoin<ExamTrainPlanTemplate>((t, x, p) => x.TrainPlanId == p.TrainPlanId)
               .InnerJoin<ExamTrainPractice>((t, x, p, tp) => p.TrainTemplateId == tp.TrainTemplateId)
               .Where((t, x, p, tp) => tp.Id == trainPracticeRequest.TrainPracticeId)
               .Select((t, x, p, tp) => t);

            var examTrainRecordAnswer = await queryable
                .FirstAsync();

            var addTrainRecordAnswerDto = _mapper.Map<ExamTrainRecordAnswer, AddTrainRecordAnswerDto>(examTrainRecordAnswer);

            return addTrainRecordAnswerDto;
        }

        public async Task<SimpleTrainPracticeDto> GetSimpleTrainPracticeAsync(TrainPracticeRequest trainPracticeRequest)
        {
            SqlSugar.ISugarQueryable<ExamTrainPractice> trainPractices = GetTrainPractices(trainPracticeRequest);

            var trainPractice = await trainPractices.FirstAsync();

            if (trainPractice == null) return null;

            var trainPracticeDto = _mapper.Map<TrainPracticeDto>(trainPractice);

            trainPracticeRequest.TrainPracticeId = trainPractice.Id;

            trainPracticeDto.TrainPracticeOptionsDtos = await GetTrainQuestionOptions(trainPracticeRequest);

            return trainPracticeDto;
        }

        public async Task<TrainResultPagedViewResponse> AnalysisTrainResult(TrainResultReportPagedRequest trainResultReportPagedRequest)
        {
            if(trainResultReportPagedRequest.EndTime == null)
            trainResultReportPagedRequest.ResolveEndTime();

            var expression = trainResultReportPagedRequest.GetExpression();
            var templateExpression = trainResultReportPagedRequest.GetTemplateExpression();

            var trainTemplateRepostitory = new ExamRepository<ExamTrainTemplate>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanRepository = new ExamRepository<ExamTrainPlan>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanTemplateRepository = new ExamRepository<ExamTrainPlanTemplate>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var userRepository = new ExamRepository<User>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var trainPlanTable = trainPlanRepository.Queryable().Where(expression);
            var trainTemplateTable = trainTemplateRepostitory.Queryable().Where(templateExpression);
            var trainPlanTemplateTable = trainPlanTemplateRepository.Queryable();
            var trainRecordTable = _repository.Queryable();
            var userTable = userRepository.Queryable();

            var queryResult = trainRecordTable.InnerJoin(trainPlanTable, (r, p) => r.TrainPlanId == p.Id)
                .InnerJoin(trainPlanTemplateTable, (r, p, pt) => p.Id == pt.TrainPlanId)
                .InnerJoin(trainTemplateTable, (r, p, pt, t) => pt.TrainTemplateId == t.Id)
                .InnerJoin(userTable, (r, p, pt, t, u) => r.UserId == u.Id)
                .Select((r, p, pt, t, u) => new TrainResultViewResponse
                {
                    TrainName = t.Name,
                    UserName = u.Name,
                    IsComplete = r.IsComplete,
                    SortIndex = r.SortIndex,
                    Status = r.Status
                })
                .MergeTable()
               .OrderByPropertyNameIF(!string.IsNullOrEmpty(trainResultReportPagedRequest.SortField), trainResultReportPagedRequest.SortField, (OrderByType)(trainResultReportPagedRequest.SortRule ?? 0));

            var total = await queryResult.CountAsync();

            var items = trainResultReportPagedRequest.IsPaged ?
                await queryResult.ToPageListAsync(trainResultReportPagedRequest.PageIndex, trainResultReportPagedRequest.PageSize)
                : await queryResult.ToListAsync();
                ;

            return new TrainResultPagedViewResponse
            {
                Items = items,
                Pagination = new Pagination(trainResultReportPagedRequest.PageIndex, trainResultReportPagedRequest.PageSize, total)
            };
        }

        public async Task<TrainResultRateViewResponse> CalcuteAnalysisRate(TrainResultReportPagedRequest trainResultReportPagedRequest)
        {
            if (trainResultReportPagedRequest.EndTime == null)
                trainResultReportPagedRequest.ResolveEndTime();

            var expression = trainResultReportPagedRequest.GetExpression();
            var templateExpression = trainResultReportPagedRequest.GetTemplateExpression();

            var trainTemplateRepostitory = new ExamRepository<ExamTrainTemplate>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanRepository = new ExamRepository<ExamTrainPlan>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanTemplateRepository = new ExamRepository<ExamTrainPlanTemplate>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var trainPlanTable = trainPlanRepository.Queryable().Where(expression);
            var trainTemplateTable = trainTemplateRepostitory.Queryable().Where(templateExpression);
            var trainPlanTemplateTable = trainPlanTemplateRepository.Queryable();
            var trainRecordTable = _repository.Queryable();

            var queryResult = trainRecordTable.InnerJoin(trainPlanTable, (r, p) => r.TrainPlanId == p.Id)
                .InnerJoin(trainPlanTemplateTable, (r, p, pt) => p.Id == pt.TrainPlanId)
                .InnerJoin(trainTemplateTable, (r, p, pt, t) => pt.TrainTemplateId == t.Id)
                .Select((r, p, pt, t) => new TrainResultViewResponse
                {
                    TrainName = t.Name,
                    IsComplete = r.IsComplete,
                    SortIndex = r.SortIndex,
                    Status = r.Status,
                    TrainTime = p.TrainEndTime
                }).MergeTable();

            var calcuteRateResult = new TrainResultRateViewResponse
            {
                Complete = await queryResult.CountAsync(x => x.IsComplete),
                Trainning = await queryResult.CountAsync(x => !x.IsComplete && x.TrainTime > DateTime.Now),
                UnComplete = await queryResult.CountAsync(x => !x.IsComplete && x.TrainTime <= DateTime.Now),
            };

            return calcuteRateResult;
        }
        #endregion

        #region private method


        private async Task AddTrainRecordItem(AddTrainDto addTrainDto, CancellationToken cancellationToken)
        {
            var trainRecordItem = _mapper.Map<ExamTrainRecordItem>(addTrainDto);

            trainRecordItem.ToInsert(_sessionContext);

            await _trainRecordItemRepository.AddWithValidateAsync(trainRecordItem, cancellationToken);
        }

        private SqlSugar.ISugarQueryable<TrainRecordViewResponse> QueryResult(TrainRecordPagedRequest queryRequest)
        {
            var trainPlanRepository = new TrainPlanRepository(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            queryRequest.UserId = _sessionContext.UserId;
            var expression = queryRequest.GetExpression();
            var trainPlanTable = trainPlanRepository.Queryable().Where(expression);
            var traiRecordExpression = queryRequest.GetTrainRecordExpression();
            var trainRecordTable = _repository.Queryable().Where(traiRecordExpression);

            var queryResult = trainPlanTable.InnerJoin(trainRecordTable, (p, r) => p.Id == r.TrainPlanId)
                            .Select((p, r) => new TrainRecordViewResponse
                            {
                                Id = r.Id,
                                TrainCode = p.Code,
                                TrainName = p.Name,
                                IsComplete = r.IsComplete,
                                Status = r.Status,
                                SortIndex = r.SortIndex,
                                TrainEndTime = p.TrainEndTime,
                                TrainStartTime = p.TrainStartTime
                            });
            return queryResult;
        }

        private async Task<List<SimpleQuestionDto>> GetQuestions(EntityQueryRequest entityQueryRequest)
        {
            SqlSugar.ISugarQueryable<SimpleQuestionDto> queryable = QueryQuestions(entityQueryRequest);

            return await queryable.ToListAsync();

        }

        private SqlSugar.ISugarQueryable<SimpleQuestionDto> QueryQuestions(EntityQueryRequest entityQueryRequest)
        {
            SqlSugar.ISugarQueryable<ExamTrainRecord, ExamTrainPlan, ExamTrainPlanTemplate, ExamTrainPractice> queryable = QuestionQueryable(entityQueryRequest);

            var result = queryable.Select((r, p, tpt, tp) => new SimpleQuestionDto
            {
                Title = tp.Title,
                Id = tp.Id
            });
            return result;
        }

        private SqlSugar.ISugarQueryable<ExamTrainRecord, ExamTrainPlan, ExamTrainPlanTemplate, ExamTrainPractice> QuestionQueryable(EntityQueryRequest entityQueryRequest)
        {
            var trainPlanRepository = new ExamRepository<ExamTrainPlan>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPracticeRepository = new ExamRepository<ExamTrainPractice>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanTemplateRepository = new ExamRepository<ExamTrainPlanTemplate>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var trainRecordTable = _repository.Queryable().Where(x => x.Id == entityQueryRequest.Id);
            var trainPlanTable = trainPlanRepository.Queryable();
            var trainPracticeTable = trainPracticeRepository.Queryable();
            var trainPlanTemplateTable = trainPlanTemplateRepository.Queryable();

            var queryable = trainRecordTable.InnerJoin(trainPlanTable, (r, p) => r.TrainPlanId == p.Id)
                .InnerJoin(trainPlanTemplateTable, (r, p, tpt) => p.Id == tpt.TrainPlanId)
                .InnerJoin(trainPracticeTable, (r, p, tpt, tp) => tpt.TrainTemplateId == tp.TrainTemplateId);
            return queryable;
        }

        private async Task<List<SimpleKnowladgeDto>> GetKnowladges(EntityQueryRequest entityQueryRequest)
        {
            var questionTable = QuestionQueryable(entityQueryRequest);
            var questionKnowladgeRepository = new ExamRepository<ExamTrainPracticeKnowladge>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var knowledgeRepository = new ExamRepository<KnowledgeBase.Knowledge>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var questionKnowladgeTable = questionKnowladgeRepository.Queryable();
            var knowledgeTable = knowledgeRepository.Queryable();

            var queryable = questionTable.InnerJoin(questionKnowladgeTable, (r, p, tpt, tp, ExamPracticeQuestionKnowledge) => tp.QuestionId == ExamPracticeQuestionKnowledge.QuestionId)
                .InnerJoin(knowledgeTable, (r, p, tpt, tp, ExamPracticeQuestionKnowledge, kl) => ExamPracticeQuestionKnowledge.KnowladgeId == kl.Id)
                .GroupBy((r, p, tpt, tp, ExamPracticeQuestionKnowledge, kl) => new
                {
                    Title = kl.Title,
                    Id = kl.Id
                })
                .Select((r, p, tpt, tp, ExamPracticeQuestionKnowledge, kl) => new SimpleKnowladgeDto
                {
                    Title = kl.Title,
                    Id = kl.Id
                });

            return await queryable.ToListAsync();
        }


        private async Task AddTrainRecordAnswer(AddTrainDto addTrainDto, CancellationToken cancellationToken)
        {
            if (addTrainDto.AddTrainRecordOptionDtos == null && addTrainDto.AddTrainRecordAnswerDto == null) return;

            var trainRecordAnswers = new List<ExamTrainRecordAnswer>();

            addTrainDto.AddTrainRecordOptionDtos?.ForEach(item =>
            {
                item.TrainRecordId = addTrainDto.TrainRecordId;
                var traiRecordAnswer = _mapper.Map<ExamTrainRecordAnswer>(item);
                traiRecordAnswer.QuestionId = addTrainDto.QuestionId;
                trainRecordAnswers.Add(traiRecordAnswer);
            });

            if (addTrainDto.AddTrainRecordAnswerDto != null)
            {
                addTrainDto.AddTrainRecordAnswerDto.TrainRecordId = addTrainDto.TrainRecordId;
                addTrainDto.AddTrainRecordAnswerDto.QuestionId = addTrainDto.QuestionId;
                trainRecordAnswers.Add(_mapper.Map<ExamTrainRecordAnswer>(addTrainDto.AddTrainRecordAnswerDto));
            }

            trainRecordAnswers.ToInsert(_sessionContext);

            await _trainRecordAnswerRepository.AddWithValidateAsync(trainRecordAnswers, cancellationToken);
        }

        //private async Task<TrainPracticeDto> GetTrainQuestionOptions(AddTrainDto addTrainDto)
        //{
        //    var trainPracticeOptionsRepository = new ExamRepository<ExamTrainPracticeOptions>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
        //    var trainPracticeRepository = new ExamRepository<ExamTrainPractice>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

        //    // TODO: 获取未答题的第一道题
        //    var trainPractice = await trainPracticeRepository.Queryable()
        //        .Where(x => x.TrainTemplateId == addTrainDto.TrainTemplateId && x.Id!= addTrainDto.TrainPracticeId).OrderBy(x=>x.SortIndex).FirstAsync();

        //    var trainPracticeOptions = await trainPracticeOptionsRepository.Queryable().Where(x => x.TrainPracticeId == trainPractice.Id).ToListAsync();

        //    var trainPracticeOptionsDtos = new List<SimpleTrainPracticeOptionsDto>();

        //    trainPracticeOptions.ForEach(x =>
        //    {
        //        trainPracticeOptionsDtos.Add(_mapper.Map<SimpleTrainPracticeOptionsDto>(x));
        //    });

        //    var trainPracticeDto = _mapper.Map<TrainPracticeDto>(trainPractice);
        //    trainPracticeDto.TrainPracticeOptionsDtos = trainPracticeOptionsDtos;

        //    return trainPracticeDto;
        //}

        private SqlSugar.ISugarQueryable<ExamTrainPractice> GetTrainPractices(TrainPracticeRequest trainPracticeRequest)
        {
            var trainPracticeRepostitory = new TrainPracticeRepository(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanRepository = new TrainPlanRepository(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainPlanTemplateRepository = new TrainPlanTemplateRepository(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var trainRecordTable = _repository.Queryable().Where(x => x.Id == trainPracticeRequest.Id);
            var trainPlanTable = trainPlanRepository.Queryable();
            var trainPracticeTable = trainPracticeRepostitory.Queryable().WhereIF(!string.IsNullOrEmpty(trainPracticeRequest.TrainPracticeId), x => x.Id == trainPracticeRequest.TrainPracticeId);
            var tranPlanTemplateTable = trainPlanTemplateRepository.Queryable();

            var trainPractices = trainPracticeTable.InnerJoin(tranPlanTemplateTable, (tp, tpt) => tp.TrainTemplateId == tpt.TrainTemplateId)
                .InnerJoin(trainPlanTable, (tp, tpt, tpn) => tpt.TrainPlanId == tpn.Id)
                .InnerJoin(trainRecordTable, (tp, tpt, tpn, tr) => tpn.Id == tr.TrainPlanId)
                .Select((tp, tpt, tpn, tr) => tp)
                .OrderBy(tp => tp.CreationTime);
            return trainPractices;
        }

        private async Task<List<SimpleTrainPracticeOptionsDto>> GetTrainQuestionOptions(TrainPracticeRequest trainPracticeRequest)
        {
            var trainPracticeOptionsRepository = new ExamRepository<ExamTrainPracticeOptions>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var trainRecordAnswerRepository = new ExamRepository<ExamTrainRecordAnswer>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            // TODO: 获取未阅卷的第一道题
            var trainPractices = GetTrainPractices(trainPracticeRequest);

            var trainPracticeOptions = await trainPracticeOptionsRepository.Queryable()
                .InnerJoin(trainPractices, (tpo, tp) => tpo.TrainPracticeId == tp.Id)
                .Where((tpo, tp) => tp.Id == trainPracticeRequest.TrainPracticeId)
                .Select((tpo, tp) => tpo).ToListAsync();

            var queryable = trainRecordAnswerRepository.Queryable()
                .InnerJoin<ExamTrainRecord>((t, x) => t.TrainRecordId == x.Id)
                .InnerJoin<ExamTrainPlanTemplate>((t, x, p) => x.TrainPlanId == p.TrainPlanId)
                .InnerJoin<ExamTrainPractice>((t, x, p, tp) => p.TrainTemplateId == tp.TrainTemplateId)
                .Where((t, x, p, tp) => tp.Id == trainPracticeRequest.TrainPracticeId)
                .Select((t, x, p, tp) => t);

            var trainRecordOptions = await queryable
                .ToListAsync();

            var trainPracticeOptionsDtos = new List<SimpleTrainPracticeOptionsDto>();

            trainPracticeOptions.ForEach(x =>
            {
                var trainPracticeOptionsDto = _mapper.Map<SimpleTrainPracticeOptionsDto>(x);

                trainPracticeOptionsDto.IsSelected = trainRecordOptions.Any(m => m.QuestionOptionId == x.QuestionOptionId);

                trainPracticeOptionsDtos.Add(trainPracticeOptionsDto);
            });

            return trainPracticeOptionsDtos;
        }

        private async Task<List<TrainPracticeKnowladgeDto>> GetTrainPracticeKnowladges(TrainPracticeRequest trainPracticeRequest)
        {
            var trainPracticeKnowladgeRepository = new ExamRepository<ExamTrainPracticeKnowladge>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var knowledgeRepository = new ExamRepository<KnowledgeBase.Knowledge>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var trainPracticeRepostitory = new ExamRepository<ExamTrainPractice>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var expression = trainPracticeRequest.GetExpression();
            var trainPracticeTable = trainPracticeRepostitory.Queryable().Where(expression);
            var trainPracticeKnowladgeTable = trainPracticeKnowladgeRepository.Queryable();
            var knowledgeTable = knowledgeRepository.Queryable();
            var queryResult = trainPracticeTable.InnerJoin(trainPracticeKnowladgeTable, (t, tk) => t.QuestionId == tk.QuestionId)
                .InnerJoin(knowledgeTable, (t, tk, k) => tk.KnowladgeId == k.Id)
                .Select((t, tk, k) => new TrainPracticeKnowladgeDto
                {
                    KnowladgeId = tk.KnowladgeId,
                    QuestionId = tk.QuestionId,
                    Title = k.Title
                });


            return await queryResult.ToListAsync();
        }

        private async Task<List<TrainPracticeSourcewareDto>> GetTrainPracticeSourcewares(TrainPracticeRequest trainPracticeRequest)
        {
            var trainPracticeSourcewareRepository = new ExamRepository<ExamTrainPracticeSourceware>(_uow, _dataPermissionFilterBuilder, _serviceProvider);
            var sourcewareRepository = new ExamRepository<ExamSourceware>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var trainPracticeRepostitory = new ExamRepository<ExamTrainPractice>(_uow, _dataPermissionFilterBuilder, _serviceProvider);

            var expression = trainPracticeRequest.GetExpression();
            var trainPracticeTable = trainPracticeRepostitory.Queryable().Where(expression);
            var trainPracticeSourcewareTable = trainPracticeSourcewareRepository.Queryable();
            var sourcewareTable = sourcewareRepository.Queryable();
            var queryResult = trainPracticeTable.InnerJoin(trainPracticeSourcewareTable, (t, ts) => t.QuestionId == ts.QuestionId)
                .InnerJoin(sourcewareTable, (t, ts, sw) => ts.SourcewareId == sw.Id)
                .Select((t, ts, sw) => new TrainPracticeSourcewareDto
                {
                    SourcewareId = ts.SourcewareId,
                    QuestionId = ts.QuestionId,
                    Name = sw.Name,
                });


            return await queryResult.ToListAsync();
        }
        #endregion


    }
}
