using FellowOakDicom;
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.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit;
using MassTransit.Initializers;
using MathNet.Numerics;
using Medallion.Threading;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Data;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using ZiggyCreatures.Caching.Fusion;

namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
    public interface IDownloadAndUploadService
    {
        Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true);
    }
    [ApiExplorerSettings(GroupName = "Trial")]
    public class DownloadAndUploadService(
        IRepository<SystemAnonymization> _systemAnonymizationRepository,
        IRepository<VisitTask> _visitTaskRepository,
        IRepository<SubjectVisit> _subjectVisitRepository,
        IOSSService _oSSService,
        IRepository<Dictionary> _dictionaryRepository,
        IRepository<Trial> _trialRepository,
        IRepository<StudyMonitor> _studyMonitorRepository,
        IRepository<TaskStudy> _taskStudyRepository,
        IRepository<TaskSeries> _taskSeriesRepository,
        IRepository<TaskInstance> _taskInstanceRepository,
        IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
        IRepository<NoneDicomStudy> _noneDicomStudyReposiotry,
        IRepository<NoneDicomStudyFile> _noneDicomStudyFileReposiotry,
        IDistributedLockProvider _distributedLockProvider) : BaseService, IDownloadAndUploadService
    {


        /// <summary>
        /// 受试者随机阅片,任务进行随机编号
        /// 进入阅片任务前,随机挑选出该受试者的一个任务,然后给该任务一个编号,编号给的逻辑是:TimePoint Ran+ 已阅任务数量+1
        /// 根据当前受试者该标准已阅任务数量(生效失效的任务都算,考虑重阅,最后编号不重复)  第一个就是TimePoint Ran1,后面依次随机挑选出来的阅片序号依次递增
        /// </summary>
        /// <param name="subjectId"></param>
        /// <param name="trialReadingCriterionId"></param>
        /// <returns></returns>
        public async Task<IResponseOutput> SubejctRandomReadingTaskNameDeal(Guid subjectId, Guid trialReadingCriterionId)
        {
            //subject 随机阅片 才处理任务编号
            if (_visitTaskRepository.Any(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.SubjectRandom))
            {
                //找到 非一致性分析,未签名,状态正常的 并且任务名称是TimePoint的 任务
                var needDealTaskList = await _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.Id
                   && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskBlindName == "Timepoint" && t.ReadingCategory == ReadingCategory.Visit
                   && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze), true).ToListAsync();

                if (needDealTaskList.Count > 0)
                {
                    //已完成的访视任务数量(包含重阅的)
                    var haveFinishedTaskCount = await _visitTaskRepository.CountAsync(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.Id
                    && t.ReadingTaskState == ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit);

                    //已经处理过的任务名称的数量

                    var haveDealedTaskCount = await _visitTaskRepository.CountAsync(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.Id
                    && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit && t.TaskBlindName != "Timepoint");



                    //随机赋值编号  比如要处理5个任务,实例化一个包含1-5的数组,每次随机取出一个
                    List<int> availableNumbers = Enumerable.Range(haveDealedTaskCount + haveFinishedTaskCount + 1, needDealTaskList.Count).ToList();
                    Random rng = new Random();
                    foreach (var visitTask in needDealTaskList)
                    {
                        int randomIndex = rng.Next(availableNumbers.Count);

                        visitTask.TaskBlindName = $"Timepoint Ran {availableNumbers[randomIndex]}";

                        availableNumbers.RemoveAt(randomIndex);
                    }
                    await _visitTaskRepository.SaveChangesAsync();
                }
            }
            return ResponseOutput.Ok();
        }

        /// <summary>
        /// 获取该受试者任务上传列表(展示已上传情况)
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public async Task<IResponseOutput<List<SubjectImageUploadDTO>>> GetSubjectImageUploadList(IRUploadStudyQuery inQuery)
        {
            await SubejctRandomReadingTaskNameDeal(inQuery.SubjectId, inQuery.TrialReadingCriterionId);

            var query = _visitTaskRepository.Where(t => t.SubjectId == inQuery.SubjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisitId != null
            && t.DoctorUserId == _userInfo.Id && t.TaskState == TaskState.Effect)
                .Select(u => new SubjectImageUploadDTO()
                {
                    VisitTaskId = u.Id,

                    SubejctId = u.SubjectId,

                    TrialSiteId = u.Subject.TrialSiteId,

                    IsImageFilter = u.TrialReadingCriterion.IsImageFilter,

                    CriterionModalitys = u.TrialReadingCriterion.CriterionModalitys,

                    SubjectCode = u.IsSelfAnalysis == true ? u.BlindSubjectCode : u.Subject.Code,
                    TaskBlindName = u.TaskBlindName,
                    TaskName = u.TaskName,

                    SourceSubjectVisitId = u.SourceSubjectVisitId,
                    PackState = u.SourceSubjectVisit.PackState,

                    OrginalStudyList = u.SourceSubjectVisit.StudyList
                    .Where(t => u.TrialReadingCriterion.IsImageFilter ? ("|" + u.TrialReadingCriterion.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
                    .Select(t => new StudyBasicInfo()
                    {
                        Id = t.Id,
                        StudyInstanceUid = t.StudyInstanceUid,
                        ModalityForEdit = t.ModalityForEdit,
                        BodyPartExamined = t.BodyPartExamined,
                        BodyPartForEdit = t.BodyPartForEdit,

                        StudyCode = t.StudyCode,
                        StudyTime = t.StudyTime,
                        Description = t.Description,
                        InstanceCount = t.InstanceCount,
                        Modalities = t.Modalities,
                        SeriesCount = t.SeriesCount,
                    }).ToList(),

                    UploadStudyList = u.TaskStudyList.Select(t => new StudyBasicInfo()
                    {
                        Id = t.Id,
                        StudyInstanceUid = t.StudyInstanceUid,
                        ModalityForEdit = t.ModalityForEdit,
                        BodyPartExamined = t.BodyPartExamined,
                        BodyPartForEdit = t.BodyPartForEdit,

                        StudyCode = t.StudyCode,
                        StudyTime = t.StudyTime,
                        Description = t.Description,
                        InstanceCount = t.InstanceCount,
                        Modalities = t.Modalities,
                        SeriesCount = t.SeriesCount,

                        SopInstanceUidList = t.InstanceList.Select(t => t.SopInstanceUid).ToList(),

                    }).ToList()
                })
                ;

            var list = await query.Where(t => t.SubjectCode == inQuery.SubjectCode).ToListAsync();

            return ResponseOutput.Ok(list);
        }

        private void SpecialArchiveStudyDeal(TaskStudy 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(PriArchiveTaskStudyCommand 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,
                FileSize = preArchiveStudyCommand.FileSize,
                FileCount = preArchiveStudyCommand.FileCount,

            };


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

            return ResponseOutput.Ok(addEntity.Id);

        }

        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> AddOrUpdateArchiveTaskStudy(TaskArchiveStudyCommand incommand)
        {
            #region 获取该subject 已生成任务的访视的检查

            var queryStudy = _visitTaskRepository.Where(t => t.SubjectId == incommand.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(),
            });

            var studyList = await queryStudy.ToListAsync();


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

            if (findOriginStudy == null)
            {
                return ResponseOutput.NotOk("该检查不属于该受试者,请核查");
            }

            #endregion



            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;

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

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

                    using (await @lock.AcquireAsync())
                    {
                        //查询数据库获取最大的Code 没有记录则为0
                        var dbStudyCodeIntMax = _taskStudyRepository.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;
                        study.Code = currentNextCodeInt;

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

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

                    }


                    study.Id = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), findOriginStudy.VisitTaskId.ToString());
                    study.TrialId = incommand.TrialId;
                    study.SubjectId = incommand.SubjectId;
                    study.VisitTaskId = findOriginStudy.VisitTaskId;
                    //study.SubjectVisitId = incommand.SubjectVisitId;


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

                    await _taskStudyRepository.AddAsync(study);


                    studyMonitor.StudyId = study.Id;
                    studyMonitor.StudyCode = study.StudyCode;


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

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

                        series.TrialId = incommand.TrialId;
                        series.SubjectId = incommand.SubjectId;
                        //series.SubjectVisitId = incommand.SubjectVisitId;
                        series.VisitTaskId = findOriginStudy.VisitTaskId;

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

                        await _taskSeriesRepository.AddAsync(series);

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

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

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

                            isntance.TrialId = incommand.TrialId;
                            isntance.SubjectId = incommand.SubjectId;
                            //isntance.SubjectVisitId = incommand.SubjectVisitId;
                            isntance.VisitTaskId = findOriginStudy.VisitTaskId;

                            await _taskInstanceRepository.AddAsync(isntance);
                        }
                    }




                }
                else
                {

                    var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), findOriginStudy.VisitTaskId.ToString());

                    var study = await _taskStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);

                    //重传的时候也要赋值检查Id
                    studyMonitor.StudyId = study.Id;
                    studyMonitor.StudyCode = study.StudyCode;

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


                    // 少了整个序列

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

                        TaskSeries dicomSeries = await _taskSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);

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

                            series.Id = seriesId;
                            series.StudyId = study.Id;

                            series.TrialId = incommand.TrialId;
                            series.SubjectId = incommand.SubjectId;
                            series.VisitTaskId = findOriginStudy.VisitTaskId;
                            //series.SubjectVisitId = incommand.SubjectVisitId;


                            dicomSeries = await _taskSeriesRepository.AddAsync(series);

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

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

                            insntance.TrialId = incommand.TrialId;
                            insntance.SubjectId = incommand.SubjectId;
                            insntance.VisitTaskId = findOriginStudy.VisitTaskId;

                            await _taskInstanceRepository.AddAsync(insntance);
                        }


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

                    }


                }

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

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

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







            return ResponseOutput.Ok(modalitys);
        }


        [HttpDelete]
        public async Task<IResponseOutput> DeleteTaskStudy(Guid visitTaskId, bool isDicom, Guid? noneDicomStudyId)
        {
            if (isDicom)
            {
                await _taskStudyRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
                await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
                await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
            }
            else
            {
                await _noneDicomStudyFileReposiotry.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.NoneDicomStudyId == noneDicomStudyId);
            }

            return ResponseOutput.Ok();
        }
        /// <summary>
        /// 打包和匿名化影像 默认是匿名化打包,也可以不匿名化打包
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="isDicom"></param>
        /// <param name="isAnonymize"></param>
        /// <returns></returns>

        public async Task<IResponseOutput> RequestPackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true)
        {


            var extralConfig = _trialRepository.Where(t => t.Id == trialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty;

            var config = JsonConvert.DeserializeObject<TrialExtraConfig>(extralConfig) ?? new TrialExtraConfig();

            if (config.IsSupportQCDownloadImage == false)
            {
                throw new BusinessValidationFailedException("该项目不支持QC下载影像");
            }

            var subjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);

            var sujectCode = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => t.Subject.Code).FirstOrDefaultAsync();

            var packState = isDicom ? subjectVisit.PackState : subjectVisit.NoDicomPackState;

            if (packState == PackState.WaitPack)
            {

                if (isDicom)
                {
                    subjectVisit.PackState = PackState.Packing;
                    HangfireJobHelper.NotImmediatelyOnceOnlyJob<IDownloadAndUploadService>(t => t.PackageAndAnonymizImage(trialId, subjectVisitId, true, isAnonymize), TimeSpan.FromSeconds(1));

                }
                else
                {
                    subjectVisit.NoDicomPackState = PackState.Packing;

                    HangfireJobHelper.NotImmediatelyOnceOnlyJob<IDownloadAndUploadService>(t => t.PackageAndAnonymizImage(trialId, subjectVisitId, false, isAnonymize), TimeSpan.FromSeconds(1));
                }


                await _subjectVisitRepository.SaveChangesAsync();
            }

            return ResponseOutput.Ok(isDicom ? subjectVisit.VisitImageZipPath : subjectVisit.VisitNoDicomImageZipPath,
                new { FileName = $"{sujectCode}_{subjectVisit.VisitName}_ImageStudy_{(isDicom ? "Dicom" : "NoneDicom")}.zip" });

        }



        /// <summary>
        /// 受试者级别所有的影像
        /// 访视级别的影响 传递subjectVisitId
        /// 标准Id是可选的  不同标准有些检查可能有过滤
        /// </summary>
        /// <param name="_subjectRepository"></param>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        public async Task<IResponseOutput> GetSubejectOrVisitZipInfo([FromServices] IRepository<Subject> _subjectRepository, SubejctZipInfoQuery inQuery)
        {
            var isImageFilter = false;

            var criterionModalitys = string.Empty;

            if (inQuery.TrialReadingCriterionId != null)
            {
                var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId).Select(t => new { t.IsImageFilter, t.CriterionModalitys }).FirstOrDefaultAsync();

                if (criterionInfo != null)
                {
                    isImageFilter = criterionInfo.IsImageFilter;
                    criterionModalitys = criterionInfo.CriterionModalitys;
                }

            }

            if (inQuery.SubejectVisitId != null)
            {
                var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubejectVisitId)


                            select new
                            {
                                SubjectCode = sv.Subject.Code,
                                VisitName = sv.VisitName,
                                StudyList = sv.StudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
                                .Select(u => new
                                {
                                    u.PatientId,
                                    u.StudyTime,
                                    u.StudyCode,

                                    SeriesList = u.SeriesList.Select(z => new
                                    {
                                        z.Modality,

                                        InstancePathList = z.DicomInstanceList.Select(k => new
                                        {
                                            k.Path
                                        })
                                    })

                                }),

                                NoneDicomStudyList = sv.NoneDicomStudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.Modality + "|"))
                                .Select(nd => new
                                {
                                    nd.Modality,
                                    nd.StudyCode,
                                    nd.ImageDate,

                                    FileList = nd.NoneDicomFileList.Select(file => new
                                    {
                                        file.FileName,
                                        file.Path,
                                        file.FileType
                                    })
                                })
                            };

                var result = query.ToList();

                return ResponseOutput.Ok(result);
            }
            else if (inQuery.SubejctId != null)
            {
                var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubejctId).SelectMany(t => t.SubjectVisitList)


                            select new
                            {
                                SubjectCode = sv.Subject.Code,
                                VisitName = sv.VisitName,
                                StudyList = sv.StudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
                                .Select(u => new
                                {
                                    u.PatientId,
                                    u.StudyTime,
                                    u.StudyCode,

                                    SeriesList = u.SeriesList.Select(z => new
                                    {
                                        z.Modality,

                                        InstancePathList = z.DicomInstanceList.Select(k => new
                                        {
                                            k.Path
                                        })
                                    })

                                }),

                                NoneDicomStudyList = sv.NoneDicomStudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.Modality + "|"))
                                .Select(nd => new
                                {
                                    nd.Modality,
                                    nd.StudyCode,
                                    nd.ImageDate,

                                    FileList = nd.NoneDicomFileList.Select(file => new
                                    {
                                        file.FileName,
                                        file.Path,
                                        file.FileType
                                    })
                                })
                            };

                var result = query.ToList();

                return ResponseOutput.Ok(result);
            }
            else
            {
                return ResponseOutput.NotOk("不允许 subjectId  SubejectVisitId 都不传递");
            }


        }

        /// <summary>
        /// 后台任务调用,前端忽略该接口
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="isDicom"></param>
        /// <param name="isAnonymize"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true)
        {

            var subjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);

            try
            {
                var addOrUpdateFixedFieldList = new List<SystemAnonymization>();

                var ircFieldList = new List<SystemAnonymization>();

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

                    addOrUpdateFixedFieldList = systemAnonymizationList.Where(t => t.IsFixed).ToList();

                    ircFieldList = systemAnonymizationList.Where(t => t.IsFixed == false).ToList();
                }

                var subjectAndVisitInfo = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { SubjectCode = t.Subject.Code, t.Trial.TrialCode, t.VisitNum }).FirstOrDefault();

                var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)

                            select new
                            {
                                SubjectCode = sv.Subject.Code,
                                VisitName = sv.VisitName,
                                StudyList = sv.StudyList.Select(u => new
                                {
                                    u.PatientId,
                                    u.StudyTime,
                                    u.StudyCode,

                                    SeriesList = u.SeriesList.Select(z => new
                                    {
                                        z.Modality,

                                        InstancePathList = z.DicomInstanceList.Select(k => new
                                        {
                                            k.Path
                                        })
                                    })

                                }),

                                NoneDicomStudyList = sv.NoneDicomStudyList.Select(nd => new
                                {
                                    nd.Modality,
                                    nd.StudyCode,
                                    nd.ImageDate,

                                    FileList = nd.NoneDicomFileList.Select(file => new
                                    {
                                        file.FileName,
                                        file.Path,
                                        file.FileType
                                    })
                                })
                            };

                var info = query.FirstOrDefault();

                if (info != null)
                {
                    // 创建一个临时文件夹来存放文件
                    string tempFolderPath = Path.Combine(Directory.GetCurrentDirectory(), $"DownloadTemp_{NewId.NextGuid()}");
                    Directory.CreateDirectory(tempFolderPath);

                    //dicom  处理

                    if (isDicom)
                    {
                        // 遍历查询结果
                        foreach (var studyInfo in info.StudyList)
                        {
                            // 遍历 Series
                            foreach (var seriesInfo in studyInfo.SeriesList)
                            {
                                string studyDicomFolderPath = Path.Combine(tempFolderPath, "Dicom",/* $"{info.SubjectCode}_{info.VisitName}",*/ $"{studyInfo.StudyCode}_{studyInfo.StudyTime?.ToString("yyyy-MM-dd")}_{seriesInfo.Modality}");

                                // 创建 影像 文件夹
                                Directory.CreateDirectory(studyDicomFolderPath);

                                // 遍历 InstancePathList
                                foreach (var instanceInfo in seriesInfo.InstancePathList)
                                {
                                    // 复制文件到相应的文件夹
                                    string destinationPath = Path.Combine(studyDicomFolderPath, Path.GetFileName(instanceInfo.Path));

                                    //下载到当前目录
                                    await _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath);

                                    #region 匿名化逻辑


                                    if (isAnonymize)
                                    {
                                        //受试者随机阅片,需要匿名化检查时间
                                        DicomFile dicomFile = await DicomFile.OpenAsync(destinationPath, Encoding.Default);
                                        DicomDataset dataset = dicomFile.Dataset;
                                        dataset.AddOrUpdate(DicomTag.StudyDate, string.Empty);
                                        dataset.AddOrUpdate(DicomTag.StudyTime, string.Empty);

                                        #region 前端已经匿名化,不需要做相关tag匿名化
                                        //DicomFile dicomFile = await DicomFile.OpenAsync(destinationPath, Encoding.Default);

                                        //DicomDataset dataset = dicomFile.Dataset;

                                        //foreach (var item in addOrUpdateFixedFieldList)
                                        //{

                                        //    var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));

                                        //    dataset.AddOrUpdate(dicomTag, item.ReplaceValue);
                                        //}

                                        //foreach (var item in ircFieldList)
                                        //{

                                        //    var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));

                                        //    if (dicomTag == DicomTag.ClinicalTrialProtocolID)
                                        //    {
                                        //        dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialCode);

                                        //    }
                                        //    if (dicomTag == DicomTag.ClinicalTrialSiteID)
                                        //    {
                                        //        //dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialSiteCode);

                                        //    }
                                        //    if (dicomTag == DicomTag.ClinicalTrialSubjectID)
                                        //    {
                                        //        dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.SubjectCode);

                                        //    }
                                        //    if (dicomTag == DicomTag.ClinicalTrialTimePointID)
                                        //    {
                                        //        dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.VisitNum.ToString());

                                        //    }
                                        //    if (dicomTag == DicomTag.PatientID)
                                        //    {
                                        //        dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialCode + "_" + subjectAndVisitInfo.SubjectCode);

                                        //    }

                                        //}
                                        #endregion

                                    }
                                    #endregion
                                }
                            }
                        }


                        var zipDicomPath = Path.Combine(Directory.GetCurrentDirectory(), $"{info.SubjectCode}_{info.VisitName}_ImageStudy_Dicom.zip");
                        ZipFile.CreateFromDirectory(Path.Combine(tempFolderPath, "Dicom"), zipDicomPath);
                        //上传到Oss
                        var relativeDicomPath = await _oSSService.UploadToOSSAsync(zipDicomPath, $"download_zip", false);

                        await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.Packed, VisitImageZipPath = relativeDicomPath });


                        File.Delete(zipDicomPath);
                    }
                    else
                    {
                        var relativeNoneDicomPath = string.Empty;

                        if (info.NoneDicomStudyList.Count() == 1 && info.NoneDicomStudyList.SelectMany(t => t.FileList).Count() == 1)
                        {
                            relativeNoneDicomPath = info.NoneDicomStudyList.First().FileList.First().Path;
                        }
                        else
                        {
                            //非dicom 处理

                            foreach (var noneDicomStudy in info.NoneDicomStudyList)
                            {
                                string studyNoneDicomFolderPath = Path.Combine(tempFolderPath, "NoneDicom", /*$"{info.SubjectCode}_{info.VisitName}",*/ $"{noneDicomStudy.StudyCode}_{noneDicomStudy.ImageDate.ToString("yyyy-MM-dd")}_{noneDicomStudy.Modality}");

                                Directory.CreateDirectory(studyNoneDicomFolderPath);

                                foreach (var file in noneDicomStudy.FileList)
                                {
                                    string destinationPath = Path.Combine(studyNoneDicomFolderPath, Path.GetFileName(file.FileName));

                                    //下载到当前目录
                                    await _oSSService.DownLoadFromOSSAsync(HttpUtility.UrlDecode(file.Path), destinationPath);
                                }
                            }

                            var zipNoneDicomPath = Path.Combine(Directory.GetCurrentDirectory(), $"{info.SubjectCode}_{info.VisitName}_ImageStudy_NoneDicom.zip");
                            ZipFile.CreateFromDirectory(Path.Combine(tempFolderPath, "NoneDicom"), zipNoneDicomPath);
                            relativeNoneDicomPath = await _oSSService.UploadToOSSAsync(zipNoneDicomPath, $"download_zip", false);

                            File.Delete(zipNoneDicomPath);
                        }

                        await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.Packed, VisitNoDicomImageZipPath = relativeNoneDicomPath });


                    }

                    //清理文件夹
                    Directory.Delete(tempFolderPath, true);

                }
            }
            catch (Exception ex)
            {
                await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.WaitPack });

            }





        }


        #region 按照任务为维度 展示上传的列表  废弃
        /// <summary>
        /// IR 影像上传任务列表 --old  20240903 界面调整,现在先废弃
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<SubjectUploadTaskInfo>> GetIRUploadTaskList_Old(CRCUploadTaskQuery inQuery)
        {
            var query = _visitTaskRepository.Where(t => t.SubjectId == inQuery.SubjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
                                                   && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.Id && t.TaskState == TaskState.Effect)
               .ProjectTo<SubjectUploadTaskInfo>(_mapper.ConfigurationProvider);


            var list = await query.Where(t => t.SubjectCode == inQuery.SubjectCode).ToListAsync();

            return list;
        }
        /// <summary>
        /// IR 上传任务  dicom 列表  后处理的数据不能排序  --old  20240903 界面调整,现在先废弃
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<IRUploadTaskDicomStudyDto>> GetIRUploadTaskDicomStudyList_Old(CRCUploadTaskStudyQuery inQuery)
        {
            var list = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
                  .SelectMany(t => t.SourceSubjectVisit.StudyList)
                 .ProjectTo<IRUploadTaskDicomStudyDto>(_mapper.ConfigurationProvider).SortToListAsync(inQuery);

            var taskDicomStudyList = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
                  .SelectMany(t => t.TaskStudyList)
                  .Select(u => new
                  {
                      u.Id,
                      u.SeriesCount,
                      u.InstanceCount,
                      SopInstanceList = u.InstanceList.Select(t => t.SopInstanceUid).ToList()
                  })
                 .ToList();

            foreach (var item in list)
            {
                var find = taskDicomStudyList.FirstOrDefault(t => t.Id == item.Id);

                if (find != null)
                {
                    item.UploadedInstanceCount = find.InstanceCount;
                    item.UploadedSopInstanceUidList = find.SopInstanceList;
                    item.UploadedSeriesCount = find.SeriesCount;
                }
            }

            return list;
        }

        /// <summary>
        /// IR 上传任务  nonedicom 列表  后处理的数据不能排序  --old  20240903 界面调整,现在先废弃
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<IRUploadTaskNoneDicomStudyDto>> GetIRUploadTaskNoneDicomStudyList_Old(CRCUploadTaskStudyQuery inQuery)
        {
            var list = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
                 .SelectMany(t => t.SourceSubjectVisit.StudyList)
                .ProjectTo<IRUploadTaskNoneDicomStudyDto>(_mapper.ConfigurationProvider).SortToListAsync(inQuery);

            var taskNoneDicomStudyList = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
                  .SelectMany(t => t.TaskNoneDicomStudyFileList).Where(t => t.VisitTaskId == inQuery.VisitTaskId)
                  .Select(u => new
                  {
                      u.OriginNoneDicomStudyId,
                  })
                 .ToList();

            foreach (var item in list)
            {
                item.UploadedFileCount = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).Count();
            }

            return list;

        }
        #endregion



        #region IR 上传 列表,dicom 上以任务为维度,非dicom 以检查为维度





        /// <summary>
        /// IR 上传任务  nonedicom 列表  后处理的数据UploadedFileCount不能排序  --new
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<TaskNoneDicomStudyDTO>> GetIRUploadTaskNoneDicomStudyList(IRUploadStudyQuery inQuery)
        {
            var query = from u in _visitTaskRepository.Where(t => t.SubjectId == inQuery.SubjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
                                                   && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.Id && t.TaskState == TaskState.Effect)
                        join ns in _noneDicomStudyReposiotry.Where(t => t.SubjectId == inQuery.SubjectId) on u.SourceSubjectVisitId equals ns.SubjectVisitId

                        select new TaskNoneDicomStudyDTO()
                        {
                            SubjectId = u.SubjectId,
                            SubjectCode = u.IsSelfAnalysis == true ? u.BlindSubjectCode : u.Subject.Code,
                            TaskBlindName = u.TaskBlindName,
                            TaskName = u.TaskName,
                            SourceSubjectVisitId = u.SourceSubjectVisitId,

                            Id = ns.Id,
                            Description = ns.Description,
                            ImageDate = ns.ImageDate,
                            BodyPart = ns.BodyPart,
                            FileCount = ns.FileCount,
                            Modality = ns.Modality,
                            StudyCode = ns.StudyCode,

                        };

            var list = await query.Where(t => t.SubjectCode == inQuery.SubjectCode).SortToListAsync(inQuery);

            var noneDicomStudyIdList = list.Select(t => t.Id).ToList();


            var taskNoneDicomStudyList = _visitTaskRepository.Where(t => noneDicomStudyIdList.Contains(t.Id))
                  .SelectMany(t => t.TaskNoneDicomStudyFileList).Where(t => noneDicomStudyIdList.Contains((Guid)t.VisitTaskId))
                  .Select(u => new
                  {
                      u.OriginNoneDicomStudyId,
                  })
                 .ToList();

            foreach (var item in list)
            {
                item.UploadedFileCount = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).Count();
            }

            return list;

        }
        #endregion


        /// <summary>
        /// IQC  获取CRC 上传到某一个访视的的检查信息 (原始影像信息  包含dicom  非dicom)
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IResponseOutput> GetCRCUploadedStudyInfo(CRCUploadedStudyQuqry inQuery)
        {
            var isQueryDicom = inQuery.DicomStudyIdList.Count > 0;
            var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0;

            var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId)


                        select new
                        {
                            SubjectCode = sv.Subject.Code,
                            VisitName = sv.VisitName,

                            StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)

                            .Select(u => new
                            {
                                u.PatientId,
                                u.StudyTime,
                                u.StudyCode,

                                SeriesList = u.SeriesList.Select(z => new
                                {
                                    z.Modality,

                                    InstanceList = z.DicomInstanceList.Select(k => new
                                    {
                                        k.Path,
                                        k.FileSize
                                    })
                                })

                            }).ToList(),

                            NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)

                            .Select(nd => new
                            {
                                nd.Modality,
                                nd.StudyCode,
                                nd.ImageDate,

                                FileList = nd.NoneDicomFileList.Select(file => new
                                {
                                    file.FileName,
                                    file.Path,
                                    file.FileType
                                })
                            }).ToList()
                        };

            var result = query.FirstOrDefault();

            return ResponseOutput.Ok(result);
        }


        /// <summary>
        /// IR 阅片页面 和IR 任务列表页面下载  勾选下载列表(后端要考虑到一致性分析 subjectCode的问题)
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<SubjectCRCImageUploadedStudyDto>> GetSubjectImageDownloadSelectList(IRReadingDownloadQuery inQuery)
        {

            var query = _visitTaskRepository.Where(t => t.SubjectId == inQuery.SubjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
                                                    && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.Id && t.TaskState == TaskState.Effect)
                .ProjectTo<SubjectCRCImageUploadedDto>(_mapper.ConfigurationProvider);


            var list = await query.Where(t => t.SubjectCode == inQuery.SubjectCode).ToListAsync();

            #region 将任务级别转为检查级别

            var result = new List<SubjectCRCImageUploadedStudyDto>();

            var dicomStudyList = list.Where(item => item.DicomStudyList.Count > 0)
              .Select(item => new SubjectCRCImageUploadedStudyDto
              {
                  VisitTaskId = item.VisitTaskId,
                  SubjectId = item.SubjectId,
                  SubjectCode = item.SubjectCode,
                  TaskBlindName = item.TaskBlindName,
                  TaskName = item.TaskName,
                  IsImageFilter = item.IsImageFilter,
                  CriterionModalitys = item.CriterionModalitys,
                  SourceSubjectVisitId = item.SourceSubjectVisitId,
                  //取dicom
                  DicomStudyList = item.DicomStudyList,
              }).ToList();

            var noneStudyList = list.Where(item => item.NoneDicomStudyList.Count > 0)
           .Select(item => new SubjectCRCImageUploadedStudyDto
           {
               VisitTaskId = item.VisitTaskId,
               SubjectId = item.SubjectId,
               SubjectCode = item.SubjectCode,
               TaskBlindName = item.TaskBlindName,
               TaskName = item.TaskName,
               IsImageFilter = item.IsImageFilter,
               CriterionModalitys = item.CriterionModalitys,
               SourceSubjectVisitId = item.SourceSubjectVisitId,
               //非dicom
               NoneDicomStudyList = item.NoneDicomStudyList,
           }).ToList();


            result.AddRange(dicomStudyList);
            result.AddRange(noneStudyList);
            #endregion


            return result;

        }

        /// <summary>
        /// IR 阅片页面获取下载检查的信息  会根据标准进行过滤检查,(后端要考虑到一致性分析 subjectCode的问题)
        /// 检查在访视下面,所以需要传递下载的访视Id,另外下载访视下面那些检查,就把访视下的对应的检查Id 丢到数组里就好
        /// </summary>
        /// <param name="inQuery"></param>
        /// <param name="_subjectRepository"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IResponseOutput> GetIRReadingDownloadStudyInfo(IRDownloadQuery inQuery, [FromServices] IRepository<Subject> _subjectRepository)
        {
            var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
                  .Select(t => new { t.IsImageFilter, t.CriterionModalitys }).FirstNotNullAsync();

            var isQueryDicom = inQuery.DicomStudyIdList.Count > 0;
            var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0;

            var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => inQuery.SubjectVisitIdList.Contains(t.Id)))

                        select new
                        {
                            SubjectCode = sv.Subject.Code,
                            VisitName = sv.VisitName,
                            StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
                            .Select(u => new
                            {
                                u.PatientId,
                                u.StudyTime,
                                u.StudyCode,

                                SeriesList = u.SeriesList.Select(z => new
                                {
                                    z.Modality,

                                    InstancePathList = z.DicomInstanceList.Select(k => new
                                    {
                                        k.Path
                                    })
                                })

                            }),

                            NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
                            .Select(nd => new
                            {
                                nd.Modality,
                                nd.StudyCode,
                                nd.ImageDate,

                                FileList = nd.NoneDicomFileList.Select(file => new
                                {
                                    file.FileName,
                                    file.Path,
                                    file.FileType
                                })
                            })
                        };



            var result = await query.FirstOrDefaultAsync();

            return ResponseOutput.Ok(result);
        }

    }


}