using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using ZiggyCreatures.Caching.Fusion;

namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
    [ApiExplorerSettings(GroupName = "Image")]
    public class StudyService(IRepository<SubjectVisit> _subjectVisitRepository,
        IRepository<DicomInstance> _dicomInstanceRepository,
        IRepository<DicomSeries> _dicomSeriesRepository,
        IRepository<DicomStudy> _dicomstudyRepository,
        IRepository<Dictionary> _dictionaryRepository,
        IRepository<Trial> _trialRepository,
        IRepository<VisitTask> _visitTaskRepository,
        IRepository<DicomStudy> _dicomStudyRepository,
        IRepository<Subject> _subjectRepository,
        IRepository<StudyMonitor> _studyMonitorRepository,
        IRepository<SystemAnonymization> _systemAnonymizationRepository,
        IRepository<NoneDicomStudy> _noneDicomStudyRepository,
        IDistributedLockProvider _distributedLockProvider,
        IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IStudyService
    {


        private void SpecialArchiveStudyDeal(DicomStudy study)
        {
            #region 特殊逻辑


            if (study.PatientBirthDate.Length == 8)
            {
                study.PatientBirthDate = $"{study.PatientBirthDate[0]}{study.PatientBirthDate[1]}{study.PatientBirthDate[2]}{study.PatientBirthDate[3]}-{study.PatientBirthDate[4]}{study.PatientBirthDate[5]}-{study.PatientBirthDate[6]}{study.PatientBirthDate[7]}";
            }

            var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();


            var modality = study.Modalities;

            var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;

            if (modality == "MR")
            {
                modalityForEdit = "MRI";
            }

            if (modality == "PT")
            {
                modalityForEdit = "PET";
            }
            if (modality == "PT、CT")
            {
                modalityForEdit = "PET-CT";
            }

            study.ModalityForEdit = modalityForEdit;
            #endregion
        }


        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]

        public async Task<IResponseOutput> PreArchiveDicomStudy(PreArchiveDicomStudyCommand preArchiveStudyCommand)
        {

            var studyMonitor = new StudyMonitor()
            {
                TrialId = preArchiveStudyCommand.TrialId,
                SubjectId = preArchiveStudyCommand.SubjectId,
                SubjectVisitId = preArchiveStudyCommand.SubjectVisitId,

                IsSuccess = false,
                UploadStartTime = DateTime.Now,
                IsDicom = true,
                IP = _userInfo.IP,

                IsDicomReUpload = preArchiveStudyCommand.IsDicomReUpload,
                FileCount = preArchiveStudyCommand.FileCount,

            };


            var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true);

            return ResponseOutput.Ok(addEntity.Id);

        }

        [HttpGet]
        public async Task<IResponseOutput> DicomUploadInProgress(Guid trialId, string studyInstanceUid, Guid? visitTaskId)
        {
            if (visitTaskId != null)
            {
                var cacheValue = _fusionCache.GetOrDefault<Guid>(CacheKeys.TrialTaskStudyUidUploading(trialId, visitTaskId.Value, studyInstanceUid));
                if (cacheValue != Guid.Empty && cacheValue != _userInfo.Id)
                {
                    //---当前已有人正在上传和归档该检查!
                    return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
                }
                else
                {
                    await _fusionCache.SetAsync(CacheKeys.TrialTaskStudyUidUploading(trialId, visitTaskId.Value, studyInstanceUid), _userInfo.Id, TimeSpan.FromSeconds(15));

                }
            }
            else
            {
                await _fusionCache.SetAsync(CacheKeys.TrialStudyUidUploading(trialId, studyInstanceUid), _userInfo.Id, TimeSpan.FromSeconds(15));

            }

            return ResponseOutput.Ok();

        }



        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> AddOrUpdateArchiveStudy(NewArchiveStudyCommand incommand)
        {


            var @uploadLock = _distributedLockProvider.CreateLock($"UploadDicom");

            using (await @uploadLock.AcquireAsync())
            {
                if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialStudyUidDBLock(incommand.TrialId, incommand.Study.StudyInstanceUid)) != Guid.Empty)
                {
                    //---当前已有人正在上传和归档该检查!
                    return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
                }
                else
                {
                    //在事务未完成前 防止前端重复提交
                    await _fusionCache.SetAsync(CacheKeys.TrialStudyUidDBLock(incommand.TrialId, incommand.Study.StudyInstanceUid), _userInfo.Id, TimeSpan.FromMinutes(3));
                }
            }


            var modalitys = string.Empty;

            try
            {
                var trialId = incommand.TrialId;

                var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
                studyMonitor.UploadFinishedTime = DateTime.Now;
                studyMonitor.ArchiveFinishedTime = DateTime.Now;
                studyMonitor.FailedFileCount = incommand.FailedFileCount;
                studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
                studyMonitor.RecordPath = incommand.RecordPath;
                studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);

                var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString());
                var findStudy = await _dicomstudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);

                studyMonitor.StudyId = studyId;
                studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
                studyMonitor.IsDicomReUpload = findStudy != null;


                if (incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Count() == 0)
                {
                    await _studyMonitorRepository.SaveChangesAsync();

                    return ResponseOutput.Ok();
                }

                //上传
                if (studyMonitor.IsDicomReUpload == false)
                {
                    var addStudy = _mapper.Map<DicomStudy>(incommand.Study);

                    var @lock = _distributedLockProvider.CreateLock($"StudyCode");

                    using (await @lock.AcquireAsync())
                    {
                        //查询数据库获取最大的Code 没有记录则为0
                        var dbStudyCodeIntMax = _dicomstudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max();

                        //获取缓存中的值 并发的时候，需要记录，已被占用的值 这样其他线程在此占用的最大的值上递增
                        var cacheMaxCodeInt = await _fusionCache.GetOrDefaultAsync<int>(CacheKeys.TrialStudyMaxCode(trialId));

                        int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1;

                        addStudy.Code = currentNextCodeInt;

                        addStudy.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy));

                        await _fusionCache.SetAsync<int>(CacheKeys.TrialStudyMaxCode(trialId), addStudy.Code, TimeSpan.FromMinutes(30));

                    }


                    addStudy.Id = studyId;
                    addStudy.TrialId = incommand.TrialId;
                    addStudy.SubjectId = incommand.SubjectId;
                    addStudy.SubjectVisitId = incommand.SubjectVisitId;
                    addStudy.IsFromPACS = false;




                    //特殊处理逻辑
                    addStudy.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Distinct());
                    SpecialArchiveStudyDeal(addStudy);
                    modalitys = addStudy.Modalities;

                    await _dicomstudyRepository.AddAsync(addStudy);



                    studyMonitor.StudyCode = addStudy.StudyCode;


                    foreach (var seriesItem in incommand.Study.SeriesList)
                    {
                        var series = _mapper.Map<DicomSeries>(seriesItem);

                        series.Id = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, incommand.TrialId.ToString());
                        series.StudyId = addStudy.Id;

                        series.TrialId = incommand.TrialId;
                        series.SubjectId = incommand.SubjectId;
                        series.SubjectVisitId = incommand.SubjectVisitId;

                        //前端传递的数量不准，上传的时候，把失败的也加进来了，以实际数组的数字为准
                        series.InstanceCount = seriesItem.InstanceList.Count;

                        await _dicomSeriesRepository.AddAsync(series);

                        foreach (var instanceItem in seriesItem.InstanceList)
                        {
                            var isntance = _mapper.Map<DicomInstance>(instanceItem);

                            Guid instanceId = IdentifierHelper.CreateGuid(addStudy.StudyInstanceUid, series.SeriesInstanceUid, isntance.SopInstanceUid, addStudy.TrialId.ToString());

                            isntance.Id = instanceId;
                            isntance.StudyId = addStudy.Id;
                            isntance.SeriesId = series.Id;

                            isntance.TrialId = incommand.TrialId;
                            isntance.SubjectId = incommand.SubjectId;
                            isntance.SubjectVisitId = incommand.SubjectVisitId;

                            await _dicomInstanceRepository.AddAsync(isntance);
                        }
                    }

                }
                else
                {

                    //特殊处理逻辑
                    findStudy.IsFromPACS = false;
                    findStudy.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Union(findStudy.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct());
                    SpecialArchiveStudyDeal(findStudy);
                    modalitys = findStudy.Modalities;


                    // 少了整个序列

                    //某个序列下少了instance
                    foreach (var seriesItem in incommand.Study.SeriesList)
                    {
                        var seriesId = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, trialId.ToString());

                        DicomSeries dicomSeries = await _dicomSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);

                        //判断重复
                        if (dicomSeries == null)
                        {
                            var series = _mapper.Map<DicomSeries>(seriesItem);

                            series.Id = seriesId;
                            series.StudyId = findStudy.Id;

                            series.TrialId = incommand.TrialId;
                            series.SubjectId = incommand.SubjectId;
                            series.SubjectVisitId = incommand.SubjectVisitId;


                            dicomSeries = await _dicomSeriesRepository.AddAsync(series);

                            //新的序列 那么  检查的序列数量+1
                            findStudy.SeriesCount += 1;
                        }
                        else
                        {
                            //该序列掉了instance
                            dicomSeries.InstanceCount += seriesItem.InstanceList.Count;
                        }

                        foreach (var instanceItem in seriesItem.InstanceList)
                        {
                            var insntance = _mapper.Map<DicomInstance>(instanceItem);
                            insntance.Id = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString());
                            insntance.StudyId = findStudy.Id;
                            insntance.SeriesId = dicomSeries.Id;

                            insntance.TrialId = incommand.TrialId;
                            insntance.SubjectId = incommand.SubjectId;
                            insntance.SubjectVisitId = incommand.SubjectVisitId;

                            await _dicomInstanceRepository.AddAsync(insntance);
                        }


                        //  不管是新的序列  还是 该序列 掉了Instance   重传的时候 检查的instance 数量都会增加
                        findStudy.InstanceCount += seriesItem.InstanceList.Count;

                    }


                }

                var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit");

                using (await @lock2.AcquireAsync())
                {
                    await _dicomInstanceRepository.SaveChangesAsync();
                }
            }
            catch (Exception ex)
            {

                return ResponseOutput.NotOk(ex.Message);
            }
            finally
            {
                await _fusionCache.RemoveAsync(CacheKeys.TrialStudyUidUploading(incommand.TrialId, incommand.Study.StudyInstanceUid));
                await _fusionCache.RemoveAsync(CacheKeys.TrialStudyUidDBLock(incommand.TrialId, incommand.Study.StudyInstanceUid));

            }







            return ResponseOutput.Ok(modalitys);
        }


        [HttpPost]
        public async Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery inQuery)
        {

            var svExpression = QCCommon.GetDicomStudySubjectVisitFilter(inQuery.VisitPlanArray);

            var dicomStudyQuery = _dicomStudyRepository.Where(t => t.TrialId == inQuery.TrialId)
                    .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.Subject.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                      //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
                      .WhereIf(inQuery.VisitPlanArray != null && inQuery.VisitPlanArray?.Length > 0, svExpression)
                    .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectInfo), t => t.Subject.Code.Contains(inQuery.SubjectInfo))
                    .Select(t => new UnionStudyViewModel()
                    {
                        TrialId = t.TrialId,
                        TrialSiteId = t.Subject.TrialSiteId,
                        SubjectId = t.SubjectId,
                        SubjectVisitId = t.SubjectVisitId,
                        VisitName = t.SubjectVisit.VisitName,
                        VisitNum = t.SubjectVisit.VisitNum,

                        IsDicom = true,
                        IsFromPACS = t.IsFromPACS,

                        SubjectCode = t.Subject.Code,

                        Id = t.Id,

                        Bodypart = t.BodyPartExamined,

                        Modalities = t.Modalities,

                        Count = t.SeriesCount,

                        StudyCode = t.StudyCode,

                        //DicomStudyCode = t.StudyCode,
                        //NoneDicomCode = 0,

                        StudyTime = t.StudyTime,

                        TrialSiteAliasName = t.Subject.TrialSite.TrialSiteAliasName,

                        TrialSiteCode = t.Subject.TrialSite.TrialSiteCode,

                        Uploader = t.CreateUser.UserName,

                        UploadTime = t.CreateTime

                    });


            //.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);
            var svExpression2 = QCCommon.GetNoneDicomStudySubjectVisitFilter(inQuery.VisitPlanArray);


            var nodeDicomStudyQuery = _noneDicomStudyRepository.Where(t => t.TrialId == inQuery.TrialId)
                .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.Subject.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                 //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
                 .WhereIf(inQuery.VisitPlanArray != null && inQuery.VisitPlanArray?.Length > 0, svExpression2)
                 .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectInfo), t => t.Subject.Code.Contains(inQuery.SubjectInfo))

                 .Select(t => new UnionStudyViewModel()
                 {
                     TrialId = t.TrialId,
                     TrialSiteId = t.Subject.TrialSiteId,
                     SubjectId = t.SubjectId,
                     SubjectVisitId = t.SubjectVisitId,
                     VisitName = t.SubjectVisit.VisitName,
                     VisitNum = t.SubjectVisit.VisitNum,

                     IsDicom = false,
                     IsFromPACS = false,

                     SubjectCode = t.Subject.Code,

                     Id = t.Id,

                     Bodypart = t.BodyPart,

                     Modalities = t.Modality,

                     Count = t.NoneDicomFileList.Count(),

                     StudyCode = t.StudyCode,

                     //NoneDicomCode = t.Code,
                     //DicomStudyCode = string.Empty,

                     StudyTime = t.ImageDate,

                     TrialSiteAliasName = t.Subject.TrialSite.TrialSiteAliasName,

                     TrialSiteCode = t.Subject.TrialSite.TrialSiteCode,

                     Uploader = t.CreateUser.UserName,

                     UploadTime = t.CreateTime

                 });

            //.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);


            var unionQuery = dicomStudyQuery.Union(nodeDicomStudyQuery)
                .WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
                .WhereIf(inQuery.SubjectVisitId != null, t => t.SubjectId == inQuery.SubjectVisitId)
                .WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
                 .WhereIf(inQuery.IsFromPACS != null, t => t.IsFromPACS == inQuery.IsFromPACS);

            return await unionQuery.ToPagedListAsync(inQuery);
        }


        [HttpPost]
        public async Task<PageOutput<UnionStudyMonitorModel>> GetDicomAndNoneDicomStudyMonitorList(StudyQuery inQuery)
        {
            var svExpression = QCCommon.GetStudyMonitorSubjectVisitFilter(inQuery.VisitPlanArray);
            var StudyMonitorQuery = _studyMonitorRepository.Where(t => t.TrialId == inQuery.TrialId, ignoreQueryFilters: true)
                 .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.Subject.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                  //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
                  .WhereIf(inQuery.VisitPlanArray != null && inQuery.VisitPlanArray?.Length > 0, svExpression)
                 .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectInfo), t => t.Subject.Code.Contains(inQuery.SubjectInfo))
                 .WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
                 .WhereIf(inQuery.SubjectVisitId != null, t => t.SubjectId == inQuery.SubjectVisitId)
                 .WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
                 .WhereIf(inQuery.IsDicom != null, t => t.IsDicom == inQuery.IsDicom)
                 .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Uploader), t => t.CreateUser.UserName.Contains(inQuery.Uploader))
                 .WhereIf(inQuery.IsSuccess != null, t => t.IsSuccess == inQuery.IsSuccess)
                 .WhereIf(!string.IsNullOrWhiteSpace(inQuery.StudyCode), t => t.StudyCode.Contains(inQuery.StudyCode))
                 .WhereIf(inQuery.UploadStartTime != null, t => t.UploadStartTime >= inQuery.UploadStartTime)
                 .WhereIf(inQuery.UploadFinishedTime != null, t => t.UploadFinishedTime <= inQuery.UploadFinishedTime)
                 .Select(t => new UnionStudyMonitorModel()
                 {
                     TrialId = t.TrialId,
                     TrialSiteId = t.Subject.TrialSiteId,
                     SubjectId = t.SubjectId,
                     SubjectVisitId = t.SubjectVisitId,
                     VisitName = t.SubjectVisit.VisitName,
                     VisitNum = t.SubjectVisit.VisitNum,



                     SubjectCode = t.Subject.Code,


                     TrialSiteAliasName = t.Subject.TrialSite.TrialSiteAliasName,

                     TrialSiteCode = t.Subject.TrialSite.TrialSiteCode,

                     Uploader = t.CreateUser.UserName,

                     UploadTime = t.CreateTime,

                     IsSuccess = t.IsSuccess,
                     Note = t.Note,
                     IP = t.IP,
                     FileCount = t.FileCount,
                     FileSize = t.FileSize,
                     UploadFinishedTime = t.UploadFinishedTime,
                     UploadStartTime = t.UploadStartTime,
                     ArchiveFinishedTime = t.ArchiveFinishedTime,


                     RecordPath = t.RecordPath,

                     IsDicomReUpload = t.IsDicomReUpload,
                     StudyId = t.Id,
                     IsDicom = t.IsDicom,

                     StudyCode = t.StudyCode


                 });

            return await StudyMonitorQuery.ToPagedListAsync(inQuery);







        }


        /// <summary> 指定资源Id，渲染Dicom检查的Jpeg预览图像  </summary>
        /// <param name="studyId"> Dicom检查的Id </param>
        [HttpGet("{studyId:guid}")]
        public async Task<FileContentResult> Preview(Guid studyId)
        {
            string path = String.Empty;

            path = (await _dicomInstanceRepository.Where(s => s.StudyId == studyId).Select(t => t.Path).FirstOrDefaultAsync()).IfNullThrowException();



            using (var sw = ImageHelper.RenderPreviewJpeg(path))
            {
                var bytes = new byte[sw.Length];
                sw.Read(bytes, 0, bytes.Length);
                sw.Close();
                return new FileContentResult(bytes, "image/jpeg");
            }
        }


        /// <summary>
        /// 获取某个检查的关联检查列表（该受试者在这个想项目下的所有检查）
        /// 点击检查检查列表中的一个检查获取对应的序列列表（调用之前的接口：/series/list/，根据StudyId，获取访视的序列列表）
        /// </summary>
        /// <returns></returns>
        [HttpGet("{subjectVisitId:guid}")]
        [AllowAnonymous]
        public IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId)
        {
            #region 废弃
            //var studylist = _studyRepository.Where(u => u.SubjectVisitId == subjectVisitId && u.IsDeleted == false).Select(t => new { StudyId = t.Id, t.SubjectId, t.TrialId }).ToList();
            //var subjectId = studylist.FirstOrDefault().SubjectId;
            //var trialId = studylist.FirstOrDefault().TrialId;
            //var studyIds = studylist.Select(t => t.StudyId).ToList();


            //var query = from studyItem in _studyRepository.Where(u => u.SubjectId == subjectId
            //                                                                   && u.TrialId == trialId && u.IsDeleted == false &&
            //                                                                   !studyIds.Contains(u.Id)
            //                                                                    /* && u.Status != (int)StudyStatus.Abandon*/)
            //            join visitItem in _subjectVisitRepository.AsQueryable()
            //                on studyItem.SubjectVisitId equals visitItem.Id
            //            select new RelationStudyDTO
            //            {
            //                StudyId = studyItem.Id,
            //                StudyCode = studyItem.StudyCode,
            //                VisitName = visitItem.VisitName,
            //                Modalities = studyItem.Modalities,
            //                Description = studyItem.Description,
            //                SeriesCount = studyItem.SeriesCount
            //            };
            #endregion

            var studyInfo = _dicomStudyRepository.Where(u => u.SubjectVisitId == subjectVisitId).Select(t => new { t.SubjectId, t.TrialId }).FirstOrDefault().IfNullThrowException();

            var query = _dicomStudyRepository.Where(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId)
                .ProjectTo<RelationStudyDTO>(_mapper.ConfigurationProvider).ToList();

            var list = query.OrderBy(u => u.VisitName).ThenBy(s => s.StudyCode).ToList();

            return ResponseOutput.Ok(list);
        }


        /// <summary> 指定资源Id，获取Dicom检查信息 </summary>
        /// <param name="studyId"> Dicom检查的Id </param>
        [HttpGet, Route("{studyId:guid}")]
        [AllowAnonymous]
        public IResponseOutput<DicomStudyDTO> Item(Guid studyId)
        {
            return ResponseOutput.Ok(_mapper.Map<DicomStudyDTO>(_dicomStudyRepository.Where().FirstOrDefault(s => s.Id == studyId)));
        }



        [HttpPost]
        public async Task<IResponseOutput<List<VerifyStudyUploadResult>>> VerifyTaskStudyAllowUploadAsync(VerifyTaskUploadOrReupload verifyInfo)
        {

            var queryStudy = _visitTaskRepository.Where(t => t.SubjectId == verifyInfo.SubjectId && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.Id).Select(u => new
            {
                VisitTaskId = u.Id,
                SourceSubjectVisitId = u.SourceSubjectVisitId,
                OrginalStudyList = u.SourceSubjectVisit.StudyList.Select(t => new StudyBasicInfo()
                {
                    Id = t.Id,
                    StudyInstanceUid = t.StudyInstanceUid
                }).ToList(),

                UploadStudyList = u.TaskStudyList.Select(t => new
                {
                    Id = t.Id,
                    StudyInstanceUid = t.StudyInstanceUid,

                    SeriesList = t.SeriesList.Select(t => new UploadedSeries()
                    { SeriesId = t.Id, SeriesInstanceUid = t.SeriesInstanceUid, SOPInstanceUIDList = t.InstanceList.Select(c => c.SopInstanceUid).ToList() }).ToList()


                }).ToList()
            });

            var studyList = await queryStudy.ToListAsync();

            var resultList = new List<VerifyStudyUploadResult>();

            var trialId = verifyInfo.TrialId;

            var subjectId = verifyInfo.SubjectId;

            var visitList = _subjectVisitRepository.Where(t => t.SubjectId == verifyInfo.SubjectId).Select(t => new { t.VisitNum, t.EarliestScanDate, t.LatestScanDate, t.Id }).ToList();

            foreach (var waitUploadItem in verifyInfo.StudyInstanceUidList)
            {

                var studyInstanceUid = waitUploadItem.StudyInstanceUid;

                var result = new VerifyStudyUploadResult();

                if (_fusionCache.GetOrDefault<Guid>($"StudyUid_{trialId}_{studyInstanceUid}") != _userInfo.Id)
                {

                    result.AllowUpload = false;

                    result.AllowReUpload = false;
                    result.StudyInstanceUid = studyInstanceUid;
                    //---当前有人正在上传归档该检查!
                    result.ErrorMesseage = _localizer["Study_UploadArchiving"];

                    resultList.Add(result);
                    continue;
                }



                var findOriginStudy = studyList.FirstOrDefault(c => c.OrginalStudyList.Any(t => t.StudyInstanceUid == studyInstanceUid));


                if (findOriginStudy == null)
                {
                    throw new BusinessValidationFailedException("该检查不属于该受试者，请核查");
                }

                else
                {
                    if (findOriginStudy.UploadStudyList.Any(t => t.StudyInstanceUid == studyInstanceUid))
                    {
                        result.AllowReUpload = true;
                        result.AllowUpload = false;

                        result.UploadedSeriesList = findOriginStudy.UploadStudyList.Where(t => t.StudyInstanceUid == studyInstanceUid).SelectMany(t => t.SeriesList).ToList();

                    }
                    else
                    {
                        result.AllowUpload = true;

                        result.AllowReUpload = false;
                    }
                }

                result.StudyInstanceUid = studyInstanceUid;

                var @lock = _distributedLockProvider.CreateLock($"StudyUpload");

                using (@lock.Acquire())
                {
                    if (result.AllowReUpload || result.AllowUpload)
                    {
                        await _fusionCache.SetAsync($"StudyUid_{trialId}_{studyInstanceUid}", _userInfo.Id, TimeSpan.FromSeconds(30));

                    }
                    else
                    {

                        await _fusionCache.RemoveAsync(CacheKeys.TrialStudyUidUploading(trialId, studyInstanceUid));
                    }
                }
                resultList.Add(result);
            }





            var systemAnonymizationList = _systemAnonymizationRepository.Where(t => t.IsEnable).ToList();

            return ResponseOutput.Ok<List<VerifyStudyUploadResult>>(resultList, new
            {
                AnonymizeFixedList = systemAnonymizationList.Where(t => t.IsFixed).ToList(),
                AnonymizeNotFixedList = systemAnonymizationList.Where(t => t.IsFixed == false).ToList()
            });
        }



        /// <summary>
        /// 批量验证 检查是否可以上传 并告知原因
        /// </summary>
        [HttpPost]
        public IResponseOutput<List<VerifyStudyUploadResult>> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo)
        {
            var trialInfo = _trialRepository.Where().FirstOrDefault(t => t.Id == verifyInfo.TrialId).IfNullThrowException();

            var result = new List<VerifyStudyUploadResult>();

            var visitList = _subjectVisitRepository.Where(t => t.SubjectId == verifyInfo.SubjectId).Select(t => new { t.VisitNum, t.EarliestScanDate, t.LatestScanDate, t.Id }).ToList();

            var currentVisitNum = visitList.Where(t => t.Id == verifyInfo.SubjectVisitId).First().VisitNum;

            verifyInfo.StudyInstanceUidList.ForEach(waitUploadItem =>
            {

                if (trialInfo.IsVerifyVisitImageDate)
                {

                    //小于当前访视 最近的最晚拍片
                    var before = visitList.Where(u => u.VisitNum < currentVisitNum).Max(k => k.LatestScanDate);

                    if (before != null && waitUploadItem.StudyDate != null && before > waitUploadItem.StudyDate)
                    {

                        // $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能早于前序访视检查时间{before?.ToString("yyyy-MM-dd")}，请核对检查数据是否有误",
                        result.Add(new VerifyStudyUploadResult() { ErrorMesseage = _localizer["Study_VisitBeforePrevError", waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")!, before?.ToString("yyyy-MM-dd")!], StudyInstanceUid = waitUploadItem.StudyInstanceUid });
                        return;
                    }

                    //大于当前访视 最近的最早拍片日期  
                    var after = visitList.Where(u => u.VisitNum > currentVisitNum).Min(k => k.EarliestScanDate);

                    if (after != null && waitUploadItem.StudyDate != null && after < waitUploadItem.StudyDate)
                    {
                        // $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能晚于该访视之后的检查时间{after?.ToString("yyyy-MM-dd")}，请核对检查数据是否有误"
                        result.Add(new VerifyStudyUploadResult() { ErrorMesseage = _localizer["Study_VisitAfterSubseqError", waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")!, after?.ToString("yyyy-MM-dd")!], StudyInstanceUid = waitUploadItem.StudyInstanceUid });
                        return;
                    }
                }

                var temp = VerifyStudyUpload(waitUploadItem.StudyInstanceUid, verifyInfo.TrialId, verifyInfo.SubjectVisitId, verifyInfo.SubjectId);

                result.Add(temp);
            });


            // 写入dicom 固定的信息，以及组织路径的信息  以及匿名化的信息
            var otherData = GetSaveToDicomInfo(verifyInfo.SubjectVisitId);

            var anonymizeList = _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7)).Result;

            return ResponseOutput.Ok<List<VerifyStudyUploadResult>>(result, new
            {
                DicomStoreInfo = otherData,
                AnonymizeFixedList = anonymizeList.Where(t => t.IsFixed).ToList(),
                AnonymizeNotFixedList = anonymizeList.Where(t => t.IsFixed == false).ToList()
            });
        }


        private VerifyStudyUploadResult VerifyStudyUpload(string studyInstanceUid, Guid trialId, Guid currentSubjectVisitId, Guid SubjectId)
        {

            var cacheUserId = _fusionCache.TryGet<Guid>(CacheKeys.TrialStudyUidUploading(trialId, studyInstanceUid));

            var result = new VerifyStudyUploadResult();

            if (cacheUserId.GetValueOrDefault() != _userInfo.Id && cacheUserId.HasValue)
            {

                result.AllowUpload = false;

                result.AllowReUpload = false;
                result.StudyInstanceUid = studyInstanceUid;
                //---当前有人正在上传归档该检查!
                result.ErrorMesseage = _localizer["Study_UploadArchiving"];

                return result;
            }

            if (_subjectRepository.Where(t => t.Id == SubjectId).Select(t => t.Status).FirstOrDefault() == SubjectStatus.EndOfVisit)
            {
                result.AllowUpload = false;

                result.AllowReUpload = false;
                result.StudyInstanceUid = studyInstanceUid;
                //---受试者访视结束，不允许上传!
                result.ErrorMesseage = _localizer["Study_VisitEndedNotAllowed"];

                return result;
            }

            Guid expectStudyId = IdentifierHelper.CreateGuid(studyInstanceUid.Trim(), trialId.ToString());



            var verifyStudyInfo = _dicomStudyRepository.Where(t => t.TrialId == trialId && t.Id == expectStudyId).ProjectTo<VerifyStudyDto>(_mapper.ConfigurationProvider).FirstOrDefault();
            result.StudyInfo = verifyStudyInfo;


            //数据库不存在该检查  允许上传
            if (verifyStudyInfo == null)
            {
                result.AllowUpload = true;
            }
            //数据库该项目有该检查  看是否支持重传
            else
            {
                //是同一个受试者  支持重传
                if (verifyStudyInfo.SubjectId == SubjectId && verifyStudyInfo.SubjectVisitId == currentSubjectVisitId)
                {
                    result.AllowReUpload = true;

                    result.UploadedSeriesList = _dicomSeriesRepository.Where(t => t.StudyId == verifyStudyInfo.Id).Select(t => new UploadedSeries()
                    { SeriesId = t.Id, SeriesInstanceUid = t.SeriesInstanceUid, SOPInstanceUIDList = t.DicomInstanceList.Select(c => c.SopInstanceUid).ToList() }).ToList();
                }
                //不是同一个受试者
                else
                {
                    //有默认值，其实不用写，这里为了好理解
                    result.AllowUpload = false;

                    result.AllowReUpload = false;

                    //$"此处不可以上传。当前影像检查已经上传给受试者{verifyStudyInfo.SubjectCode}的{verifyStudyInfo.VisitName}"
                    result.ErrorMesseage = _localizer["Study_ImgAlreadyUploaded", verifyStudyInfo.SubjectCode, verifyStudyInfo.VisitName];
                }
            }
            result.StudyInstanceUid = studyInstanceUid;

            var @lock = _distributedLockProvider.CreateLock($"StudyUpload");

            using (@lock.Acquire())
            {
                if (result.AllowReUpload || result.AllowUpload)
                {
                    _fusionCache.Set(CacheKeys.TrialStudyUidUploading(trialId, studyInstanceUid), _userInfo.Id, TimeSpan.FromSeconds(30));
                }
                else
                {
                    _fusionCache.Remove(CacheKeys.TrialStudyUidUploading(trialId, studyInstanceUid));
                }
            }

            return result;
        }




        /// <summary>
        /// 获取保存到Dicom文件中的信息
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <returns></returns>
        public DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId)
        {
            //6表连接 subject trial trialSite sponsor subjectVisit   site 
            var info = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).ProjectTo<DicomTrialSiteSubjectInfo>(_mapper.ConfigurationProvider).FirstOrDefault().IfNullThrowException();

            return info;
        }

        public (List<string> SeriesInstanceUid, List<string> SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId)
        {
            var seriesInstanceUidList = _dicomSeriesRepository.Where(t => t.StudyId == studyId).Select(t => t.SeriesInstanceUid).ToList();

            var sopInstanceUidList = _dicomInstanceRepository.Where(t => t.StudyId == studyId).Select(t => t.SopInstanceUid).ToList();

            return (seriesInstanceUidList, sopInstanceUidList);
        }

    }
}
