using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Abp.Domain.Repositories;
using Abp.UI;
using Microsoft.EntityFrameworkCore;
using YGNT.QuestionLibrary.Core.BaseData;
using YGNT.QuestionLibrary.Core.Disciplines.Cache;
using YGNT.QuestionLibrary.Core.KnowledgePoints;
using YGNT.QuestionLibrary.Core.Models;
using YGNT.QuestionLibrary.Core.Papers;
using YGNT.QuestionLibrary.Core.Questions.Models;
using YGNT.QuestionLibrary.Core.Tasks.Domain;
using Z.EntityFramework.Plus;

namespace YGNT.QuestionLibrary.Core.Questions.Domain
{
    public class QuestionManager : IQuestionManager
    {
        private readonly IRepository<Question, long> _questionRepository;
        private readonly IRepository<Resolve, long> _resolveRepository;
        private readonly IRepository<QuestionOrigin, long> _questionOriginRepository;
        private readonly IRepository<PaperQuestion, long> _paperQuestionRepository;
        private readonly IDisciplineQuestionTypeCache _disciplineQuestionTypeCache;
        private readonly IRepository<KnowledgePoint, long> _knowledgePointRepository;
        private readonly ITaskManager _taskManager;

        public QuestionManager(IRepository<Question, long> questionRepository, IRepository<PaperQuestion, long> paperQuestionRepository, IDisciplineQuestionTypeCache disciplineQuestionTypeCache, IRepository<KnowledgePoint, long> knowledgePointRepository, IRepository<QuestionOrigin, long> questionOriginRepository, IRepository<Resolve, long> resolveRepository, ITaskManager taskManager)
        {
            _questionRepository = questionRepository;
            _paperQuestionRepository = paperQuestionRepository;
            _disciplineQuestionTypeCache = disciplineQuestionTypeCache;
            _knowledgePointRepository = knowledgePointRepository;
            _questionOriginRepository = questionOriginRepository;
            _resolveRepository = resolveRepository;
            _taskManager = taskManager;
        }

        /// <summary>
        /// 新建试题
        /// </summary>
        /// <param name="shortName">试题简称</param>
        /// <param name="disciplineId">学科Id</param>
        /// <param name="disciplineQuestionTypeId">学科细分题型Id</param>
        /// <param name="difficulty">难度</param>
        /// <param name="questionOriginId"></param>
        /// <param name="chapterId">章节id</param>
        /// <param name="knowledgePointList">试题包含知识点</param>
        /// <param name="ariseTime">出题年份</param>
        /// <param name="checkPoints">章节</param>
        /// <param name="isActive"></param>
        /// <returns></returns>
        public async Task<Question> CreateAsync(string shortName,
            int disciplineId,
            int disciplineQuestionTypeId,
            Difficulty difficulty,
            long questionOriginId,
            long? chapterId = null,
            List<long> knowledgePointList = null,
            DateTime? ariseTime = null,
            string checkPoints = null,
            bool isActive = false)
        {
            var questionTypeCacheItem = await _disciplineQuestionTypeCache.GetAsync(disciplineQuestionTypeId);
            if (questionTypeCacheItem == null)
                throw new UserFriendlyException($"学科细分题型id:{disciplineQuestionTypeId}不存在!");
            if (questionTypeCacheItem.DisciplineId != disciplineId)
                throw new UserFriendlyException("题型与学科不匹配!");
            var question = new Question()
            {
                ShortName = shortName,
                DisciplineId = disciplineId,
                DisciplineQuestionTypeId = disciplineQuestionTypeId,
                QuestionTypeId = questionTypeCacheItem.QuestionTypeId,
                ChapterId = chapterId,
                AriseTime = ariseTime,
                Difficulty = difficulty,
                CheckPoints = checkPoints,
                QuestionOriginId = questionOriginId,
                IsActive = isActive
            };
            await _questionRepository.InsertAndGetIdAsync(question);
            if (knowledgePointList != null)
            {
                foreach (var knowledgePointId in knowledgePointList)
                {
                    var knowledgePoint = await _knowledgePointRepository.FirstOrDefaultAsync(x => x.Id == knowledgePointId);
                    if (knowledgePoint == null)
                        throw new UserFriendlyException($"知识点Id{knowledgePointId}不存在");
                    if (knowledgePoint.DisciplineId != disciplineId)
                        throw new UserFriendlyException($"知识点Id{knowledgePointId}所属学科和试题不匹配");
                    question.QuestionKnowledgePoints.Add(new QuestionKnowledgePoint()
                    {
                        KnowledgePointId = knowledgePointId,
                        QuestionId = question.Id

                    });
                }
            }
            await _questionRepository.UpdateAsync(question);
            return question;
        }

        /// <summary>
        /// 编辑试题
        /// </summary>
        /// <param name="question">试题</param>
        /// <param name="questionHtml">试题完整内容(题干+选项)</param>
        /// <param name="stemHtml">题干html</param>
        /// <param name="answerHtml">答案html</param>
        /// <param name="analysisHtml">解析html</param>
        /// <param name="options">试题选项</param>
        /// <returns></returns>
        public async Task UpdateQuestionAsync(Question question,
            string questionHtml,
            string stemHtml,
            string answerHtml,
            string analysisHtml,
            List<UpdateOptionDto> options)
        {
            var questionOrigin = await _questionOriginRepository.GetAsync(question.QuestionOriginId);

            await UpdateQuestionOriginAsync(questionOrigin,
                questionHtml,
                stemHtml,
                answerHtml,
                analysisHtml,
                options);
        }

        /// <summary>
        /// 修改试题原始数据
        /// </summary>
        /// <param name="questionOrigin"></param>
        /// <param name="questionHtml">试题完整内容(题干+选项)</param>
        /// <param name="stemHtml">题干html</param>
        /// <param name="answerHtml">答案html</param>
        /// <param name="analysisHtml">解析html</param>
        /// <param name="options">试题选项</param>
        /// <returns></returns>
        public async Task UpdateQuestionOriginAsync(QuestionOrigin questionOrigin,
            string questionHtml,
            string stemHtml,
            string answerHtml,
            string analysisHtml,
            List<UpdateOptionDto> options)
        {
            questionOrigin.Html = questionHtml;
            await UpdateResolveAsync(questionOrigin.Id, ResolveType.题干和选项, questionHtml);

            await UpdateResolveAsync(questionOrigin.Id, ResolveType.题干, stemHtml);

            questionOrigin.Answer = answerHtml;
            await UpdateResolveAsync(questionOrigin.Id, ResolveType.答案, answerHtml);

            questionOrigin.Analysis = analysisHtml;
            await UpdateResolveAsync(questionOrigin.Id, ResolveType.解析, analysisHtml);

            var sort = 0;
            foreach (var option in options)
            {
                sort++;
                Resolve optionResolve = new Resolve()
                {
                    ResolveType = ResolveType.选项,
                    QuestionOriginId = questionOrigin.Id
                };
                if (option.Id.HasValue)
                {
                    optionResolve = await _resolveRepository.GetAsync((long)option.Id);
                }
                if (optionResolve.QuestionOriginId != questionOrigin.Id)
                    throw new UserFriendlyException("选项和试题不匹配");
                optionResolve.Sort = sort;
                optionResolve.Html = option.Html;
                optionResolve.IsAnswer = option.IsAnswer;
                optionResolve.IsModified = true;
                option.Id = await _resolveRepository.InsertOrUpdateAndGetIdAsync(optionResolve);
            }
            //删除去除的选项
            await _resolveRepository.GetAll()
                .Where(x => x.QuestionOriginId == questionOrigin.Id)
                .Where(x => x.ResolveType == ResolveType.选项)
                .Where(x => !options.Select(f => f.Id).Contains(x.Id))
                .DeleteAsync();
            questionOrigin.IsModified = true;
            await _taskManager.EnqueueQuestionConvertAsync(questionOrigin);
        }

        /// <summary>
        /// 修改试题解析结构的html
        /// </summary>
        /// <param name="questionOriginId"></param>
        /// <param name="resolveType"></param>
        /// <param name="html"></param>
        /// <returns></returns>
        private async Task UpdateResolveAsync(long questionOriginId, ResolveType resolveType, string html)
        {
            var resolve = await _resolveRepository.GetAll()
                              .Where(x => x.QuestionOriginId == questionOriginId)
                              .Where(x => x.ResolveType == resolveType)
                              .FirstOrDefaultAsync() ?? new Resolve()
                              {
                                  QuestionOriginId = questionOriginId,
                                  ResolveType = resolveType
                              };
            resolve.Html = html;
            resolve.IsModified = true;
            await _resolveRepository.InsertOrUpdateAndGetIdAsync(resolve);
        }

        /// <summary>
        /// 删除试题
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task DeleteAsync(long id)
        {
            var isUsed = await _paperQuestionRepository.GetAll()
                .AnyAsync(x => x.QuestionId == id);

            if (isUsed) throw new UserFriendlyException("试题已经使用,禁止删除!");
            await _questionRepository.DeleteAsync(id);
        }
    }
}