using DocumentFormat.OpenXml.EMMA;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Org.BouncyCastle.Asn1.Tsp;

namespace IRaCIS.Core.Application.Services
{
    [ApiExplorerSettings(GroupName = "Trial")]
    public class SubjectVisitService(IRepository<SubjectVisit> _subjectVisitRepository,
        IRepository<Trial> _trialRepository,
        IRepository<DicomStudy> _dicomStudyRepository,
        IRepository<NoneDicomStudy> _noneDicomStudyRepository,
        IRepository<VisitTask> _visitTaskRepository,
        IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
         //IRepository<ReadingCustomTag> _readingCustomTagRepository,
         IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMark,
        IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
        IRepository<Subject> _subjectRepository,
        IRepository<DicomInstance> _dicomInstanceRepository,
        IRepository<TaskStudy> _taskStudyRepository,
             IRepository<TaskSeries> _taskSeriesRepository,
               IRepository<Segmentation> _segmentationRepository,
                 IRepository<TaskInstance> _taskInstanceRepository,
        IServiceProvider _serviceProvider,
        IRepository<DicomSeries> _dicomSeriesRepository,
        IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ISubjectVisitService
    {


        [HttpPost]
        [TrialGlobalLimit("AfterStopCannNotOpt")]
        [UnitOfWork]
        //[Authorize(Policy = IRaCISPolicy.CRC)]
        public async Task<IResponseOutput<string>> AddOrUpdateSV(SubjectVisitCommand svCommand)
        {

            var verifyExp1 = new EntityVerifyExp<SubjectVisit>()
            {
                VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId,
                //---该受试者的访视计划中已经包含一个具有相同访视号的访视。
                VerifyMsg = _localizer["Visit_DuplicateVisitNo"]
            };

            var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
            {
                VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit,
                //---该受试者已经有访视设置为末次访视，不允许将当前访视设置为末次访视。
                VerifyMsg = _localizer["Visit_LastVisitNoChange"],
                IsVerify = svCommand.IsFinalVisit
            };

            var verifyExp3 = new EntityVerifyExp<SubjectVisit>()
            {
                VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.VisitName == svCommand.VisitName,
                //---该受试者的访视计划中已经包含一个具有相同访视名称的访视。
                VerifyMsg = _localizer["Visit_DuplicateVisitName"]

            };

            svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3");
            svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted;




            SubjectVisit? dbBeforeEntity = null;
            //Add
            if (svCommand.Id == null)
            {

                //设置末次评估后，不允许添加计划外访视
                if (svCommand.InPlan == false)
                {
                    if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit))
                    {
                        //---设置末次评估后，不允许添加计划外访视。
                        throw new BusinessValidationFailedException(_localizer["Visit_NoExtraVisitAfterLast"]);
                    }

                    if (await _visitTaskRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.TaskState == TaskState.Effect && t.VisitTaskNum > svCommand.VisitNum && t.SignTime != null && t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder))
                    {
                        //---该受试者后续访视已有任务完成阅片(有序阅片标准)，不允许在此添加，如果确实需要，请回退
                        throw new BusinessValidationFailedException(_localizer["Visit_FinishedTasksNoAdd"]);
                    }

                }

                dbBeforeEntity = await _subjectVisitRepository.InsertFromDTOAsync(svCommand, false, verifyExp1, verifyExp2, verifyExp3);

                //var cRCClinicalDataIds = await _clinicalDataTrialSetRepository.Where(x => x.TrialId == svCommand.TrialId && x.UploadRole == UploadRole.CRC && x.IsConfirm && x.ClinicalDataLevel == ClinicalLevel.SubjectVisit)

                //.Select(x => x.Id).ToListAsync();



                //List<ReadingClinicalData> readingClinicals = cRCClinicalDataIds.Select(x => new ReadingClinicalData()
                //{
                //    ClinicalDataTrialSetId = x,
                //    IsVisit = true,
                //    SubjectId = svCommand.SubjectId,
                //    ReadingId = dbBeforeEntity.Id,
                //    TrialId = svCommand.TrialId
                //}).ToList();

                //await _readingClinicalDataRepository.AddRangeAsync(readingClinicals);
            }

            else
            {
                dbBeforeEntity = await _subjectVisitRepository.UpdateFromDTOAsync(svCommand, false, false, verifyExp1, verifyExp2, verifyExp3);


                if (svCommand.PDState != dbBeforeEntity.PDState && dbBeforeEntity.SubmitState == SubmitStateEnum.Submitted)
                {
                    //---当前访视影像提交后，不允许修改PD确认状态。
                    throw new BusinessValidationFailedException(_localizer["Visit_NoPDStatusChangeAfterSubmission"]);
                }

                if (svCommand.PDState != dbBeforeEntity.PDState && dbBeforeEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack)
                {
                    //---当前访视影像提交后，不允许修改PD确认状态。
                    throw new BusinessValidationFailedException(_localizer["Visit_NoPDStatusChangeAfterSubmission"]);
                }

                if (svCommand.IsLostVisit)
                {
                    if (await _subjectVisitRepository.AnyAsync(t => t.Id == svCommand.Id && t.SubmitState == SubmitStateEnum.ToSubmit))
                    {
                        //---当前访视已经有影像上传，不允许设置为失访。
                        throw new BusinessValidationFailedException(_localizer["Visit_UploadedNoLost"]);
                    }
                }

                dbBeforeEntity = await _subjectVisitRepository.UpdateFromDTOAsync(svCommand, true, false, verifyExp1, verifyExp2, verifyExp3);
            }


            //更新受试者 访视基准日期 是否入组确认
            if (svCommand.SubjectFirstGiveMedicineTime != null && svCommand.IsBaseLine)
            {

                await _subjectRepository.UpdatePartialFromQueryAsync(svCommand.SubjectId, t => new Subject()
                {
                    FirstGiveMedicineTime = svCommand.SubjectFirstGiveMedicineTime
                });

            }


            await _subjectVisitRepository.SaveChangesAsync();

            return ResponseOutput.Ok(dbBeforeEntity.Id.ToString());


        }




        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{isUrgent:bool}")]
        [TrialGlobalLimit("AfterStopCannNotOpt")]
        //[Authorize(Policy = IRaCISPolicy.PM_IQC)]
        public async Task<IResponseOutput> SetSubjectVisitUrgent(Guid subjectVisitId, bool isUrgent)
        {
            await _subjectVisitRepository.UpdatePartialFromQueryAsync(subjectVisitId, u => new SubjectVisit() { IsUrgent = isUrgent }, true);

            return ResponseOutput.Ok();
        }



        [HttpDelete, Route("{trialId:guid}/{id:guid}")]
        [TrialGlobalLimit("AfterStopCannNotOpt")]
        //[Authorize(Policy = IRaCISPolicy.CRC)]
        public async Task<IResponseOutput> DeleteSV(Guid id)
        {
            if (await _dicomStudyRepository.AnyAsync(t => t.SubjectVisitId == id))
            {
                //---当前访视已经有影像上传，不允许删除。
                return ResponseOutput.NotOk(_localizer["Visit_UploadedNoDelete"]);
            }
            if (await _subjectVisitRepository.AnyAsync(t => t.Id == id && t.InPlan))
            {
                //---计划内的访视不允许删除。
                return ResponseOutput.NotOk(_localizer["Visit_PlanVisitNoDelete"]);
            }
            if (await _subjectVisitRepository.AnyAsync(t => t.OutPlanPreviousVisitId == id))
            {
                //---当前访视已经被设置为另一访视的上一访视，不允许删除。
                return ResponseOutput.NotOk(_localizer["Visit_PreviousVisitNoDelete"]);
            }

            await _subjectVisitRepository.DeleteFromQueryAsync(s => s.Id == id, true);

            return ResponseOutput.Ok();
        }



        /// <summary>
        /// 获取访视下的Dicom 检查信息   分所有的， 阅片的 不阅片   isReading : 0 查询所有 1 查询仅仅阅片的
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="sujectVisitId"></param>
        /// <param name="isReading"></param>
        /// <param name="visitTaskId"></param>
        /// <returns></returns>
        [HttpGet, Route("{trialId:guid}/{sujectVisitId:guid}/{isReading}")]
        [AllowAnonymous]
        public async Task<List<VisitStudyDTO>> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading, [FromQuery] Guid? visitTaskId)
        {

            var qcAuditState = await _subjectVisitRepository.Where(s => s.Id == sujectVisitId).Select(t => t.AuditState).FirstOrDefaultAsync();

            //质控通过以后，过滤删除的   质控之前的不过滤
            var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;


            var isImageFilter = false;
            var criterionModalitys = "";
            var criterionType = CriterionType.NoCriterion;

            var isVisitTask = false;

            bool? isImageSegmentLabel = null;
            if (visitTaskId != null && visitTaskId != Guid.Empty)
            {
                isVisitTask = true;
                var info = await _visitTaskRepository.Where(t => t.Id == visitTaskId)
                    .Select(t => new { t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys, t.TrialReadingCriterion.CriterionType }).FirstNotNullAsync();
                isImageFilter = info.IsImageFilter;
                criterionModalitys = info.CriterionModalitys;

                criterionType = info.CriterionType;

                if (criterionType == CriterionType.OCT || criterionType == CriterionType.IVUS)
                {
                    isImageSegmentLabel = true;
                }
            }



            var studyList = await _dicomStudyRepository.Where(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).IgnoreQueryFilters()
          .Where(t => isImageFilter ? ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
          .WhereIf(isReading == 1 || isQCFinished, s => s.IsDeleted == false)
          //预览靶段标注上传的影像 影像后处理  上传了新的影像 还要原始dsa
          .WhereIf(isImageSegmentLabel == true && isVisitTask && (criterionType == CriterionType.OCT || criterionType == CriterionType.IVUS), t => t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" || t.ModalityForEdit == "OCT")
          .Select(k => new VisitStudyDTO()
          {
              InstanceCount = k.InstanceCount,
              Modalities = k.Modalities,
              //SeriesCount = k.SeriesCount,
              StudyCode = k.StudyCode,
              StudyId = k.Id
          }).ToListAsync();

            var studyIds = studyList.Select(t => t.StudyId).ToList();

            var instanceList = await _dicomInstanceRepository.Where(t => studyIds.Contains(t.StudyId)).IgnoreQueryFilters()
                   .WhereIf(isReading == 1, s => s.IsReading && s.IsDeleted == false)
                   .WhereIf(isQCFinished, t => t.IsDeleted == false)
                   .Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.HtmlPath, t.IsReading, t.IsDeleted, t.FileSize, t.ImagePositionPatient, t.ImageOrientationPatient }).ToListAsync();

            foreach (var t in studyList)
            {
                t.SeriesList = await _dicomSeriesRepository.Where(s => s.StudyId == t.StudyId).IgnoreQueryFilters()
               .WhereIf(isReading == 1, s => s.IsReading && s.IsDeleted == false)
                .WhereIf(isQCFinished, t => t.IsDeleted == false)
               .OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime)
               .ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();


                t.SeriesList.ForEach(series =>
                {

                    var instances = instanceList.Where(x => x.SeriesId == series.Id);

                    // ⭐ DICOM 空间排序（带兜底）
                    var sorted = DicomSortHelper.SortSlices(
                        instances,
                        x => x.ImagePositionPatient,
                        x => x.ImageOrientationPatient,
                        x => x.InstanceNumber
                    );

                    series.InstanceInfoList = sorted.Select(k =>
                    new InstanceBasicInfo()
                    {
                        Id = k.Id,
                        NumberOfFrames = k.NumberOfFrames,
                        HtmlPath = k.HtmlPath,
                        Path = k.Path,
                        InstanceNumber = k.InstanceNumber,
                        IsReading = k.IsReading,
                        IsDeleted = k.IsDeleted,
                        FileSize = k.FileSize,
                    }).ToList();

                    series.InstanceCount = series.InstanceInfoList.Count();
                }
                );

                //设置为阅片与否 不更改数据库检查  的instance数量 和 SeriesCount  所以这里要实时统计
                //t.SeriesCount = t.SeriesList.Count;
                t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
            }

            //预览靶段标注上传的影像
            if (isImageSegmentLabel == true && isVisitTask)
            {
                //var taskStudyList = await _taskStudyRepository.Where(t => t.SubjectVisitId == sujectVisitId)
                //   .WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
                //   .ProjectTo<VisitStudyDTO>(_mapper.ConfigurationProvider).ToListAsync();

                //foreach (var study in taskStudyList)
                //{
                //    study.SeriesList = study.SeriesList.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ToList();

                //    study.InstanceCount = study.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
                //}

                //studyList.AddRange(taskStudyList);
            }



            return studyList.Where(x => x.SeriesList.Count() > 0).ToList();




        }

        /// <summary>
        /// 获取Series信息
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<DicomSeriesDTO> GetDicomSeriesInfo(GetDicomSeriesInfoInDto inDto)
        {
            DicomSeriesDTO? series = await _dicomSeriesRepository.Where(s => s.Id == inDto.SeriesId).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();

            if (series != null)
            {
                var instanceList = await _dicomInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId)
                              .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync();



                series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
                      new InstanceBasicInfo()
                      {
                          Id = k.Id,
                          NumberOfFrames = k.NumberOfFrames,
                          HtmlPath = k.HtmlPath,
                          Path = k.Path,
                          InstanceNumber = k.InstanceNumber,
                          FileSize = k.FileSize

                      }).ToList();
            }
            else
            {
                series = await _taskSeriesRepository.Where(s => s.Id == inDto.SeriesId).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).FirstNotNullAsync();

                var instanceList = await _taskInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId)
                          .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync();



                series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
                      new InstanceBasicInfo()
                      {
                          Id = k.Id,
                          NumberOfFrames = k.NumberOfFrames,
                          HtmlPath = k.HtmlPath,
                          Path = k.Path,
                          InstanceNumber = k.InstanceNumber,
                          FileSize = k.FileSize

                      }).ToList();
            }

            return series;
        }


        /// <summary>
        /// 获取PTAndCtSeries
        /// </summary>
        /// <param name="inDto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<GetPTAndCtSeriesOutDto>> GetPTAndCtSeries(GetPTAndCtSeriesInDto inDto)
        {



            var pastResultList = await _serviceProvider.GetService<IReadingImageTaskService>().GetReadingPastResultList(new GetReadingPastResultListInDto()
            {
                VisitTaskId = inDto.VisitTaskId
            });

            var visitTaskIds = pastResultList.Select(x => x.VisitTaskId).ToList();
            var visitSeriesList = await _readingTableAnswerRowInfoRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId))
                   .Where(x => x.PTSeriesId != null && x.CTSeriesId != null)
                   .Select(x => new
                   {
                       x.PTSeriesId,
                       x.CTSeriesId,
                       x.VisitTaskId,
                       x.OtherStudyId,
                       x.VisitTask.SourceSubjectVisitId,
                       x.VisitTask.SourceSubjectVisit.IsBaseLine,
                       x.VisitTask.VisitTaskNum,
                       x.VisitTask.TaskBlindName,
                       x.UpdateTime,
                   }).ToListAsync();

            List<GetPTAndCtSeriesOutDto> result = new List<GetPTAndCtSeriesOutDto>();

            List<Guid> ctseriesIds = visitSeriesList.Select(x => x.CTSeriesId.Value).ToList();

            List<Guid> ptseriesIds = visitSeriesList.Select(x => x.PTSeriesId.Value).ToList();
            foreach (var item in visitTaskIds)
            {
                var visitSeries = visitSeriesList.Where(x => x.VisitTaskId == item).OrderByDescending(x => x.UpdateTime).FirstOrDefault();
                if (visitSeries != null)
                {
                    result.Add(new GetPTAndCtSeriesOutDto()
                    {
                        PTSeriesId = visitSeries.PTSeriesId!.Value,
                        CTSeriesId = visitSeries.CTSeriesId!.Value,
                        TaskBlindName = visitSeries.TaskBlindName,
                        VisitTaskId = item,
                        SubjectVisitId = visitSeries.SourceSubjectVisitId!.Value,
                        IsBaseLineTask = visitSeries.IsBaseLine,
                    });


                }

            }


            List<DicomSeriesDTO> ctseriesLists = await _dicomSeriesRepository.Where(s => ctseriesIds.Contains(s.Id)).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
            List<DicomSeriesDTO> ptseriesLists = await _dicomSeriesRepository.Where(s => ptseriesIds.Contains(s.Id)).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();

            var seriesIds = ctseriesIds.Union(ptseriesIds).ToList();  //并集

            var instanceList = await _dicomInstanceRepository.Where(t => seriesIds.Contains(t.SeriesId))
              .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.FileSize }).ToListAsync();

            var studyIds = instanceList.Select(x => x.StudyId).Distinct().ToList();

            var studyList = await _dicomStudyRepository.Where(t => studyIds.Contains(t.Id))
            .Select(k => new StudyInfo()
            {
                InstanceCount = k.InstanceCount,
                Modalities = k.Modalities,
                SeriesCount = k.SeriesCount,
                StudyCode = k.StudyCode,
                StudyId = k.Id,
                SubjectVisitId = k.SubjectVisitId,
            }).ToListAsync();
            AddinstanceList(ctseriesLists);
            AddinstanceList(ptseriesLists);

            void AddinstanceList(List<DicomSeriesDTO> list)
            {
                list.ForEach(series =>
                {


                    series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
                          new InstanceBasicInfo()
                          {
                              Id = k.Id,
                              NumberOfFrames = k.NumberOfFrames,
                              HtmlPath = k.HtmlPath,
                              Path = k.Path,
                              InstanceNumber = k.InstanceNumber,
                              FileSize = k.FileSize
                          }).ToList();



                    //series.WindowWidth = instanceList.FirstOrDefault()!.WindowWidth;
                    //series.WindowCenter = instanceList.FirstOrDefault()!.WindowCenter;
                });
            }




            foreach (var item in result)
            {

                item.StudyId = ptseriesLists.Where(x => x.Id == item.PTSeriesId).Select(x => x.StudyId).FirstOrDefault();

                item.StudyInfoList = studyList.Where(x => x.SubjectVisitId == item.SubjectVisitId).ToList();

                foreach (var study in item.StudyInfoList)
                {
                    study.PTSeriesList = ptseriesLists.Where(x => x.SubjectVisitId == item.SubjectVisitId).ToList();
                    study.CTSeriesList = ctseriesLists.Where(x => x.SubjectVisitId == item.SubjectVisitId).ToList();
                }

            }

            return result;
        }


        /// <summary>
        /// 获取访视下的Dicom 检查信息   分所有的， 阅片的 不阅片   isReading : 0 查询所有 1 查询仅仅阅片的
        /// </summary>
        /// <param name="indto"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<VisitStudyDTO>> GetReadingVisitStudyList(GetReadingVisitStudyListIndto indto)
        {

            var studyList = new List<VisitStudyDTO>();

            var taskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).Select(t => new
            {
                t.TrialReadingCriterionId,
                t.TrialReadingCriterion.CriterionType,
                t.TrialReadingCriterion.IsImageFilter,
                t.TrialReadingCriterion.CriterionModalitys,
                t.ReadingTaskState,

                //是否有了后处理的dicom检查
                IsHaveTaskStudy = t.TaskStudyList.Any(),
                //是否有了后处理的NoneDicom检查
                IsHaveTaskNoneDicomStudyFile = t.SourceSubjectVisit.NoneDicomStudyList.SelectMany(c => c.TaskNoneDicomFileList.Where(t => t.VisitTaskId == indto.VisitTaskId)).Any(),
                //是否有了标注的dicom检查
                //IsMarkDicomStudy = t.SourceSubjectVisit.TaskStudyList.Any(),
                //是否有了标注的NoneDicom检查
                IsMarkNoneDicomStudy = t.SourceSubjectVisit.NoneDicomStudyList.SelectMany(c => c.ImageLabelNoneDicomFileList).Any()

            }).FirstNotNullAsync();



            #region dicom 检查查询

            //如果是手动生成的标准，需要过滤检查和序列数据

            var isManualGenerate = await _trialReadingCriterionRepository.AnyAsync(t => t.Id == taskInfo.TrialReadingCriterionId && t.IsAutoCreate == false);

            var dicomStudyList = await _dicomStudyRepository.Where(t => t.TrialId == indto.TrialId && t.SubjectVisitId == indto.SujectVisitId)
                .WhereIf(taskInfo.IsImageFilter == true, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
                .WhereIf(isManualGenerate, t => t.SubjectCriteriaEvaluationVisitStudyFilterList.Any(t => t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.IsConfirmed && t.IsReading))
                //影像后处理  上传了新的影像 还要原始dsa
                .WhereIf(taskInfo.IsHaveTaskStudy && taskInfo.CriterionType == CriterionType.OCT,
                t => t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA")

                 .WhereIf(taskInfo.CriterionType == CriterionType.IVUS,
                t => t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" || t.ModalityForEdit == "IVUS")

                  .WhereIf(taskInfo.IsHaveTaskStudy == false && taskInfo.CriterionType == CriterionType.OCT,
                t => t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" || t.ModalityForEdit == "OCT")


                //其他 不应该看原始影像
                .WhereIf(taskInfo.IsHaveTaskStudy && (taskInfo.CriterionType != CriterionType.OCT && taskInfo.CriterionType != CriterionType.IVUS), t => false)
                .Select(k => new VisitStudyDTO()
                {
                    InstanceCount = k.InstanceCount,
                    StudyName = k.StudyName,
                    Modalities = k.Modalities,
                    //SeriesCount = k.SeriesCount,
                    StudyCode = k.StudyCode,
                    StudyId = k.Id,

                    BodyPartForEdit = k.BodyPartForEdit,
                    BodyPartForEditOther = k.BodyPartForEditOther,
                    PatientSex=k.PatientSex,
                    PatientWeight=k.PatientWeight,
                    RadionuclideTotalDose=k.RadionuclideTotalDose,
                    RadionuclideHalfLife=k.RadionuclideHalfLife,
                    RadiopharmaceuticalStartTime=k.RadiopharmaceuticalStartTime,
                    AcquisitionTime= k.AcquisitionTime,



                }).ToListAsync();


            var studyIds = dicomStudyList.Select(t => t.StudyId).ToList();

            if (studyIds.Count > 0)
            {
                var instanceList = await _dicomInstanceRepository.Where(t => studyIds.Contains(t.StudyId) && t.IsReading)
                    .Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.IsReading, t.FileSize, t.ImagePositionPatient, t.ImageOrientationPatient,t.PhotometricInterpretation }).ToListAsync();

                List<DicomSeriesDTO> seriesLists = await _dicomSeriesRepository.Where(s => studyIds.Contains(s.StudyId))
                     .WhereIf(isManualGenerate == false, t => t.IsReading)
                     .WhereIf(isManualGenerate, t => t.SubjectCriteriaEvaluationVisitStudyFilterList.Any(t => t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.IsConfirmed && t.IsReading))
                    .OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();

                foreach (var t in dicomStudyList)
                {

                    t.SeriesList = seriesLists.Where(s => s.StudyId == t.StudyId).OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ToList();

                    t.SeriesList.ForEach(series =>
                    {

                        var instances = instanceList.Where(x => x.SeriesId == series.Id);

                        // ⭐ DICOM 空间排序（带兜底）
                        var sorted = DicomSortHelper.SortSlices(
                            instances,
                            x => x.ImagePositionPatient,
                            x => x.ImageOrientationPatient,
                            x => x.InstanceNumber
                        );

                        series.InstanceInfoList = sorted.Select(k =>
                       new InstanceBasicInfo()
                       {
                           Id = k.Id,
                           NumberOfFrames = k.NumberOfFrames,
                           HtmlPath = k.HtmlPath,
                           Path = k.Path,
                           InstanceNumber = k.InstanceNumber,
                           FileSize = k.FileSize,
                           PhotometricInterpretation=k.PhotometricInterpretation

                       }).ToList();

                        // 设置阅片 不阅片，数字要要重新统计
                        series.InstanceCount = series.InstanceInfoList.Count;

                        //series.WindowWidth = instanceList.FirstOrDefault()!.WindowWidth;
                        //series.WindowCenter = instanceList.FirstOrDefault()!.WindowCenter;
                    });

                    //设置为阅片与否 不更改数据库检查  的instance数量 和 SeriesCount  所以这里要实时统计
                    //t.SeriesCount = t.SeriesList.Count;
                    t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
                }

                studyList.AddRange(dicomStudyList);
            }

            //影像后处理  上传了新的影像
            if (taskInfo.IsHaveTaskStudy /*|| taskInfo.IsMarkDicomStudy*/ || taskInfo.IsMarkNoneDicomStudy)
            {

                var taskStudyList = await _taskStudyRepository.Where(t => t.TrialId == indto.TrialId)
                    .WhereIf(taskInfo.IsHaveTaskStudy, t => t.VisitTaskId == indto.VisitTaskId)
                    .WhereIf(taskInfo.IsHaveTaskStudy == false && (/*taskInfo.IsMarkDicomStudy ||*/ taskInfo.IsMarkNoneDicomStudy), t => t.SubjectVisitId == indto.SujectVisitId)
                    .WhereIf(taskInfo.IsImageFilter == true, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
                    .ProjectTo<VisitStudyDTO>(_mapper.ConfigurationProvider).ToListAsync();

                foreach (var study in taskStudyList)
                {
                    study.SeriesList = study.SeriesList.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ToList();

                    study.SeriesList.ForEach(series =>
                    {

                        // ⭐ DICOM 空间排序（带兜底）
                        var sorted = DicomSortHelper.SortSlices(
                            series.InstanceInfoList,
                            x => x.ImagePositionPatient,
                            x => x.ImageOrientationPatient,
                            x => x.InstanceNumber
                        );

                        series.InstanceInfoList = sorted;
                    });

                    study.InstanceCount = study.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
                }

                studyList.AddRange(taskStudyList);
            }

            #endregion

            #region dicom 关键序列处理       

            //已经签名的任务，加关键序列
            if (taskInfo.ReadingTaskState == ReadingTaskState.HaveSigned)
            {
                var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == indto.VisitTaskId && x.StudyId != null).OrderBy(x => x.ReadingQuestionTrial.ShowOrder).ThenBy(x => x.RowIndex).Select(x => new StudyInstanceInfo()
                {
                    ShowOrder = x.ReadingQuestionTrial.ShowOrder,
                    RowIndex = x.RowIndex,
                    SeriesId = x.SeriesId,
                    StudyId = x.StudyId,
                    InstanceId = x.InstanceId,
                    NumberOfFrames = x.NumberOfFrames,
                    CreateTime = x.CreateTime,

                }).ToListAsync();


                // 这个表的数据已经移动到 _readingTaskQuestionMark 了
                //var customoList = await _readingCustomTagRepository.Where(x => x.VisitTaskId == indto.VisitTaskId && x.StudyId != null).Select(x => new StudyInstanceInfo()
                //{
                //    ShowOrder = 0,
                //    RowIndex = 0m,
                //    SeriesId = x.SeriesId,
                //    StudyId = x.StudyId,
                //    InstanceId = x.InstanceId,
                //    NumberOfFrames = x.NumberOfFrames,
                //    CreateTime = x.CreateTime,
                //}).ToListAsync();
                //rowInfoList.AddRange(customoList);

                var questionMarkList = await _readingTaskQuestionMark.Where(x => x.VisitTaskId == indto.VisitTaskId && x.StudyId != null).Select(x => new StudyInstanceInfo()
                {
                    ShowOrder = x.ReadingQuestionTrial == null ? 0 : x.ReadingQuestionTrial.ShowOrder,
                    RowIndex = 0m,
                    SeriesId = x.SeriesId,
                    StudyId = x.StudyId,
                    InstanceId = x.InstanceId,
                    NumberOfFrames = x.NumberOfFrames,
                    CreateTime = x.CreateTime,
                }).ToListAsync();
                rowInfoList.AddRange(questionMarkList);

                var thisStudyIds = rowInfoList.OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(x => x.StudyId).Distinct().ToList();
                var thisSeriesIdIds = rowInfoList.Where(x => x.SeriesId != null).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(x => x.SeriesId).Distinct().ToList();
                if (rowInfoList.Count > 0)
                {
                    var thisVisitTaskStudy = await _dicomStudyRepository.Where(t => thisStudyIds.Contains(t.Id)).Select(k => new VisitStudyDTO()
                    {
                        InstanceCount = k.InstanceCount,

                        //SeriesCount = k.SeriesCount,

                        StudyId = k.Id,
                        IsCriticalSequence = true,

                    }).FirstOrDefaultAsync();

                    if (thisVisitTaskStudy != null)
                    {
                        thisVisitTaskStudy.StudyId = default(Guid);
                        var item = await _dicomSeriesRepository.Where(s => thisSeriesIdIds.Contains(s.Id)).OrderBy(s => s.SeriesNumber).
                            ThenBy(s => s.SeriesTime)
                            .ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();

                        if (item != null)
                        {
                            item.SeriesInstanceUid = string.Empty;

                            var markInstanceIdList = rowInfoList.Where(y => y.InstanceId != null).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(y => y.InstanceId!.Value).Distinct().ToList();

                            item.InstanceInfoList = await _dicomInstanceRepository.Where(t => markInstanceIdList.Contains(t.Id)).OrderBy(s => s.DicomSerie.SeriesNumber).ThenBy(s => s.DicomSerie.SeriesTime).ThenBy(x => x.InstanceTime).Select(k =>
                              new InstanceBasicInfo()
                              {
                                  Id = k.Id,
                                  NumberOfFrames = k.NumberOfFrames,
                                  HtmlPath = k.HtmlPath,
                                  Path = k.Path,
                                  InstanceNumber = k.InstanceNumber,
                                  StudyId = k.StudyId,
                                  SeriesId = k.SeriesId,
                                  FileSize = k.FileSize,
                                  PhotometricInterpretation=k.PhotometricInterpretation,
                              }).ToListAsync();

                            item.InstanceInfoList.ForEach(x =>
                            {
                                x.RowDate = rowInfoList.FirstOrDefault(y => y.InstanceId == x.Id)?.CreateTime ?? DateTime.Now;
                                var keyFramesList = rowInfoList.Where(y => y.InstanceId == x.Id && y.NumberOfFrames != 0 && y.NumberOfFrames != null).Select(y => y.NumberOfFrames).Distinct().ToList();

                                if (keyFramesList.Count() > 0)
                                {
                                    x.KeyFramesList = keyFramesList;
                                }

                                var item = rowInfoList.FirstOrDefault(y => y.InstanceId == x.Id);
                                if (item != null)
                                {
                                    x.ShowOrder = item.ShowOrder;
                                    x.RowIndex = item.RowIndex;
                                }

                            });

                            item.InstanceInfoList = item.InstanceInfoList.OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).ThenBy(x => x.RowDate).ToList();


                            item.InstanceCount = item.InstanceInfoList.Count;

                            item.Description = "Key Series";

                            var modalityList = await _dicomSeriesRepository.Where(s => thisSeriesIdIds.Contains(s.Id)).OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).Select(x => x.Modality).Distinct().ToListAsync(); ;
                            item.Modality = string.Join(",", modalityList);
                            thisVisitTaskStudy.SeriesList.Add(item);
                            //thisVisitTaskStudy.SeriesCount = thisVisitTaskStudy.SeriesList.Count;
                        }



                        studyList.Insert(0, thisVisitTaskStudy);

                    }



                }

                studyList.ForEach(x =>
                {
                    x.SeriesList.ForEach(y =>
                    {
                        y.IsBeMark = rowInfoList.Any(z => z.SeriesId == y.Id);
                    });

                });
            }


            #endregion


            #region 非Dicom 检查查询

            var noDicomList = await _noneDicomStudyRepository.Where(x => x.TrialId == indto.TrialId && x.SubjectVisitId == indto.SujectVisitId)
                //iVUS 存在空检查
                .WhereIf(taskInfo.CriterionType != CriterionType.IVUS && taskInfo.CriterionType != CriterionType.OCT, x => x.NoneDicomFileList.Any(t => !t.FileType.Contains(StaticData.FileType.Zip)))
                .Where(t => t.IsReading)
                .WhereIf(taskInfo.IsImageFilter, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.Modality + "|"))
                .ToListAsync();


            List<VisitStudyDTO> noDicomStudyList = noDicomList.Select(x => new VisitStudyDTO()
            {
                InstanceCount = x.FileCount,
                StudyId = x.Id,
                StudyName = x.StudyName,
                Modalities = x.Modality,
                //SeriesCount = 1,
                StudyCode = x.StudyCode,
                IsDicom = false,

                BodyPartForEdit = x.BodyPart,
                BodyPartForEditOther = x.BodyPartForEditOther

            }).ToList();

            //var isExistTaskNoneDicomFile = _noneDicomStudyFileRepository.Any(t => t.VisitTaskId == indto.VisitTaskId);

            foreach (var item in noDicomStudyList)
            {
                var nodicom = noDicomList.Where(x => x.Id == item.StudyId).First();

                var instanceCount = await _noneDicomStudyFileRepository.Where(t => t.IsReading)
                    .WhereIf(taskInfo.IsHaveTaskNoneDicomStudyFile == false && taskInfo.IsMarkNoneDicomStudy == true, x => x.ImageLabelNoneDicomStudyId == item.StudyId)
                    .WhereIf(taskInfo.IsHaveTaskNoneDicomStudyFile && taskInfo.IsMarkNoneDicomStudy, x => x.OriginNoneDicomStudyId == item.StudyId && x.VisitTaskId == indto.VisitTaskId)
                    .WhereIf(taskInfo.IsHaveTaskNoneDicomStudyFile == false && taskInfo.IsMarkNoneDicomStudy == false, x => x.NoneDicomStudyId == item.StudyId)
                    .Where(t => !t.FileType.Contains(StaticData.FileType.Zip))
                    .CountAsync();

                if (instanceCount == 0)
                {
                    item.SeriesList = new List<DicomSeriesDTO>();
                    //item.SeriesCount = 0;
                }
                else
                {
                    item.SeriesList = new List<DicomSeriesDTO>()
                    {
                        new DicomSeriesDTO (){
                        IsDicom=false,
                        Id=item.StudyId,
                        InstanceCount=instanceCount,
                        Modality=item.Modalities,
                        StudyId=item.StudyId,
                        TrialId=nodicom.TrialId,
                        SubjectVisitId=nodicom.SubjectVisitId,
                        SubjectId=nodicom.SubjectId,
                        SeriesNumber=1,
                        NoneDicomFileFirstFile=await _noneDicomStudyFileRepository
                        .WhereIf(taskInfo.IsHaveTaskNoneDicomStudyFile == false && taskInfo.IsMarkNoneDicomStudy == true, x => x.ImageLabelNoneDicomStudyId == item.StudyId)
                        .WhereIf(taskInfo.IsHaveTaskNoneDicomStudyFile && taskInfo.IsMarkNoneDicomStudy, x => x.OriginNoneDicomStudyId == item.StudyId && x.VisitTaskId==indto. VisitTaskId)
                        .WhereIf(taskInfo.IsHaveTaskNoneDicomStudyFile == false && taskInfo.IsMarkNoneDicomStudy == false, x => x.NoneDicomStudyId == item.StudyId)
                        .Where(x=> !x.FileType.Contains(StaticData.FileType.Zip)).Select(x=>x.Path).FirstOrDefaultAsync(),
                        }

                    };
                }

            }

            studyList.AddRange(noDicomStudyList);

            #endregion


            #region 过滤空序列得检查 过滤空instance得序列

            foreach (var study in studyList)
            {
                study.SeriesList = study.SeriesList.Where(t => t.InstanceCount > 0).ToList();
            }

            var result = studyList.Where(x => x.SeriesCount > 0).ToList();

            #endregion

            #region 处理分割

            var segmentatSeriesList =await _segmentationRepository.Where(x => x.VisitTaskId == indto.VisitTaskId && x.SEGUrl != string.Empty).Select(x => x.SeriesId).ToListAsync();
            result.ForEach(x =>
            {
                x.SeriesList.ForEach(y =>
                {
                    y.IsBeSegment = segmentatSeriesList.Any(z => z == y.Id);
                });

            });
            #endregion


            return result;


        }




        /// <summary>
        /// 设置受试者访视已执行  也就是将studyUploaded状态置为true  为了那些没有影像 人工设置准备
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
        [TrialGlobalLimit("AfterStopCannNotOpt")]
        [Obsolete]
        public async Task<IResponseOutput> SetSVExecuted(Guid subjectVisitId)
        {
            await _subjectVisitRepository.UpdatePartialFromQueryAsync(subjectVisitId, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Executed }, true);
            return ResponseOutput.Ok();
        }
    }
}
