using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Service.Reading.Dto;
using MassTransit;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Application.Filter;

namespace IRaCIS.Application.Services
{
    /// <summary>
    /// 阅片期配置
    /// </summary>
    [ApiExplorerSettings(GroupName = "Reading")]
    public class ReadingPeriodSetService(
        IRepository<SubjectVisit> _subjectVisitRepository,
        IRepository<ReadingPeriodSet> _readingPeriodSetRepository,
        IRepository<ReadModule> _readModuleRepository,
        IRepository<VisitStage> _visitStageRepository,
        IRepository<Trial> _trialRepository,
        IRepository<VisitTask> _visitTaskRepository,
        IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
        IVisitTaskHelpeService _visitTaskHelpeService,
        IRepository<ReadingPeriodPlan> _readingPeriodPlanRepository,
        IRepository<Site> _siteSetRepository,
        IRepository<Subject> _subjectRepository) : BaseService
    {

       



        #region 阅片期配置 基本信息维护  以及生效

        /// <summary>
        /// 新增或者修改  (增加标准搜索,已修改)
        /// </summary>
        /// <param name="addOrEditReadingPeriodSet"></param>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> AddOrUpdateReadingPeriodSet(ReadingPeriodSetAddOrEdit addOrEditReadingPeriodSet)
        {
            if (await _readingPeriodSetRepository.AnyAsync(x => x.Id != addOrEditReadingPeriodSet.Id && x.IsTakeEffect != ReadingPeriodStatus.Revocation
            && x.TrialId == addOrEditReadingPeriodSet.TrialId && x.ReadingPeriodName == addOrEditReadingPeriodSet.ReadingPeriodName && x.TrialReadingCriterionId == addOrEditReadingPeriodSet.TrialReadingCriterionId))
            {
                //---阅片期名称重复,操作失败
                return ResponseOutput.NotOk(_localizer["ReadingPeriodSet_NameDup"]);
            }
            if (addOrEditReadingPeriodSet.ReadingPeriodName == "Global")
            {
                //---阅片期名称不能为Global
                return ResponseOutput.NotOk(_localizer["ReadingPeriodSet_Global"]);
            }
            if (addOrEditReadingPeriodSet.Id == null)
            {
                var entity = _mapper.Map<ReadingPeriodSet>(addOrEditReadingPeriodSet);
                entity.ReadingPeriodSites = addOrEditReadingPeriodSet.SiteIds.Select(x => new ReadingPeriodSite()
                {
                    ReadingPeriodSetId = entity.Id,
                    TrialId = entity.TrialId,
                    TrialSiteId = x,
                }).ToList();

                entity.ReadingPeriodPlanList = addOrEditReadingPeriodSet.SubjectVisitIds.Select(x => new ReadingPeriodPlan
                {
                    ReadingPeriodSetId = entity.Id,
                    SubjectVisitId = x,
                }).ToList();
                await _readingPeriodSetRepository.AddAsync(entity, true);
                return ResponseOutput.Ok(entity.Id);
            }
            else
            {
                var entity = (await _readingPeriodSetRepository.Where(t => t.Id == addOrEditReadingPeriodSet.Id, true).Include(t => t.ReadingPeriodSites).Include(x => x.ReadingPeriodPlanList).FirstOrDefaultAsync()).IfNullThrowException();
                _mapper.Map(addOrEditReadingPeriodSet, entity);

                entity.ReadingPeriodSites = addOrEditReadingPeriodSet.SiteIds.Select(x => new ReadingPeriodSite()
                {
                    ReadingPeriodSetId = entity.Id,
                    TrialId = entity.TrialId,
                    TrialSiteId = x,
                }).ToList();

                entity.ReadingPeriodPlanList = addOrEditReadingPeriodSet.SubjectVisitIds.Select(x => new ReadingPeriodPlan
                {
                    ReadingPeriodSetId = entity.Id,
                    SubjectVisitId = x,
                }).ToList();

                var success = await _readingPeriodSetRepository.SaveChangesAsync();
                return ResponseOutput.Ok(entity.Id);

            }
        }



        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="readingPeriodSetId"></param>
        /// <returns></returns>
        [HttpDelete("{readingPeriodSetId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> DeleteReadingPeriodSet(Guid readingPeriodSetId)
        {
            await _readingPeriodSetRepository.UpdatePartialFromQueryAsync(t => t.Id == readingPeriodSetId, x => new ReadingPeriodSet()
            {

                IsDeleted = true
            });
            await _readingPeriodPlanRepository.UpdatePartialFromQueryAsync(t => t.ReadingPeriodSetId == readingPeriodSetId, x => new ReadingPeriodPlan()
            {
                IsDeleted = true

            });
            await _readingPeriodPlanRepository.SaveChangesAsync();
            return ResponseOutput.Ok();
        }


        /// <summary>
        /// 设置阅片期配置是否生效   (增加标准搜索,已修改)
        /// </summary>
        /// <param name="indto"></param>
        /// <returns></returns>
        [HttpPut]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> SetReadingPeriodSetEffect(SetReadingPeriodSetEffect indto)
        {
            var readingPeriodSet = await _readingPeriodSetRepository.Where(x => x.Id == indto.Id).FirstNotNullAsync();

            if (indto.IsTakeEffect == ReadingPeriodStatus.TakeEffect)
            {
                var plans = _readingPeriodPlanRepository.Where(x => x.ReadingPeriodSetId == indto.Id).Include(x => x.SubjectVisit)
                    .Include(x => x.ReadingPeriodSet).Include(x => x.SubjectVisit).ToList();
                var needAddVisitIds = plans.Select(x => x.SubjectVisitId).ToList();

                var repeatVisitIds = _readModuleRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && x.ReadingSetType == readingPeriodSet.ReadingSetType && needAddVisitIds.Contains(x.SubjectVisitId)).Select(x => x.SubjectVisitId).ToList();


                plans = plans.Where(x => !repeatVisitIds.Contains(x.SubjectVisitId)).ToList();



                List<ReadModule> readModules = new List<ReadModule>();
                foreach (var item in plans)
                {
                    readModules.Add(new ReadModule()
                    {
                        Id = NewId.NextGuid(),
                        SubjectId = item.SubjectVisit.SubjectId,
                        ModuleType = item.ReadingPeriodSet.ReadingSetType == ReadingSetType.ImageReading ? ModuleTypeEnum.Global : ModuleTypeEnum.Oncology,
                        IsUrgent = item.SubjectVisit.IsUrgent,
                        ModuleName = item.ReadingPeriodSet.ReadingPeriodName,
                        SubjectVisitId = item.SubjectVisitId,
                        ReadingSetType = item.ReadingPeriodSet.ReadingSetType,
                        ReadingPeriodSetId = item.ReadingPeriodSet.Id,
                        ReadingStatus = ReadingStatusEnum.TaskAllocate,
                        TrialId = readingPeriodSet.TrialId,
                        //VisitNum = item.SubjectVisit.VisitNum,

                        //增加标准
                        TrialReadingCriterionId = readingPeriodSet.TrialReadingCriterionId
                    });
                };


                // 判断是否要添加肿瘤学或者全局阅片任务
                var subjectVisitIds = readModules.Select(x => x.SubjectVisitId).ToList();
                switch (readingPeriodSet.ReadingSetType)
                {
                    case ReadingSetType.ImageReading:
                        //增加标准
                        var taskInfoList = await _visitTaskRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && subjectVisitIds.Contains(x.SourceSubjectVisitId ?? default(Guid)) &&

                        x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId &&
                        x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned && !x.IsAnalysisCreate).ToListAsync();

                        foreach (var item in taskInfoList)
                        {

                            var readModule = readModules.Where(x => x.SubjectVisitId == item.SourceSubjectVisitId).FirstOrDefault();
                            if (readModule != null)
                            {
                                await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand()
                                {
                                    OriginalVisitId = item.Id,
                                    ReadingCategory = GenerateTaskCategory.Global,
                                    TrialId = item.TrialId,
                                    ReadingGenerataTaskList = new List<ReadingGenerataTaskDTO>() {
                                    new ReadingGenerataTaskDTO()
                                     {
                                       IsUrgent = readModule.IsUrgent??false,
                                       SubjectId = readModule.SubjectId,
                                       ReadingName = readModule.ModuleName,
                                       ReadModuleId =readModule.Id,
                                       ReadingCategory = ReadingCategory.Global,
                                     }
                                   }
                                });
                            }
                        }
                        break;

                    case ReadingSetType.TumorReading:




                        var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == readingPeriodSet.TrialReadingCriterionId).Select(x => new
                        {
                            x.ReadingType,

                        }).FirstNotNullAsync();

                        //增加标准
                        var globalModuleIds = await _readModuleRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && subjectVisitIds.Contains(x.SubjectVisitId) && x.ModuleType == ModuleTypeEnum.Global).Select(x => x.Id).ToListAsync();

                        //增加标准
                        var globalTaskInfo = await _visitTaskRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && globalModuleIds.Contains(x.SouceReadModuleId ?? default(Guid))

                        && x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned && !x.IsAnalysisCreate).GroupBy(x => new { x.SouceReadModuleId }).Select(x =>
                        new
                        {
                            SouceReadModuleId = x.Key.SouceReadModuleId,
                            Count = x.ToList().Count,
                            TaskId = x.Select(x => x.Id).FirstOrDefault(),
                            ReadModuleId = x.Select(x => x.SouceReadModuleId).FirstOrDefault(),
                            JudgeTaskId = x.Select(x => x.JudgeVisitTaskId).FirstOrDefault(),
                            JudgeTaskResultId = x.Select(x => x.JudgeVisitTask.JudgeResultTaskId).FirstOrDefault(),
                        }).ToListAsync();

                        foreach (var item in globalTaskInfo)
                        {

                            if (item.Count == (int)criterionInfo.ReadingType)
                            {
                                //没有裁判  或者有裁判,并且裁判任务做完了
                                if (item.JudgeTaskId == null || item.JudgeTaskResultId != null)
                                {
                                    var readModule = readModules.Where(x => x.Id == item.ReadModuleId).FirstOrDefault();

                                    await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand()
                                    {
                                        OriginalVisitId = item.TaskId,
                                        ReadingCategory = GenerateTaskCategory.Oncology,
                                        TrialId = readingPeriodSet.TrialId,
                                        ReadingGenerataTaskList = new List<ReadingGenerataTaskDTO>() {
                                        new ReadingGenerataTaskDTO()
                                         {
                                           IsUrgent = readModule.IsUrgent ?? false,
                                           SubjectId = readModule.SubjectId,

                                           ReadingName = readModule.ModuleName,
                                           ReadModuleId =readModule.Id,
                                           ReadingCategory = ReadingCategory.Oncology,
                                         }
                                }
                                    });
                                }

                            }



                        }

                        break;
                }

                await _readModuleRepository.AddRangeAsync(readModules);



            }
            else
            {

                List<Guid> readModuleIds = await _readModuleRepository.Where(x => x.ReadingPeriodSetId == indto.Id).Select(x => x.Id).ToListAsync();

                if (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && readModuleIds.Contains(x.SouceReadModuleId ?? default(Guid))
                && x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId
                && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.TaskState == TaskState.Effect))
                {
                    //---当前标准阅片已生成任务并且阅片完成,撤销失败。
                    throw new BusinessValidationFailedException(_localizer["ReadingPeriodSet_TaskCompletedCannotRevoke"]);
                }


                await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && readModuleIds.Contains(x.SouceReadModuleId ?? default(Guid)), x => new VisitTask()
                {
                    TaskState = TaskState.Adbandon
                });

                await _readModuleRepository.UpdatePartialFromQueryAsync(x => x.ReadingPeriodSetId == indto.Id, x => new ReadModule()
                {

                    IsDeleted = true
                });
            }

            var readQuery = await _readingPeriodSetRepository.UpdatePartialFromQueryAsync(indto.Id, x => new ReadingPeriodSet()
            {
                IsTakeEffect = indto.IsTakeEffect,
                EffectOfTime = indto.IsTakeEffect == ReadingPeriodStatus.TakeEffect ? DateTime.Now : null,
            });

            var result = await _readingPeriodSetRepository.SaveChangesAsync();
            return ResponseOutput.Result(result);
        }



        #endregion


        #region 阅片计划 相关

        /// <summary>
        /// 获取选中的计划  (增加标准不影响 因为阅片期设置关联了标准)
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<PageOutput<PreviewTheReadingListOutDto>> GetPreviewTheReadingPlanList(PreviewTheReadingListDto inDto)
        {
            var plans = _readingPeriodPlanRepository.Where(x => x.ReadingPeriodSetId == inDto.ReadingPeriodSetId).Include(x => x.SubjectVisit).Include(x => x.SubjectVisit.TrialSite).Include(x => x.SubjectVisit.Subject)
                 .Include(x => x.ReadingPeriodSet).Select(x => new PreviewTheReadingListOutDto
                 {
                     Id = x.Id,
                     ExpirationDate = x.ReadingPeriodSet.ExpirationDate,
                     SubjectVisitId = x.SubjectVisitId,
                     TrialSiteCode = x.SubjectVisit.TrialSite.TrialSiteCode,
                     LatestScanDate = x.SubjectVisit.LatestScanDate,
                     ReadingPeriodName = x.ReadingPeriodSet.ReadingPeriodName,
                     ReadingPeriodSetId = x.ReadingPeriodSetId,
                     SubjectCode = x.SubjectVisit.Subject.Code,
                     SubjectId = x.SubjectVisit.SubjectId,
                     SubjectVisitName = x.SubjectVisit.VisitName,
                     EffectOfTime = x.ReadingPeriodSet.EffectOfTime,
                 });

            return await plans.ToPagedListAsync(inDto, nameof(PreviewTheReadingListOutDto.SubjectId));
        }


        /// <summary>
        /// 添加对应的阅片计划 (后续生效将计划变为模块)   (增加标准不影响 因为阅片期设置关联了标准)
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> GenerateReadingTask(ReadingToGenerateInDto inDto)
        {
            List<ReadingPeriodPlan> plans = new List<ReadingPeriodPlan>();
            inDto.SubjectVisitIds.ForEach(x =>
            {
                plans.Add(new ReadingPeriodPlan()
                {
                    SubjectVisitId = x,
                    ReadingPeriodSetId = inDto.ReadingPeriodSetId
                });
            });


            await _readingPeriodPlanRepository.UpdatePartialFromQueryAsync(x => x.ReadingPeriodSetId == inDto.ReadingPeriodSetId, x => new ReadingPeriodPlan()
            {
                IsDeleted = true

            });

            await _readingPeriodPlanRepository.SaveChangesAsync();
            await _readingPeriodPlanRepository.AddRangeAsync(plans);
            var result = await _readingPeriodPlanRepository.SaveChangesAsync();
            return ResponseOutput.Result(result);
        }

        #endregion



        #region 阅片期相关查询

        /// <summary>
        /// 分页获取  (增加标准搜索,已修改)
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<PageOutput<ReadingPeriodSetView>> GetReadingPeriodSetList(ReadingPeriodSetQuery query)
        {
            var readQuery = _readingPeriodSetRepository.Where(t => t.TrialId == query.TrialId).Include(x => x.ReadingPeriodSites)
               .WhereIf(query.ReadingPeriodName != null, x => x.ReadingPeriodName.Contains(query.ReadingPeriodName!))
               .WhereIf(query.TrialReadingCriterionId != null, x => x.TrialReadingCriterionId == query.TrialReadingCriterionId)
               .ProjectTo<ReadingPeriodSetView>(_mapper.ConfigurationProvider);
            var pageList = await readQuery.ToPagedListAsync(query, nameof(ReadingPeriodSetView.CreateTime));

            pageList.CurrentPageData.ForEach(x =>
            {
                //---末次访视
                x.SubjectVisitName = x.IsGlobal ? _localizer["ReadingPeriodSet_LastVisit"] : x.SubjectVisitName;
            });
            return pageList;
        }



        /// <summary>
        /// 获取单条
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpPost("{id:guid}")]
        public async Task<ReadingPeriodSetView> GetReadingPeriodSet(Guid id)
        {
            return await _readingPeriodSetRepository.AsQueryable().Include(x => x.ReadingPeriodSites).Where(x => x.Id == id).ProjectTo<ReadingPeriodSetView>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
        }

        /// <summary>
        /// 获取阅片期配置的截至访视的下拉框  (增加标准搜索,已修改)
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<GetReadingVisitListOutDto>> GetReadingVisitList(GetReadingVisitListInDto inDto)
        {
            var maxVisitNum = await _readingPeriodSetRepository
                .WhereIf(inDto.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inDto.TrialReadingCriterionId)

                .Where(x => x.TrialId == inDto.TrialId && x.ReadingSetType == inDto.ReadingSetType && x.IsTakeEffect == ReadingPeriodStatus.TakeEffect)
                .MaxAsync(x => x.ExpirationVisitNum) ?? 0;
            var thisVisitNum = await _readingPeriodSetRepository.Where(x => x.Id == inDto.ReadingPeriodSetId).Select(x => x.ExpirationVisitNum).FirstOrDefaultAsync() ?? -1;

            var globalVisitNum = new List<decimal>();
            if (inDto.ReadingSetType == ReadingSetType.TumorReading)
            {
                globalVisitNum = await _readModuleRepository
                    .WhereIf(inDto.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inDto.TrialReadingCriterionId)

                    .Where(x => x.ReadingSetType == ReadingSetType.ImageReading && x.TrialId == inDto.TrialId).Select(x => x.SubjectVisit.VisitNum).Distinct().ToListAsync();
            }

            List<GetReadingVisitListOutDto> result = await _visitStageRepository.Where(x => x.TrialId == inDto.TrialId)
                .WhereIf(inDto.ReadingSetType == ReadingSetType.TumorReading, x => globalVisitNum.Contains(x.VisitNum))
                .Where(x => x.VisitNum > 0)// 不能是基线
                .Where(x => x.VisitNum == thisVisitNum || x.VisitNum >= maxVisitNum).Select(x => new GetReadingVisitListOutDto()
                {
                    VisitName = x.VisitName,
                    VisitNum = x.VisitNum,
                    VisitStageId = x.Id,
                }).ToListAsync();
            return result;
        }



        /// <summary>
        /// 获取影像阅片的预览 // 需要清除之前已经选中的  (增加标准搜索,已修改)
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<PageOutput<PreviewTheReadingListOutDto>> GetPreviewTheReadingList(PreviewTheReadingListInDto inDto)
        {
            var readModulequery = _readModuleRepository.AsQueryable();

            // 当前项目 最晚拍片日期不为null  中心筛选
            var visitQuery = _subjectVisitRepository.Where(x => x.TrialId == inDto.TrialId && x.LatestScanDate != null && !x.IsLostVisit)
                .WhereIf(inDto.ReadingScope == ReadingScopeEnum.Site, x => inDto.SiteIds.Contains(x.TrialSiteId))
                .Where(x => !x.IsBaseLine);// 排除基线

            // 已经存在的访视 需要排除
            var existsBubjectVisitsQuery = _readModuleRepository.Where(y => y.ReadingSetType == inDto.ReadingSetType && y.TrialId == inDto.TrialId && y.TrialReadingCriterionId == inDto.TrialReadingCriterionId).Select(x => x.SubjectVisitId);

            visitQuery = visitQuery.Where(x => !existsBubjectVisitsQuery.Contains(x.Id))
                .WhereIf(inDto.ExpirationDate != null, x => x.LatestScanDate < inDto.ExpirationDate.Value.AddDays(1))
                .WhereIf(inDto.ExpirationVisitNum != null, x => x.VisitNum == inDto.ExpirationVisitNum)
                .WhereIf(inDto.ReadingSetType == ReadingSetType.TumorReading, x => readModulequery.Where(y => y.SubjectVisitId == x.Id && y.ReadingSetType == ReadingSetType.ImageReading).Count() > 0);

            var subjectIdlist = await visitQuery.OrderBy(x => x.SubjectId).Select(x => x.SubjectId).Distinct().Skip((inDto.PageIndex - 1) * inDto.PageSize).Take(inDto.PageSize).ToListAsync();


            var totalCount = visitQuery.Select(x => x.SubjectId).Distinct().Count();

            var visitlist = await visitQuery.Include(x => x.Subject).Include(x => x.TrialSite).Where(x => subjectIdlist.Contains(x.SubjectId)).ToListAsync();

            var subjectVisits = visitlist.GroupBy(x => x.SubjectId).Select(x => new
            {
                SubjectId = x.Key,
                Visits = x.ToList()
            });

            List<SubjectVisit> visits = new List<SubjectVisit>();
            subjectVisits.ForEach(x =>
            {
                var visit = x.Visits.OrderByDescending(x => x.VisitNum).FirstOrDefault();
                if (visit != null)
                {
                    visits.Add(visit);
                }
            });

            PageOutput<PreviewTheReadingListOutDto> result = new PageOutput<PreviewTheReadingListOutDto>()
            {
                CurrentPageData = visits
                .Select(x => new PreviewTheReadingListOutDto
                {
                    ExpirationDate = inDto.ExpirationDate,
                    SubjectVisitId = x.Id,
                    TrialSiteCode = x.TrialSite.TrialSiteCode,
                    LatestScanDate = x.LatestScanDate,
                    ReadingPeriodName = inDto.ReadingPeriodName,
                    SubjectCode = x.Subject.Code,
                    SubjectId = x.SubjectId,
                    SubjectVisitName = x.VisitName,
                }).ToList(),
                PageSize = inDto.PageSize,
                PageIndex = inDto.PageIndex,
                TotalCount = totalCount,
            };
            return result;
        }

        #endregion









    }
}