using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Service.WorkLoad.DTO;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Service.Reading.Dto;
using MassTransit;
using IRaCIS.Core.Application.Service.Reading;
using IRaCIS.Core.Infra.EFCore.Common;
using Panda.DynamicWebApi.Attributes;
using AutoMapper;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Infrastructure;
using Newtonsoft.Json;

namespace IRaCIS.Application.Services
{
    /// <summary>
    /// IR影像阅片
    /// </summary>
    [ApiExplorerSettings(GroupName = "Reading")]
    public class ReadingImageTaskService : BaseService, IReadingImageTaskService
    {
        private readonly IMapper mapper;
        private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
        private readonly IRepository<VisitTask> _visitTaskRepository;
        private readonly IRepository<SubjectVisit> _subjectVisitRepository;
        private readonly IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository;
        private readonly IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository;
        private readonly IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository;

        public ReadingImageTaskService(
                 IMapper mapper,
                 IRepository<NoneDicomStudy> noneDicomStudyRepository,
                  IRepository<VisitTask> visitTaskRepository,
                   IRepository<SubjectVisit> subjectVisitRepository,
                 IRepository<ReadingTaskQuestionAnswer> readingTaskQuestionAnswerRepository,
                  IRepository<ReadingQuestionCriterionTrial> readingQuestionCriterionTrialRepository,
                  IRepository<ReadingQuestionTrial> readingQuestionTrialRepository
          )
        {
            this.mapper = mapper;
            this._noneDicomStudyRepository = noneDicomStudyRepository;
            this._visitTaskRepository = visitTaskRepository;
            this._subjectVisitRepository = subjectVisitRepository;
            this._readingTaskQuestionAnswerRepository = readingTaskQuestionAnswerRepository;
            this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository;
            this._readingQuestionTrialRepository = readingQuestionTrialRepository;
        }

        /// <summary>
        /// 获取下一个阅片任务
        /// </summary>
        /// <param name="subjectId"></param>
        /// <param name="trialId"></param>
        /// <returns></returns>
        private async Task<GetReadingTaskDto> GetNextTaskId(Guid? subjectId,Guid trialId,Guid? visistTaskId)
        {
            GetReadingTaskDto? task = new GetReadingTaskDto();

            if (visistTaskId != null)
            {
                task = await _visitTaskRepository.Where(x => x.Id==visistTaskId).Select(x => new GetReadingTaskDto()
                {
                    VisistTaskId = x.Id,
                    ReadingCategory = x.ReadingCategory,
                    VisistId = x.ReadingCategory == ReadingCategory.Visit ? x.SourceSubjectVisitId.Value : x.ReadModule.SubjectVisitId,
                    VisitNum = x.ReadingCategory == ReadingCategory.Visit ? x.SubjectVisit.VisitNum : x.ReadModule.VisitNum
                }).FirstOrDefaultAsync();
              
                task.SubjectId = await _subjectVisitRepository.Where(x => x.Id == task.VisistId).Select(x => x.SubjectId).FirstOrDefaultAsync();
                return task;
            }
            if (subjectId != null)
            {
                task = await _visitTaskRepository.Where(x => x.TrialId == trialId && x.ReadingTaskState != ReadingTaskState.HaveSigned && x.SubjectId == subjectId.Value&&x.DoctorUserId == _userInfo.Id).Select(x => new GetReadingTaskDto()
                {
                     VisistTaskId=x.Id,
                    ReadingCategory = x.ReadingCategory,
                    VisistId = x.ReadingCategory == ReadingCategory.Visit ? x.SourceSubjectVisitId.Value : x.ReadModule.SubjectVisitId,
                    VisitNum = x.ReadingCategory == ReadingCategory.Visit ? x.SubjectVisit.VisitNum : x.ReadModule.VisitNum
                }).OrderBy(x => x.VisitNum).ThenBy(x => x.ReadingCategory).FirstOrDefaultAsync();
                if (task == null)
                {
                    throw new BusinessValidationFailedException("任务都已经完成");
                }
                task.SubjectId = subjectId.Value;


            }
            else
            {
                task = await _visitTaskRepository.Where(x => x.TrialId == trialId && x.ReadingTaskState != ReadingTaskState.HaveSigned).Select(x => new GetReadingTaskDto()
                {
                    VisistTaskId = x.Id,
                    ReadingCategory = x.ReadingCategory,
                    VisistId = x.ReadingCategory == ReadingCategory.Visit ? x.SourceSubjectVisitId.Value : x.ReadModule.SubjectVisitId,
                    VisitNum = x.ReadingCategory == ReadingCategory.Visit ? x.SubjectVisit.VisitNum : x.ReadModule.VisitNum
                }).FirstOrDefaultAsync();
                if (task == null)
                {
                    throw new BusinessValidationFailedException("任务都已经完成");
                }
                task.SubjectId = await _subjectVisitRepository.Where(x => x.Id == task.VisistId).Select(x => x.SubjectId).FirstOrDefaultAsync();
            }

            return task;



        

          
        }

        /// <summary>
        /// 获取阅片非Dicom文件
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<(List<NoneDicomStudyView>,object)> GetReadingImageFile(GetReadingImgInDto inDto)
        {
            var task=await GetNextTaskId(inDto.SubjectId, inDto.TrialId,inDto.VisistTaskId);
            List<Guid> visitIds = new List<Guid>();
            if (task.ReadingCategory == ReadingCategory.Visit)
            {
                visitIds.Add(task.VisistId);
            }
            else
            {
                // 阅片期取前面所有的图像
                visitIds.AddRange(await _subjectVisitRepository.Where(x => x.VisitNum <= task.VisitNum && x.SubjectId == task.SubjectId).Select(x => x.Id).ToListAsync());
            }
            List<NoneDicomStudyView> result=await _noneDicomStudyRepository.Where(t => visitIds.Contains(t.SubjectVisitId))
                .ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken }).ToListAsync();
            return (result, new  { 
            VisitTaskId= task.VisistTaskId
            });
        }

        /// <summary>
        /// 获取项目已确认的标准
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<GetTrialConfirmCriterionListOutDto>> GetTrialConfirmCriterionList(GetConfirmCriterionInDto inDto)
        {
            var result= await _readingQuestionCriterionTrialRepository.Where(x => x.TrialId == inDto.TrialId&&x.IsConfirm&&x.IsCompleteConfig)
               .Select(x => new GetTrialConfirmCriterionListOutDto()
               {
                   ReadingQuestionCriterionTrialId = x.Id,
                   ReadingQuestionCriterionTrialName = x.CriterionName
               }).ToListAsync();
            return result;
        }

        /// <summary>
        /// 获取项目标准的裁判问题
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<GetTrialCriterionJudgeQuestionListOutDto>> GetTrialCriterionJudgeQuestionList(GetTrialCriterionJudgeQuestionListInDto inDto)
        {
            var result = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == inDto.ReadingQuestionCriterionTrialId && x.IsJudgeQuestion)
                .Select(x => new GetTrialCriterionJudgeQuestionListOutDto()
                {
                    AnswerGroup = JsonConvert.DeserializeObject<List<string>>(x.AnswerGroup.IsNullOrEmpty()?"[]": x.AnswerGroup),
                    QuestionName = x.QuestionName,
                    TypeValue =x.TypeValue,
                    ReadingQuestionTrialId = x.Id

                }).ToListAsync();
            return result;
        }

        /// <summary>
        /// 设置裁判问题的答案分组
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IResponseOutput> SetTrialCriterionJudgeQuestionAnswerGroup(SetTrialCriterionJudgeQuestionAnswerGroupInDto inDto)
        {
            await _readingQuestionTrialRepository.UpdatePartialFromQueryAsync(inDto.ReadingQuestionTrialId, x => new ReadingQuestionTrial()
            {
                AnswerGroup = JsonConvert.SerializeObject(inDto.AnswerGroup)
            }) ;

            var result = await _readingQuestionTrialRepository.SaveChangesAsync();

            return ResponseOutput.Ok(result);
        }

        /// <summary>
        /// 获取项目的阅片问题
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<(List<GetTrialReadingQuestionOutDto>, object)> GetTrialReadingQuestion(GetTrialReadingQuestionInDto inDto)
        {

         var readingTaskState = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.ReadingTaskState).FirstOrDefaultAsync();
         var query=  from data in _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId==inDto.ReadingQuestionCriterionTrialId )
            join questionAnswer in _readingTaskQuestionAnswerRepository.Where(x=>x.VisitTaskId==inDto.VisitTaskId) on data.Id equals questionAnswer.ReadingQuestionTrialId into questionAnswerTemp
                     from leftquestionAnswer in questionAnswerTemp.DefaultIfEmpty()
                     select new GetTrialReadingQuestionOutDto()
                     {
                        ReadingQuestionTrialId=data.Id,
                       ReadingQuestionCriterionTrialId=data.ReadingQuestionCriterionTrialId,
                       TrialId=data.TrialId,
                       Type=data.Type,
                       ParentTriggerValue=data.ParentTriggerValue,
                       GroupName=data.GroupName,
                       QuestionName=data.QuestionName,
                       IsRequired=data.IsRequired,
                       ShowOrder=data.ShowOrder,
                       ParentId=data.ParentId,
                       TypeValue=data.TypeValue,
                       Answer= leftquestionAnswer.Answer
                     };

            var qusetionList =await query.OrderBy(x=>x.ShowOrder).ToListAsync();

        

            List<GetTrialReadingQuestionOutDto> groupList = qusetionList.Where(x => x.ParentId == null).ToList();
            groupList.ForEach(x =>
            {
                FindChildQuestion(x, qusetionList);
            });
            return (groupList, new
            {
                readingTaskState = readingTaskState
            });
        }


        /// <summary>
        /// 找子问题
        /// </summary>
        /// <param name="trialReadingQuestion"></param>
        /// <param name="questionlists"></param>

        private void FindChildQuestion(GetTrialReadingQuestionOutDto trialReadingQuestion, List<GetTrialReadingQuestionOutDto> questionlists)
        {
            trialReadingQuestion.Childrens = questionlists.Where(x => x.ParentId == trialReadingQuestion.ReadingQuestionTrialId).ToList();
            if (trialReadingQuestion.Childrens != null && trialReadingQuestion.Childrens.Count != 0)
            {
                trialReadingQuestion.Childrens.ForEach(x =>
                {
                    FindChildQuestion(x, questionlists);
                });
            }
        }

        /// <summary>
        /// 保存任务问题
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IResponseOutput> SaveVisitTaskQuestions(SubmitVisitTaskQuestionsInDto inDto)
        {
            var subjectId = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.SubjectId).FirstOrDefaultAsync();
            await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionCriterionTrialId == inDto.ReadingQuestionCriterionTrialId);
            List<ReadingTaskQuestionAnswer> readingTaskAnswerList = inDto.AnswerList.Select(x => new ReadingTaskQuestionAnswer()
            {
                Id = NewId.NextGuid(),
                SubjectId = subjectId,
                Answer = x.Answer,
                ReadingQuestionCriterionTrialId = inDto.ReadingQuestionCriterionTrialId,
                ReadingQuestionTrialId = x.ReadingQuestionTrialId,
                VisitTaskId = inDto.VisitTaskId,
                TrialId = inDto.TrialId
            }).ToList();
            await _readingTaskQuestionAnswerRepository.AddRangeAsync(readingTaskAnswerList);
            var result = await _visitTaskRepository.SaveChangesAsync();
            return ResponseOutput.Ok(result);
        }



        /// <summary>
        /// 提交问题
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [NonDynamicMethod]
        public async Task<IResponseOutput> SubmitVisitTaskQuestions(SubmitVisitTaskQuestionsInDto inDto)
        {
            await this.SaveVisitTaskQuestions(inDto);
            await _visitTaskRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask()
            {
                ReadingTaskState = ReadingTaskState.HaveSigned
            });
            var result = await _visitTaskRepository.SaveChangesAsync();
            await this.TriggerJudgeQuestion(inDto.VisitTaskId);
          
            return ResponseOutput.Ok(result);
        }

        /// <summary>
        /// 触发裁判任务
        /// </summary>
        /// <param name="VisitTaskId"></param>
        /// <returns></returns>
        private async Task TriggerJudgeQuestion(Guid VisitTaskId)
        {
            var visitTask = await _visitTaskRepository.Where(x => x.Id == VisitTaskId).FirstOrDefaultAsync();
            var visitTaskids = await _visitTaskRepository.Where(x => x.ReadingTaskState == ReadingTaskState.HaveSigned && x.SourceSubjectVisitId == visitTask.SourceSubjectVisitId && x.SouceReadModuleId == visitTask.SouceReadModuleId).Select(x => x.Id).ToListAsync();
            if (visitTaskids.Count == 2)
            {
                var query =  from questionAnswet  in _readingTaskQuestionAnswerRepository.Where(x=> visitTaskids.Contains(x.VisitTaskId))
                             join question in _readingQuestionTrialRepository.Where(x=>x.IsJudgeQuestion) on  new { ReadingQuestionTrialId= questionAnswet.ReadingQuestionTrialId } equals  new { ReadingQuestionTrialId= question.Id }
                             select new TaskAnswerDto()
                             {
                                Answer= questionAnswet.Answer,
                                AnswerGroup= question.AnswerGroup,
                                QuestionId= question.Id,
                                VisitTaskId= questionAnswet.VisitTaskId,
                             };
                var questionAnswerlist =await query.ToListAsync();
                List<GroupTaskAnswerDto> groupTasks = questionAnswerlist.GroupBy(x => new { x.QuestionId, x.AnswerGroup }).Select(x => new GroupTaskAnswerDto
                {
                    QuestionId = x.Key.QuestionId,
                    AnswerGroup = x.Key.AnswerGroup,
                    TaskAnswerList = x.ToList(),
                }).ToList();
                var verificationResults = true;
                foreach (var item in groupTasks)
                {
                    if (item.TaskAnswerList.Count() != 2|| item.AnswerGroup==string.Empty)
                    {
                        verificationResults = false;
                        break;
                    }
                    else
                    {
                        var item1= item.TaskAnswerList[0];
                        var item2= item.TaskAnswerList[1];
                        if (item1.Answer != item2.Answer)
                        {
                            var answerGroup = JsonConvert.DeserializeObject<List<string>>(item.AnswerGroup).Select(x => new AnswerGroup()
                            {
                                GroupId = NewId.NextGuid(),
                                GroupValue = x
                            }).ToList();
                            var itemAnswerGroupsitem1 = answerGroup.Where(x => x.GroupValue.Contains($"|{item1.Answer}|"));
                            var itemAnswerGroupsitem2 = answerGroup.Where(x => x.GroupValue.Contains($"|{item2.Answer}|"));
                            var unionList = itemAnswerGroupsitem1.Intersect(itemAnswerGroupsitem2).ToList();
                            if (unionList.Count < 1)
                            {
                                verificationResults = false;
                                break;
                            }
                        }
                    }
                }

                if (!verificationResults)
                {
                    await this.SaveJudgeTask(new SaveJudgeTaskDto() { 
                       VisitTaskIds= visitTaskids,
                    });
                }
            }
        }

        /// <summary>
        /// 添加裁判任务
        /// </summary>
        /// <returns></returns>
        private async Task SaveJudgeTask(SaveJudgeTaskDto inDto)
        {
            var firstTask = await _visitTaskRepository.Where(x => inDto.VisitTaskIds.Contains(x.Id)).FirstOrDefaultAsync();

            VisitTask visitTask = new VisitTask()
            {
                Id = NewId.NextGuid(),
                ArmEnum = Arm.JudgeArm,
                SouceReadModuleId = firstTask.SouceReadModuleId,
                SourceSubjectVisitId = firstTask.SourceSubjectVisitId,
                SubjectId = firstTask.SubjectId,
                ReadingTaskState = ReadingTaskState.WaitReading,
                TaskName = firstTask.TaskName + "AD",
                ReadingCategory = ReadingCategory.Judge,
                TrialId = firstTask.TrialId,
            };

            await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => inDto.VisitTaskIds.Contains(x.Id), x => new VisitTask()
            {
                JudgeVisitTaskId = visitTask.Id
            });

            await _visitTaskRepository.AddAsync(visitTask);

            await _visitTaskRepository.SaveChangesAsync();
        }

    }
}