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

namespace YGNT.QuestionLibrary.Core.Papers.Domain
{
    public class PaperManager : IPaperManager
    {
        private readonly IRepository<Paper> _paperRepository;
        private readonly IRepository<PaperQuestion, long> _paperQuestionRepository;
        private readonly IRepository<PaperDiscipline> _paperDisciplineRepository;
        private readonly IRepository<PaperDisciplineQtSortSetting> _sortSettingRepository;
        private readonly IRepository<QuestionType> _questionRepository;
        private readonly IRepository<PaperStructureSetting> _paperStructureSettingRepository;
        private readonly IRepository<PaperSetting> _paperSettingRepository;
        private readonly IRepository<DisciplineQuestionType> _disciplineQuestionTypeRepository;
        private readonly IDisciplineQuestionTypeCache _disciplineQuestionTypeCache;

        public PaperManager(IRepository<Paper> paperRepository, IRepository<PaperQuestion, long> paperQuestionRepository, IRepository<QuestionType> questionRepository, IDisciplineQuestionTypeCache disciplineQuestionTypeCache, IRepository<DisciplineQuestionType> disciplineQuestionTypeRepository, IRepository<PaperDiscipline> paperDisciplineRepository, IRepository<PaperDisciplineQtSortSetting> sortSettingRepository, IRepository<PaperStructureSetting> paperStructureSettingRepository, IRepository<PaperSetting> paperSettingRepository)
        {
            _paperRepository = paperRepository;
            _paperQuestionRepository = paperQuestionRepository;
            _questionRepository = questionRepository;
            _disciplineQuestionTypeCache = disciplineQuestionTypeCache;
            _disciplineQuestionTypeRepository = disciplineQuestionTypeRepository;
            _paperDisciplineRepository = paperDisciplineRepository;
            _sortSettingRepository = sortSettingRepository;
            _paperStructureSettingRepository = paperStructureSettingRepository;
            _paperSettingRepository = paperSettingRepository;
        }


        /// <summary>
        /// 创建试卷
        /// </summary>
        /// <param name="name"></param>
        /// <param name="examTime"></param>
        /// <param name="disciplines"></param>
        /// <param name="remark"></param>
        /// <returns></returns>
        public async Task<Paper> CreateAsync(string name,
            long examTime,
            List<int> disciplines,
            string remark = null)
        {
            var paper = new Paper()
            {
                Name = name,
                ExamTime = examTime,
                Remark = remark
            };
            var id = await _paperRepository.InsertAndGetIdAsync(paper);
            paper.PaperDisciplines = disciplines.Select(x => new PaperDiscipline()
            {
                DisciplineId = x,
                PaperId = id
            }).ToList();
            await CreateDefaultSortSettingAsync(paper);
            await CreateDefaultPaperSettingAsync(paper);
            await _paperRepository.UpdateAsync(paper);
            return paper;
        }

        /// <summary>
        /// 创建默认排序设置
        /// </summary>
        /// <param name="paper"></param>
        /// <returns></returns>
        public async Task<List<PaperDisciplineQtSortSetting>> CreateDefaultSortSettingAsync(Paper paper)
        {
            var settings = new List<PaperDisciplineQtSortSetting>();
            var paperDisciplines = paper.PaperDisciplines;
            if (paper.PaperDisciplines == null)
            {
                paperDisciplines = await _paperDisciplineRepository
                        .GetAll()
                        .Where(x => x.PaperId == paper.Id)
                        .OrderBy(x => x.Id)
                        .ToListAsync();
            }

            int sort = 0;
            var questionTypes = await _questionRepository.GetAll()
                .OrderBy(x => x.Sort)
                .ToListAsync();
            foreach (var questionType in questionTypes)
            {
                foreach (var paperDiscipline in paperDisciplines)
                {
                    var disciplineQuestionTypes = await _disciplineQuestionTypeRepository.GetAll()
                        .Where(x => x.DisciplineId == paperDiscipline.DisciplineId)
                        .Where(x => x.QuestionTypeId == questionType.Id)
                        .OrderBy(x => x.Id)
                        .ToListAsync();
                    foreach (var disciplineQuestionType in disciplineQuestionTypes)
                    {
                        sort++;
                        var setting = new PaperDisciplineQtSortSetting()
                        {
                            DisciplineId = paperDiscipline.DisciplineId,
                            DisciplineQuestionTypeId = disciplineQuestionType.Id,
                            PaperId = paper.Id,
                            Sort = sort
                        };
                        settings.Add(setting);
                        await _sortSettingRepository.InsertAndGetIdAsync(setting);
                    }
                }
            }
            return settings;
        }

        /// <summary>
        /// 创建默认试题设置
        /// </summary>
        /// <param name="paper"></param>
        /// <returns></returns>
        public async Task<List<PaperSetting>> CreateDefaultPaperSettingAsync(Paper paper)
        {
            var paperStructureSettings = await _paperStructureSettingRepository.GetAllListAsync(x => x.IsDefault);
            var paperSettings = paperStructureSettings.Select(x => new PaperSetting()
            {
                PaperId = paper.Id,
                PaperStructureSettingId = x.Id,
                PaperStructureSettingCode = x.Code,
                Param = x.Param
            }).ToList();
            foreach (var paperSetting in paperSettings)
            {
                await _paperSettingRepository.InsertAndGetIdAsync(paperSetting);
            }
            return paperSettings;
        }

        /// <summary>
        /// 添加试题
        /// </summary>
        /// <param name="paper"></param>
        /// <param name="questionId"></param>
        /// <param name="disciplineQuestionTypeId"></param>
        /// <param name="singleScore">传null使用题型设置的评分标准</param>
        /// <returns>如果试题已经存在 返回null</returns>
        public async Task<PaperQuestion> AddQuestion(Paper paper,
            long questionId,
            int disciplineQuestionTypeId,
            float singleScore)
        {
            var isUsed = await _paperQuestionRepository.GetAll()
                .Where(x => x.QuestionId == questionId)
                .Where(x => x.PaperId == paper.Id)
                .FirstOrDefaultAsync();
            if (isUsed != null) return null;
            var sortSetting = await _sortSettingRepository.FirstOrDefaultAsync(x =>
                x.DisciplineQuestionTypeId == disciplineQuestionTypeId && x.PaperId == paper.Id);
            var question = new PaperQuestion()
            {
                QuestionTypeSort = sortSetting.Sort,
                PaperId = paper.Id,
                DisciplineQuestionTypeId = disciplineQuestionTypeId,
                SingleScore = singleScore,
                QuestionId = questionId
            };
            var lastSort = await _paperQuestionRepository.GetAll()
                               .Where(x => x.PaperId == paper.Id)
                               .Where(x => x.DisciplineQuestionTypeId == disciplineQuestionTypeId)
                               .MaxAsync(x => (int?)x.Sort) ?? default;
            question.Sort = lastSort + 1;
            await _paperQuestionRepository.InsertAndGetIdAsync(question);
            paper.TotalScore += question.SingleScore;
            return question;
        }

        /// <summary>
        /// 移动试题排序位置
        /// </summary>
        /// <param name="question"></param>
        /// <param name="sortType"></param>
        /// <returns></returns>
        public async Task MoveQuestionAsync(PaperQuestion question, SortType sortType)
        {
            var queryable = _paperQuestionRepository.GetAll()
                .Where(x => x.DisciplineQuestionTypeId == question.DisciplineQuestionTypeId)
                .Where(x => x.PaperId == question.PaperId);
            PaperQuestion targetQuestion = new PaperQuestion();
            switch (sortType)
            {
                case SortType.上移:
                    targetQuestion = await queryable.Where(x => x.Sort < question.Sort)
                        .OrderByDescending(x => x.Sort)
                        .FirstOrDefaultAsync();
                    break;
                case SortType.下移:
                    targetQuestion = await queryable.Where(x => x.Sort > question.Sort)
                        .OrderBy(x => x.Sort)
                        .FirstOrDefaultAsync();
                    break;
            }
            if (targetQuestion != null)
            {
                var tempSort = targetQuestion.Sort;
                targetQuestion.Sort = question.Sort;
                question.Sort = tempSort;
            }
        }

        /// <summary>
        /// 更新试题排序
        /// </summary>
        /// <param name="sortSetting"></param>
        /// <returns></returns>
        
        public async Task UpdatePaperQuestionSortAsync(PaperDisciplineQtSortSetting sortSetting)
        {
            await _paperQuestionRepository.GetAll()
                .Where(x => x.DisciplineQuestionTypeId == sortSetting.DisciplineQuestionTypeId)
                .Where(x => x.PaperId == sortSetting.PaperId)
                .UpdateAsync(x => new PaperQuestion()
                {
                    QuestionTypeSort = sortSetting.Sort
                });
        }

        /// <summary>
        /// 排序试卷试题
        /// </summary>
        /// <param name="paper"></param>
        /// <returns></returns>
        public async Task SortPaperAsync(Paper paper)
        {
            var sortSettings = await _sortSettingRepository.GetAll()
                .Where(x => x.PaperId == paper.Id)
                .ToListAsync();
            var settingDic = sortSettings.ToDictionary(x => x.DisciplineQuestionTypeId);
            //细分题型下排序字典
            var dic = new Dictionary<int, int>();
            foreach (var paperQuestion in paper.PaperQuestions)
            {
                paperQuestion.QuestionTypeSort = settingDic[paperQuestion.DisciplineQuestionTypeId].Sort;
                if (!dic.ContainsKey(paperQuestion.DisciplineQuestionTypeId))
                    dic.Add(paperQuestion.DisciplineQuestionTypeId, 0);
                dic[paperQuestion.DisciplineQuestionTypeId] = dic[paperQuestion.DisciplineQuestionTypeId] + 1;
                paperQuestion.Sort = dic[paperQuestion.DisciplineQuestionTypeId];
            }
        }
    }
}