using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.Domain.Uow;
using Abp.Extensions;
using Abp.UI;
using Mapster;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc.Diagnostics;
using QuestionSwapDoc;
using QuestionSwapDoc.SwapWordModel;
using YGNT.File.Core.Cache;
using YGNT.Infrastructure;
using YGNT.Infrastructure.Extension;
using YGNT.QuestionLibrary.Core.Disciplines.Cache;
using YGNT.QuestionLibrary.Core.Disciplines.Domain;
using YGNT.QuestionLibrary.Core.Helper;
using YGNT.QuestionLibrary.Core.Models;
using YGNT.QuestionLibrary.Core.Questions;
using YGNT.QuestionLibrary.Core.Tasks.Enum;
using Z.EntityFramework.Plus;

namespace YGNT.QuestionLibrary.Core.Tasks.Domain
{
    public class QuestionConvertManager : DomainService, IQuestionConvertManager
    {
        private readonly IRepository<Resolve, long> _questionResolveRepository;
        private readonly IRepository<QuestionOrigin, long> _questionOriginRepository;
        private readonly IRepository<QuestionConvertTask, long> _questionConvertTaskRepository;
        private readonly IRepository<Question, long> _questionRepository;
        private readonly IRepository<QuestionReplaceTask, long> _questionReplaceTaskRepository;
        private readonly IWebHostEnvironment _webHostEnvironment;
        private readonly IDocHelper _docHelper;
        private readonly IDisciplineQuestionTypeCache _disciplineQuestionTypeCache;
        private readonly IFileCache _fileCache;
        private readonly IQuestionResolveManager _questionResolveManager;
        private readonly IDisciplineQuestionTypeManager _disciplineQuestionTypeManager;

        public QuestionConvertManager(IRepository<Resolve, long> questionResolveRepository, IWebHostEnvironment webHostEnvironment, IDocHelper docHelper, IDisciplineQuestionTypeCache disciplineQuestionTypeCache, IRepository<QuestionOrigin, long> questionOriginRepository, IRepository<QuestionConvertTask, long> questionConvertTaskRepository, IFileCache fileCache, IRepository<Question, long> questionRepository, IQuestionResolveManager questionResolveManager, IRepository<QuestionReplaceTask, long> questionReplaceTaskRepository, IDisciplineQuestionTypeManager disciplineQuestionTypeManager)
        {
            _questionResolveRepository = questionResolveRepository;
            _webHostEnvironment = webHostEnvironment;
            _docHelper = docHelper;
            _disciplineQuestionTypeCache = disciplineQuestionTypeCache;
            _questionOriginRepository = questionOriginRepository;
            _questionConvertTaskRepository = questionConvertTaskRepository;
            _fileCache = fileCache;
            _questionRepository = questionRepository;
            _questionResolveManager = questionResolveManager;
            _questionReplaceTaskRepository = questionReplaceTaskRepository;
            _disciplineQuestionTypeManager = disciplineQuestionTypeManager;
        }

        /// <summary>
        /// 试题html转换为word
        /// </summary>
        /// <param name="questionConvertTask"></param>
        public void ConvertHtmlToDocByTask(QuestionConvertTask questionConvertTask)
        {
            using (var unit = UnitOfWorkManager.Begin())
            {
                var questionOrigin = _questionOriginRepository.Get(questionConvertTask.QuestionOriginId);
                try
                {
                    using (var newUnit = UnitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
                    {
                        questionConvertTask.Remark = null;
                        questionOrigin.QuestionConvertState = QuestionConvertState.转换中;
                        _questionConvertTaskRepository.Update(questionConvertTask);
                        _questionOriginRepository.Update(questionOrigin);
                        newUnit.Complete();
                    }
                    ConvertHtmlToDoc(questionOrigin);
                    questionConvertTask.TaskState = TaskState.成功;
                    questionOrigin.QuestionConvertState = QuestionConvertState.正常;
                    var isExit = _questionConvertTaskRepository.Any(x => x.Id == questionConvertTask.Id);
                    if (isExit)
                    {
                        _questionConvertTaskRepository.Update(questionConvertTask);
                        _questionOriginRepository.Update(questionOrigin);
                        unit.Complete();
                    }
                }
                catch (Exception exception)
                {
                    questionConvertTask.TaskState = TaskState.失败;
                    questionOrigin.QuestionConvertState = QuestionConvertState.转换失败;
                    var errMsg = $"解析失败:{exception.Message}";
                    if (!questionConvertTask.Remark.IsNullOrEmpty())
                    {
                        errMsg += "\n" + questionConvertTask.Remark;
                    }
                    questionConvertTask.Remark = errMsg;
                    _questionConvertTaskRepository.Update(questionConvertTask);
                    _questionOriginRepository.Update(questionOrigin);
                    unit.Complete();
                    
                    throw;
                }
            }
        }

        /// <summary>
        /// 试题html转换为word
        /// </summary>
        /// <param name="questionOrigin"></param>
        /// <returns></returns>
        public void ConvertHtmlToDoc(QuestionOrigin questionOrigin)
        {
            if (questionOrigin.Resolves == null || !questionOrigin.Resolves.Any())
                questionOrigin.Resolves = _questionResolveRepository.GetAllList(x => x.QuestionOriginId == questionOrigin.Id);
            var fullResolve = questionOrigin.Resolves.Find(x => x.ResolveType == ResolveType.完整试题);
            var questionDir = "Convert";
            if (fullResolve.XmlPath.IsNullOrEmpty() == false)
                questionDir = Path.GetDirectoryName(fullResolve.XmlPath);

            foreach (var resolve in questionOrigin.Resolves.Where(x => x.IsModified && x.ResolveType != ResolveType.完整试题).ToList())
            {
                var newFilePath = Path.ChangeExtension(Path.Combine(questionDir, Path.GetRandomFileName()), QuestionLibraryConsts.DocExtension);
                var newResolve = resolve.Adapt<Resolve>();
                newResolve.Id = default;
                if (!newResolve.Html.IsNullOrEmpty())
                {
                    SwapWord.HtmlToWord(_webHostEnvironment.SplicePath(newFilePath)
                        , newResolve.Html.Replace(QuestionLibraryConsts.ResolveImgPlaceholder, string.Empty)
                        , _webHostEnvironment.WebRootPath);
                    newResolve.XmlPath = newFilePath;
                }
                newResolve.IsModified = false;
                questionOrigin.Resolves.Remove(resolve);
                questionOrigin.Resolves.Add(newResolve);
            }

            var joinQueItem = new SwapWordJoinQueItem()
            {
                TiXinStr = questionOrigin.QuestionTypeName,
                ImgLinkLeftPath = _webHostEnvironment.WebRootPath,
                IsXuanZhe = questionOrigin.QuestionCategory == BaseData.Enum.QuestionCategory.客观题,
                IsPanDuan = questionOrigin.QuestionCategory == BaseData.Enum.QuestionCategory.判断题
            };
            foreach (var resolve in questionOrigin.Resolves)
            {
                switch (resolve.ResolveType)
                {
                    case ResolveType.题干和选项:
                        joinQueItem.TiRange = GetSwapQueContent(resolve);
                        break;
                    case ResolveType.答案:
                        joinQueItem.DaAnRange = GetSwapQueContent(resolve);
                        break;
                    case ResolveType.解析:
                        joinQueItem.JieXiRange = GetSwapQueContent(resolve);
                        break;
                }
            }
            var fullResolveNewPath = Path.ChangeExtension(Path.Combine(questionDir, Path.GetRandomFileName()),
                QuestionLibraryConsts.DocExtension);
            SwapWord.JoinQue(_webHostEnvironment.SplicePath(fullResolveNewPath), joinQueItem);
            fullResolve.Html = string.Empty;
            fullResolve.XmlPath = fullResolveNewPath;
        }

        private SwapQueContent GetSwapQueContent(Resolve resolve)
        {
            return new SwapQueContent()
            {
                HtmlText = resolve.Html.Replace(QuestionLibraryConsts.ResolveImgPlaceholder, string.Empty),
                XmlFile = _webHostEnvironment.SplicePath(resolve.XmlPath)
            };
        }

        /// <summary>
        /// 解析上传的试题文件
        /// </summary>
        /// <param name="questionReplaceTask"></param>
        public void QuestionReplace(QuestionReplaceTask questionReplaceTask)
        {
            using (var unit = UnitOfWorkManager.Begin())
            {
                QuestionOrigin questionOrigin = null;
                try
                {
                    var fileCacheItem = _fileCache.Get(questionReplaceTask.FileId);
                    var filePath = _webHostEnvironment.SplicePath(fileCacheItem.Path);
                    if (!System.IO.File.Exists(filePath))
                        throw new UserFriendlyException($"文件不存在!");
                    var question = _questionRepository.Get(questionReplaceTask.QuestionId);
                    questionOrigin = _questionOriginRepository.Get(question.QuestionOriginId);
                    using (var newUnit = UnitOfWorkManager.Begin(TransactionScopeOption.Suppress))
                    {
                        questionOrigin.QuestionConvertState = QuestionConvertState.转换中;
                        questionReplaceTask.TaskState = TaskState.正在执行;
                        questionReplaceTask.Remark = string.Empty;
                        _questionReplaceTaskRepository.Update(questionReplaceTask);
                        _questionOriginRepository.Update(questionOrigin);
                        newUnit.Complete();
                    }

                    var questionTypes =
                        _disciplineQuestionTypeManager.GetDisciplineQuestionTypes(question.DisciplineId);
                    var questions = DocHelper.ResolveDoc(_webHostEnvironment, filePath, questionTypes);
                    if (questions.QueItems.Count != 1)
                        throw new UserFriendlyException($"试题解析失败,试题数量不匹配.解析出{questions.QueItems.Count}道试题.");
                    var resolveQuestion = questions.QueItems.First();

                    if (questionOrigin.QuestionTypeName != resolveQuestion.TiXin)
                        throw new UserFriendlyException("解析题型和原题型不一致");
                    //删除原来的解析
                    _questionResolveRepository.GetAll()
                        .Where(x => x.QuestionOriginId == questionOrigin.Id)
                        .Update(x => new Resolve() { IsDeleted = true });
                    _questionResolveManager.SaveResolve(questionOrigin, resolveQuestion);
                    questionReplaceTask.TaskState = TaskState.成功;
                    questionOrigin.QuestionConvertState = QuestionConvertState.正常;
                    var isExit = _questionReplaceTaskRepository.Any(x => x.Id == questionReplaceTask.Id);
                    if (isExit)
                    {
                        _questionReplaceTaskRepository.Update(questionReplaceTask);
                        _questionOriginRepository.Update(questionOrigin);
                        unit.Complete();
                    }
                }
                catch (Exception e)
                {
                    questionReplaceTask.TaskState = TaskState.失败;
                    if (questionOrigin != null)
                        questionOrigin.QuestionConvertState = QuestionConvertState.解析替换失败;
                    var errMsg = $"解析失败:{e.GetInnerExceptionMessage()}";
                    if (!questionReplaceTask.Remark.IsNullOrEmpty())
                    {
                        errMsg += "\n" + questionReplaceTask.Remark;
                    }
                    questionReplaceTask.Remark = errMsg;
                    _questionReplaceTaskRepository.Update(questionReplaceTask);
                    _questionOriginRepository.Update(questionOrigin);
                    unit.Complete();
                }
            }
        }

    }
}