using Hangfire;
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
using IRaCIS.Core.Application.BackGroundJob;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Domain.Share;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Http;
using MiniExcelLibs;
using ExcelDataReader;
using System.Text;
using System.Data;
using Microsoft.AspNetCore.Authorization;
using WinSCP;
using Magicodes.ExporterAndImporter.Excel;
using Newtonsoft.Json;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using Nito.AsyncEx;

namespace IRaCIS.Core.Application.Image.QA
{
    [ApiExplorerSettings(GroupName = "Image")]
    public class QCOperationService : BaseService, IQCOperationService
    {

        private readonly DicomFileStoreHelper _dicomFileStoreHelper;
        private readonly IRepository<SubjectVisit> _subjectVisitRepository;
        private readonly IRepository<QCChallenge> _qcChallengeRepository;
        private readonly IRepository<DicomStudy> _dicomStudyRepository;
        private readonly IRepository<Subject> _subjectRepository;
        private readonly IRepository<Trial> _trialRepository;
        private readonly IMediator _mediator;

        private readonly AsyncLock _mutex = new AsyncLock();

        public QCOperationService(DicomFileStoreHelper dicomFileStoreHelper, IRepository<SubjectVisit> subjectVisitRepository,
            IRepository<QCChallenge> qcChallengeRepository,
            IRepository<Trial> trialRepository,
            IMediator mediator,
            IRepository<DicomStudy> dicomStudyRepository,
            IRepository<Subject> subjectRepository
            )
        {
            _dicomFileStoreHelper = dicomFileStoreHelper;
            _subjectVisitRepository = subjectVisitRepository;
            _qcChallengeRepository = qcChallengeRepository;
            _dicomStudyRepository = dicomStudyRepository;
            this._subjectRepository = subjectRepository;
            _mediator = mediator;
            _trialRepository = trialRepository;
        }

        #region QC质疑 以及回复 关闭

        [HttpGet("{trialId:guid}/{subjectVisitId:guid}/{currentQCType:int}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> VerifyQCCanAddChallenge(Guid subjectVisitId, [FromRoute] CurrentQC currentQCType)
        {
            await VerifyIsCanQCAsync(null, subjectVisitId);
            if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == currentQCType))
            {
                return ResponseOutput.NotOk("请先核查图像，保存审核问题后，再发质疑。");
            }
            return ResponseOutput.Ok();

        }

        /// <summary>
        ///  添加和更新质疑
        /// </summary>
        /// <param name="qaQuestionCommand"></param>
        /// <param name="trialId"></param>
        /// <param name="trialQCProcess"></param>
        /// <param name="currentQCType"></param>
        /// <returns></returns>
        [HttpPost("{trialId:guid}/{trialQCProcess:int}/{currentQCType:int}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        [Authorize(Policy = "ImageQCPolicy")]
        public  async Task<IResponseOutput> AddOrUpdateQCChallenge(QCChallengeCommand qaQuestionCommand, Guid trialId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
        {
            await VerifyIsCanQCAsync(null, qaQuestionCommand.SubjectVisitId);

            if (qaQuestionCommand.Id == null)
            {
                if (await _qcChallengeRepository.AnyAsync(t => t.IsClosed == false && t.SubjectVisitId == qaQuestionCommand.SubjectVisitId && t.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))
                {
                    throw new BusinessValidationFailedException("当前访视有未关闭的 同意CRC上传的质疑，不允许再次添加质疑");

                }

                var trialConfig = (await _trialRepository.Where(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification }).FirstOrDefaultAsync()).IfNullThrowException();



                using (await _mutex.LockAsync())
                {
                    //获取编号
                    var code = _qcChallengeRepository.Where(t => t.TrialId == trialId).Select(t => t.ChallengeCode).DefaultIfEmpty().Max();

                    var qcChallenge = _mapper.Map<QCChallenge>(qaQuestionCommand);

                    qcChallenge.QCProcessEnum = trialConfig.QCProcessEnum;
                    qcChallenge.CurrentQCEnum = currentQCType;
                    qcChallenge.TrialId = trialId;
                    qcChallenge.ChallengeCode = code + 1;
                    qcChallenge.UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt;

                    qcChallenge = await _qcChallengeRepository.AddAsync(qcChallenge, true);

                    return ResponseOutput.Ok(qcChallenge.Id);

                }

            }
            else
            {

                 await _repository.UpdateFromDTOAsync<QCChallenge, QCChallengeCommand>(qaQuestionCommand, true);

                return ResponseOutput.Ok();

            }


        }


        /// <summary>
        /// 关闭质疑，什么情况下允许？
        /// </summary>
        /// <param name="qcChallengeId"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="closeEnum"></param>
        /// <param name="closeReason"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}/{closeEnum}/{closeReason}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        [UnitOfWork]
        //[Authorize(Policy = "ImageQCPolicy")]
        public async Task<IResponseOutput> CloseQCChallenge(Guid qcChallengeId, Guid subjectVisitId, [FromRoute] QCChallengeCloseEnum closeEnum, [FromRoute] string closeReason)
        {

            if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IQC)
            {
                await VerifyIsCanQCAsync(null, subjectVisitId);
            }

            var dbQCChallenge = (await _qcChallengeRepository.FirstOrDefaultAsync(t => t.Id == qcChallengeId)).IfNullThrowException();


            if (dbQCChallenge.ReuploadEnum == QCChanllengeReuploadEnum.CRCRequestReupload || dbQCChallenge.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload)
            {
                throw new BusinessValidationFailedException("CRC申请重传的/QC同意重传的质疑，在CRC设置重传完成前不允许关闭质疑");
            }


            #region 之前

            dbQCChallenge.CloseResonEnum = closeEnum;

            dbQCChallenge.IsClosed = true;

            dbQCChallenge.ClosedTime = DateTime.Now;


            dbQCChallenge.DialogList.Add(new QCChallengeDialog()
            {
                SubjectVisitId = dbQCChallenge.SubjectVisitId,
                UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
                QCChallengeId = dbQCChallenge.Id,
                TalkContent = "关闭原因: " + closeReason
            });

            var success = await _qcChallengeRepository.SaveChangesAsync();

            #endregion


            return ResponseOutput.Result(success);

        }






        /// <summary>
        /// 删除QC质疑记录
        /// </summary>
        /// <returns></returns>
        [HttpDelete("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        [Authorize(Policy = "ImageQCPolicy")]
        public async Task<IResponseOutput> DeleteQCChallenge(Guid qcChallengeId)
        {

            if (await _repository.AnyAsync<QCChallengeDialog>(t => t.QCChallengeId == qcChallengeId))
            {
                ResponseOutput.NotOk("this QC Challenge Has been replied ");
            }

            var qaRecord = (await _qcChallengeRepository.FirstOrDefaultAsync(t => t.Id == qcChallengeId)).IfNullThrowException();


            await _qcChallengeRepository.DeleteAsync(qaRecord);


            var success1 = await _repository.SaveChangesAsync();

            return ResponseOutput.Result(success1 /*|| success2 || success3*/);
        }

        /// <summary>
        /// 针对 某条QC质疑 添加回复  
        /// </summary>
        /// <param name="qaDialogCommand"></param>
        /// <returns></returns>
        [HttpPost("{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        [Authorize(Policy = "ImageQCPolicy")]
        public async Task<IResponseOutput> AddQCChallengeReply(QADialogCommand qaDialogCommand)
        {
            var qaReply = _mapper.Map<QCChallengeDialog>(qaDialogCommand);

            await _repository.AddAsync(qaReply);

            qaReply.UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt;

            var dbQCChallenge = (await _repository.FirstOrDefaultAsync<QCChallenge>(t => t.Id == qaDialogCommand.QCChallengeId)).IfNullThrowException();

            dbQCChallenge.LatestMsgTime = DateTime.Now;


            dbQCChallenge.LatestReplyUserId = _userInfo.Id;


            var success = await _repository.SaveChangesAsync();


            return ResponseOutput.Result(success, qaReply);
        }

        #endregion


        #region 一致性核查

        /// <summary>
        /// 一致性核查 质疑的添加/回复
        /// </summary>
        /// <param name="checkDialogCommand"></param>
        /// <returns></returns>
        [HttpPost("{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        [Authorize(Policy = "ImageCheckPolicy")]
        public async Task<IResponseOutput> AddCheckChallengeReply(CheckChallengeDialogCommand checkDialogCommand)
        {


            //修改一致性核查 质疑状态
            var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == checkDialogCommand.SubjectVisitId)).IfNullThrowException();

            var qaReply = _mapper.Map<CheckChallengeDialog>(checkDialogCommand);

            qaReply.UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt;

            await _repository.AddAsync(qaReply);

            if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator)
            {
                sv.CheckChallengeState = CheckChanllengeTypeEnum.CRCWaitPMReply;

            }
            else if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager)
            {
                sv.CheckChallengeState = CheckChanllengeTypeEnum.PMWaitCRCReply;
            }
            else
            {
                throw new BusinessValidationFailedException("一致性核查对话操作用户 只允许  CRC/PM");
            }

            var success = await _repository.SaveChangesAsync();

            return ResponseOutput.Result(success, qaReply.Id);
        }

        /// <summary>
        /// 关闭  一致性核查质疑
        /// </summary>
        /// <returns></returns>
        [HttpPut("{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> CloseCheckChallenge(CloseCheckChallengeDto input)
        {

            var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == input.subjectVisitId)).IfNullThrowException();

            if (sv.RequestBackState == RequestBackStateEnum.PM_AgressBack)
            {
                ResponseOutput.NotOk("执行一致性核查的访视 不允许关闭质疑!");
            }
            sv.CloseTheReason = input.CloseCheckChallenge;
            sv.CheckChallengeState = CheckChanllengeTypeEnum.Closed;

            await _repository.SaveChangesAsync();

            return ResponseOutput.Ok(sv);
        }


        /// <summary>
        /// 手动设置一致性核查通过
        /// </summary>
        /// <returns></returns>
        [HttpPut("{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> SetCheckPass(SetCheckPassDt data)
        {
            if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager)
            {
                ResponseOutput.NotOk("只允许PM 手动设置一致性核查通过");
            }

            var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == data.SubjectVisitId)).IfNullThrowException();


            if (sv.RequestBackState == RequestBackStateEnum.PM_AgressBack)
            {
                ResponseOutput.NotOk("当前是PM同意回退,不允许设置一致性核查通过");
            }

            if (sv.CheckChallengeState != CheckChanllengeTypeEnum.Closed && sv.AuditState == AuditStateEnum.QCPassed)
            {
                ResponseOutput.NotOk("一致性核查质疑未关闭/审核状态不是通过，不允许设置一致性核查通过");
            }

            sv.CheckState = CheckStateEnum.CVPassed;

            sv.ForwardState = ForwardStateEnum.ToForward;
            sv.ManualPassReason = data.ManualPassReason;
            sv.CheckPassedTime = DateTime.Now;

            await _subjectVisitRepository.SaveChangesAsync();


            return ResponseOutput.Result(true);

        }

        /// <summary>
        /// CRC 请求回退
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> CRCRequstCheckBack(Guid subjectVisitId)
        {
            var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();


            if (sv.CheckState == CheckStateEnum.CVPassed)
            {
                return ResponseOutput.NotOk("核查通过的数据不允许申请回退");
            }

            await _subjectVisitRepository.UpdatePartialFromQueryAsync( subjectVisitId, u => new SubjectVisit() { RequestBackState = RequestBackStateEnum.CRC_RequestBack },true);

            return ResponseOutput.Ok();

        }

        /// <summary>
        /// 一致性核查 回退  对话记录不清除  只允许PM回退  [签名  不需要对]
        /// </summary>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> CheckBack(Guid subjectVisitId)
        {
            if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager)
            {
                return ResponseOutput.NotOk(" 只允许PM 回退!");
            }

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


            if (sv.CheckState == CheckStateEnum.CVPassed || sv.CheckState == CheckStateEnum.ToCheck)
            {
                return ResponseOutput.NotOk("待核查/核查通过的数据不允许回退");
            }

            //sv.CheckChallengeState = (int)CheckChanllengeTypeEnum.None;
            //sv.CheckState = CheckStateEnum.None;
            //sv.ChallengeState = (int)ChallengeStateEnum.No;

            sv.AuditState = AuditStateEnum.None;
            sv.SubmitState = SubmitStateEnum.ToSubmit;

            //回退后，回退状态恢复
            sv.RequestBackState = RequestBackStateEnum.NotRequest;
            sv.IsCheckBack = true;
            sv.CheckState = CheckStateEnum.None;
            sv.CheckChallengeState = CheckChanllengeTypeEnum.None;

            sv.SVENDTC = null;
            sv.SVSTDTC = null;

            sv.PreliminaryAuditTime = null;
            sv.SubmitTime = null;
            sv.ReviewAuditTime = null;
            sv.CurrentActionUserExpireTime = null;


            sv.IsTake = false;
            sv.CurrentActionUserId = null;
            sv.PreliminaryAuditUserId = null;
            sv.ReviewAuditUserId = null;

            //var success1 = _studyRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
            //var succeess2 = _instanceRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
            //var success3 = _seriesRepository.Delete(t => t.SubjectVisitId == subjectVisitId);

            //_qcChallengeRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
            //_qcChallengeDialogRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
            //_checkChallengeDialogRepository.Delete(t => t.SubjectVisitId == subjectVisitId);
            await _repository.AddAsync(new CheckChallengeDialog() { SubjectVisitId = subjectVisitId, TalkContent = "PM执行了一致性核查回退", UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt });

            await _repository.BatchDeleteAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId);

            var success = await _subjectVisitRepository.SaveChangesAsync();


            return ResponseOutput.Result(success);

        }


        /// <summary>
        /// 一致性核查 excel上传 支持三种格式
        /// </summary>
        /// <param name="file"></param>
        /// <param name="trialId"></param>
        /// <returns></returns>
        [HttpPost("{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> UploadVisitCheckExcel(IFormFile file, Guid trialId)
        {
            if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ProjectManager)
            {
                return ResponseOutput.NotOk("只允许PM 操作");
            }

            var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;

            var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.ToString().Trim('"').ToLower();
            if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".csv") && !fileName.EndsWith(".xls"))
            {
                return ResponseOutput.NotOk("只允许Excel、 CSV！");
            }

            //上传根路径
            string uploadFolderPath = Path.Combine(rootPath, "UploadFile", "Check");

            if (!Directory.Exists(uploadFolderPath))
            {
                Directory.CreateDirectory(uploadFolderPath);
            }

            //存放核对表
            var filePath = Path.Combine(uploadFolderPath, DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + fileName);
            using (FileStream fs = System.IO.File.Create(filePath))
            {
                await file.CopyToAsync(fs);
                await fs.FlushAsync();
            }

            //获取Excel表内容
            var config = new MiniExcelLibs.Csv.CsvConfiguration()
            {
                StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
            };

            var etcCheckList = new List<CheckViewModel>();



            #region MiniExcel  需要自己验证数据格式规范

            //if (fileName.EndsWith(".csv"))
            //{
            //    //因为csv 需要加配置文件 不然都是null
            //    etcCheckList = MiniExcel.Query<CheckViewModel>(filePath, null, configuration: config).ToList();
            //}
            //else if (fileName.EndsWith(".xlsx"))
            //{
            //    


            //    etcCheckList = MiniExcel.Query<CheckViewModel>(filePath).ToList();
            //}

            #endregion

            //Magicodes 支持自定义特性验证
            if (fileName.EndsWith(".xlsx"))
            {
                var Importer = new ExcelImporter();

                var import = await Importer.Import<CheckViewModel>(File.OpenRead(filePath));

                if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());

                if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));

                if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));

                etcCheckList = import.Data.ToList();
            }
            else if (fileName.EndsWith(".csv"))
            {
                #region   临时方案   MiniExcel读取  然后保存为xlsx  再用 Magicodes验证数据

                //因为csv 需要加配置文件 不然都是null
                etcCheckList = MiniExcel.Query<CheckViewModel>(filePath, null, configuration: config).ToList();

                var csVToXlsxPath = Path.Combine(uploadFolderPath, DateTime.Now.ToString("yyyy-MM-dd-hh-mm-ss") + Path.GetFileNameWithoutExtension(fileName) + ".xlsx");

                await MiniExcel.SaveAsAsync(csVToXlsxPath, etcCheckList, excelType: ExcelType.XLSX);


                var Importer = new ExcelImporter();

                var import = await Importer.Import<CheckViewModel>(File.OpenRead(csVToXlsxPath));

                if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());

                if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));

                if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));

                etcCheckList = import.Data.ToList();

                #endregion


                #region 导入组件有问题  excel编码格式
                //var Importer = new CsvImporter();

                //var import = await Importer.Import<CheckViewModel>(File.OpenRead(filePath));

                //if (import.Exception != null) return ResponseOutput.NotOk(import.Exception.ToString());

                //if (import.RowErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.RowErrors));

                //if (import.TemplateErrors.Count > 0) return ResponseOutput.NotOk(JsonConvert.SerializeObject(import.TemplateErrors));

                //etcCheckList = import.Data.ToList();
                #endregion

            }
            //ExcelReaderFactory  需要自己验证数据 并且从固定列取数据
            else
            {
                //为了支持 xls  引入新的组件库
                using (var stream = System.IO.File.Open(filePath, FileMode.Open, FileAccess.Read))
                {
                    // Auto-detect format, supports:
                    //  - Binary Excel files (2.0-2003 format; *.xls)
                    //  - OpenXml Excel files (2007 format; *.xlsx, *.xlsb)
                    using (var reader = ExcelReaderFactory.CreateReader(stream))
                    {

                        // 2. Use the AsDataSet extension method
                        var dateset = reader.AsDataSet();

                        foreach (DataRow col in dateset.Tables[0].Rows)
                        {

                            etcCheckList.Add(new CheckViewModel()
                            {
                                SiteCode = col[0].ToString(),
                                SubjectCode = col[1].ToString(),
                                VisitName = col[2].ToString(),
                                StudyDate = col[3].ToString(),
                                Modality = col[4].ToString(),
                            });
                        }

                        etcCheckList.Remove(etcCheckList[0]);

                        // The result of each spreadsheet is in result.Tables
                    }
                }
            }


            //etcCheckList = etcCheckList.Where(t=>)

            if (etcCheckList == null || etcCheckList.Count == 0)
            {
                return ResponseOutput.NotOk("请上传规定格式的Excel文件，保证有有效数据！");
            }
            else
            {
                //处理Excel  有时只是清除某些行的数据  读取也会读到数据，只是数据是null   后面处理的时候转为字符串为报错
                etcCheckList.ForEach(t =>
                {
                    t.Modality = t.Modality ?? string.Empty;
                    t.SiteCode = t.SiteCode ?? string.Empty;
                    t.SubjectCode = t.SubjectCode ?? string.Empty;
                    t.VisitName = t.VisitName ?? string.Empty;
                    t.StudyDate = t.StudyDate ?? string.Empty;
                });

                var dt = DateTime.Now;

                etcCheckList = etcCheckList.Where(t => !(t.Modality == string.Empty && t.SiteCode == string.Empty && t.SubjectCode == string.Empty && t.VisitName == string.Empty && t.StudyDate == string.Empty && DateTime.TryParse(t.StudyDate, out dt))).ToList();

                if (etcCheckList.Count == 0)
                {
                    return ResponseOutput.NotOk("请上传规定格式的Excel文件，保证有有效数据！");
                }

            }

            await _mediator.Send(new ConsistencyVerificationRequest() { ETCList = etcCheckList, TrialId = trialId });

            return ResponseOutput.Ok();

        }

        #endregion


        #region QC 核对问题  操作检查各种操作

        /// <summary>
        /// 添加或者更新 QC核对问题列表   两个人不能同时操作，就算意外进去了，提交数据，也不会覆盖前一个人数据， 后台已经做好判断
        /// </summary>
        [HttpPost("{trialId:guid}/{subjectVisitId:guid}/{trialQCProcess:int}/{currentQCType:int}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> AddOrUpdateQCQuestionAnswerList(QCQuestionAnswerCommand[] qcQuestionAnswerCommands, Guid trialId, Guid subjectVisitId, [FromRoute] TrialQCProcess trialQCProcess, [FromRoute] CurrentQC currentQCType)
        {
            //验证是否能操作
            await VerifyIsCanQCAsync(null, subjectVisitId);

            //更新
            if (qcQuestionAnswerCommands.Any(t => t.Id != null))
            {

                #region 先删除再添加

                //await _repository.DeleteFromQueryAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.QCProcessEnum == trialQCProcess && t.CurrentQCEnum == currentQCType);

                //var addlist = _mapper.Map<List<TrialQCQuestionAnswer>>(qcQuestionAnswerCommands);

                //addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; });

                //await _repository.AddRangeAsync(addlist);

                #endregion

                #region 先查询再更新

                var questionAnswerList = await _repository.Where<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.QCProcessEnum == trialQCProcess && t.CurrentQCEnum == currentQCType, true).ToListAsync();

                qcQuestionAnswerCommands.ToList().ForEach(t =>
                {
                    var temp = questionAnswerList.FirstOrDefault(u => u.Id == t.Id);

                    if (temp != null)
                    {
                        temp.Answer = t.Answer;
                        //temp.ChildAnswer = t.ChildAnswer;
                    }

                });

                //Automapper 映射有问题   automapper 会把Guid? 类型的null 值转为 guid.Empty 导致映射错误
                //_mapper.Map(qcQuestionAnswerCommands, questionAnswerList);
                #endregion



                return ResponseOutput.Ok(await _repository.SaveChangesAsync());
            }
            else
            {
                var addlist = _mapper.Map<List<TrialQCQuestionAnswer>>(qcQuestionAnswerCommands);

                addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; });

                await _repository.AddRangeAsync(addlist);

                return ResponseOutput.Result(await _repository.SaveChangesAsync());
            }


        }


        /// <summary>
        ///  1、设置为不读片，2 设置为读片(取消 先前设置为不读片)  4 设置为删除(数据库记录软删除) 5 恢复为未删除
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <param name="studyId"></param>
        /// <param name="seriesId"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{studyId:guid}/{seriesId:guid}/{state:int}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> SetSeriesState(Guid subjectVisitId, Guid studyId, Guid seriesId, int state)
        {

            await VerifyIsCanQCAsync(null, subjectVisitId);


            var series = (await _repository.Where<DicomSeries>(t => t.Id == seriesId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();

         
            if (state == 1)
            {
                series.IsReading = false;
            }
            else if (state == 2)
            {
                series.IsReading = true;
            }
            else if (state == 4)
            {
                series.IsDeleted = true;

                var study = (await _repository.Where<DicomStudy>(t => t.Id == studyId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();

                var instanceIdList = await _repository.Where<DicomInstance>(t => t.SeriesId == seriesId).Select(t => t.Id).ToListAsync();

                //instanceIdList.ForEach(t =>
                //{
                //    var path = _dicomFileStoreHelper.GetInstanceFilePath(study, seriesId, t.ToString());

                //    if (System.IO.File.Exists(path))
                //    {
                //        File.Delete(path);
                //    }

                //});

                study.InstanceCount = study.InstanceCount - instanceIdList.Count;
                study.SeriesCount = study.SeriesCount - 1;

                study.IsDeleted = study.SeriesCount == 0;

            }
            else if (state == 5)
            {
                series.IsDeleted = false;

                var study = (await _repository.Where<DicomStudy>(t => t.Id == studyId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException();


                var instanceIdList = await _repository.Where<DicomInstance>(t => t.SeriesId == seriesId).Select(t => t.Id).ToListAsync();

                study.InstanceCount = study.InstanceCount + instanceIdList.Count;

                study.SeriesCount = study.SeriesCount + 1;

                study.IsDeleted = study.SeriesCount == 0;
            }

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


        /// <summary>
        ///type 1 :study 2: series 3:非dicom  QC修改检查部位和 拍片类型
        /// </summary>
        /// <param name="id"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="type"></param>
        /// <param name="modality"></param>
        /// <param name="bodyPart"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{id:guid}/{type:int}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> UpdateModality(Guid id, Guid subjectVisitId, int type, [FromQuery] string modality, [FromQuery] string bodyPart)
        {

            await VerifyIsCanQCAsync(null, subjectVisitId);

            var DicomSeriesdata = await _repository.GetQueryable<DicomSeries>().Where(x => x.StudyId == id).ToListAsync();
            var study = await _repository.FirstOrDefaultAsync<DicomStudy>(t => t.Id == id);
        
            DateTime time = DateTime.Now.AddMilliseconds(500);
            if (type == 1)
            {

                if (study == null) return Null404NotFound(study);

                study.BodyPartForEdit = bodyPart;
                study.Modalities = modality;
                await _repository.BatchUpdateAsync<DicomSeries>(t => t.StudyId == id, r => new DicomSeries() { BodyPartForEdit = bodyPart, Modality = modality });
            }
            else if (type == 2)
            {
                var series = await _repository.FirstOrDefaultAsync<DicomSeries>(t => t.Id == id);
                if (series == null) return Null404NotFound(series);
                series.BodyPartForEdit = bodyPart;

            }
            else if (type == 3)
            {

            }

            // 移动不进去
            //await _trialRepository.AddListInspectionRecordAsync(datas);
            await _repository.SaveChangesAsync();
            return ResponseOutput.Ok();
        }


        /// <summary>
        /// 验证是否质疑都关闭了 可以审核通过和不通过
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <returns></returns>
        [HttpGet("{trialId:guid}/{subjectVisitId:guid}")]
        public async Task<IResponseOutput> VerifyCanQCPassedOrFailed(Guid subjectVisitId)
        {
            await VerifyIsCanQCAsync(null, subjectVisitId);

            if (await _repository.AnyAsync<QCChallenge>(t => t.SubjectVisitId == subjectVisitId && t.IsClosed == false))
            {
                return ResponseOutput.NotOk("有质疑未关闭，不允许该操作");
            }
            return ResponseOutput.Ok();
        }




        /// <summary>
        /// 删除检查列表
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="trialId"></param>
        /// <returns></returns>SeriesCount
        [HttpDelete, Route("{trialId:guid}/{subjectVisitId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        [UnitOfWork]
        public async Task<IResponseOutput> DeleteStudyList(Guid[] ids, Guid subjectVisitId, Guid trialId)
        {


            //提交了 但是IQC同意的时候 是可以删除的
            if (await _subjectVisitRepository.AnyAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.Submitted &&
             (!t.QCChallengeList.Any(u => u.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload))))
            {
                return ResponseOutput.NotOk("CRC Has Submited Image，can not delete");
            }
            var waitDeleteStudyList = await _dicomStudyRepository.Where(x => ids.Contains(x.Id)).ToListAsync();

            foreach (var study in waitDeleteStudyList)
            {

                var id = study.Id;

                await _dicomStudyRepository.DeleteAsync(study, true);
                var succeess2 = await _repository.BatchDeleteAsync<DicomInstance>(t => t.StudyId == id);

                var DicomSeriess = await _repository.GetQueryable<DicomSeries>().Where(t => t.StudyId == id).Select(x => new
                {
                    x.StudyId,
                    x.SubjectId,
                    x.SiteId,
                    x.TrialId,
                    x.Id,
                    x.SubjectVisitId,
                    x.SeriesTime,
                    x.IsReading,
                    x.InstanceCount,
                    x.SeriesNumber,
                    StudyCode = x.DicomStudy.StudyCode,
                    Modalities = x.DicomStudy.Modalities,

                }).ToListAsync();



                var success3 = await _repository.BatchDeleteAsync<DicomSeries>(t => t.StudyId == id);
                var success4 = await _repository.BatchDeleteAsync<StudyMonitor>(t => t.StudyId == id);

                //删除 物理文件

                var instanceIdList = await _repository.Where<DicomInstance>(t => t.StudyId == id)
                    .Select(t => new { InstanceId = t.Id, t.SeriesId, t.StudyId, t.SubjectId, t.SiteId }).ToListAsync();

                instanceIdList.ForEach(t =>
                {
                    var path = _dicomFileStoreHelper.GetInstanceFilePath(new DicomStudy() { Id = t.StudyId, SubjectId = t.SubjectId, TrialId = trialId, SiteId = t.SiteId, SubjectVisitId = subjectVisitId }, t.SeriesId, t.InstanceId.ToString());

                    if (System.IO.File.Exists(path))
                    {
                        File.Delete(path);
                    }

                });
            }



            var subvisit = await _repository.GetQueryable<SubjectVisit>().FirstOrDefaultAsync(x => x.Id == subjectVisitId);

            return ResponseOutput.Ok();
        }

        #endregion


        private async Task VerifyIsCanQCAsync(SubjectVisit? subjectVisit, Guid? sujectVisitId = null)
        {
            if (sujectVisitId != null)
            {
                subjectVisit = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == sujectVisitId)).IfNullThrowException();
            }

            if (subjectVisit!.CurrentActionUserId != _userInfo.Id)
            {
                throw new BusinessValidationFailedException("您不是该质控任务当前领取人，没有操作权限!");
            }
        }

        #region  临床数据签名  领取、 设置紧急、RequestToQC QC通过、不通过


        /// <summary>替换当前领取人 </summary>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
        public async Task<IResponseOutput> ReplaceQCTaskActionUser(Guid trialId, Guid subjectVisitId)
        {
            var dbSubjectVisit = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();

            dbSubjectVisit.IsTake = true;

            dbSubjectVisit.CurrentActionUserId = _userInfo.Id;

            dbSubjectVisit.CurrentActionUserExpireTime = DateTime.Now.AddHours(1);

            var success = await _subjectVisitRepository.SaveChangesAsync();

            return ResponseOutput.Result(success);
        }


        /// <summary>
        /// 手动领取 或者取消 QC任务
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="obtaionOrCancel">true 获取  false是取消领取</param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{obtaionOrCancel:bool}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> ObtainOrCancelQCTask(Guid trialId, Guid subjectVisitId, bool obtaionOrCancel)
        {

            if (await _subjectVisitRepository.AnyAsync(t => t.CurrentActionUserId != null && t.IsTake && t.Id == subjectVisitId))
            {
                throw new BusinessValidationFailedException("当前访视已被领取，不允许领取");
            }

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


            var trialConfig = await _trialRepository
                .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
                .FirstOrDefaultAsync(t => t.TrialId == trialId)
                .IfNullThrowException();

            if (obtaionOrCancel)
            {

                if (await _subjectVisitRepository.AnyAsync(t => t.Trial.QCQuestionConfirmedUserId == null && t.Id == subjectVisitId))
                {
                    return ResponseOutput.NotOk("QC问题未确认，不允许领取任务");
                }


                //if (await _subjectVisitRepository.AnyAsync(t => t.IsTake &&
                //                                                t.SubjectId != dbSubjectVisit.SubjectId &&
                //                                                t.CurrentActionUserId == _userInfo.Id &&
                //                                                t.TrialId == dbSubjectVisit.TrialId
                //                                                ))
                //{


                //    return ResponseOutput.NotOk("您已经领取了其他受试者，完成后才允许领取新的受试者");
                //}

                #region 处理验证

                if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
                {
                    return ResponseOutput.NotOk("项目配置为不审，没有领取QC Task");
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
                {
                    if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.Id)
                    {
                        return ResponseOutput.NotOk("初审已通过，不能继续领取");
                    }

                    if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
                    }
                    if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
                    {
                        //单审QC 释放后 也是可以领取的
                    }
                    else
                    {
                        return ResponseOutput.NotOk("项目配置为单审,不满足SubmmitState：已提交 或者 AuditState：待审核/审核中, 不允许领取,请刷新界面");
                    }
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
                {
                    if (dbSubjectVisit.PreliminaryAuditUserId == _userInfo.Id)
                    {
                        return ResponseOutput.NotOk("复审不能和初审是同一个人");
                    }

                    //提交 并且初审通过  那么领取后进入 复审中
                    if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.PrimaryQCPassed)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.InSecondaryQC;

                    }
                    else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.InPrimaryQC;
                    }
                    else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC || dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC))
                    {
                        //初审中  复审中  领取也是ok的 其他人接着做
                    }
                    else
                    {
                        return ResponseOutput.NotOk("项目配置为复审，不满足提交状态：已提交 或者 审核状态：待审核/QC中, 不允许领取,请刷新界面");
                    }
                }

                #endregion

                dbSubjectVisit.IsTake = true;

                dbSubjectVisit.CurrentActionUserId = _userInfo.Id;

                dbSubjectVisit.CurrentActionUserExpireTime = DateTime.Now.AddHours(1);


                //启动定时任务 1h后处理
                //BackgroundJob.Schedule<IObtainTaskAutoCancelJob>(t => t.CancelQCObtaion(subjectVisitId, DateTime.Now), TimeSpan.FromHours(1));
            }
            else
            {

                if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
                {
                    return ResponseOutput.NotOk("项目配置为不审，没有取消QC Task");
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
                {

                    if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.ToAudit;
                    }

                    else
                    {
                        return ResponseOutput.NotOk("项目配置为单审,不满足SubmmitState：已提交 或者 AuditState：InPrimaryQC, 不允许释放");
                    }
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
                {

                    //提交 并且初审通过  那么领取后进入 复审中
                    if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.PrimaryQCPassed;

                    }
                    else if (dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted && dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.ToAudit;
                    }

                    else
                    {
                        return ResponseOutput.NotOk("项目配置为复审，不满足提交状态：已提交 或者 审核状态：InPrimaryQC/InSecondaryQC, 不允许释放");
                    }
                }

                dbSubjectVisit.IsTake = false;

                dbSubjectVisit.CurrentActionUserId = null;

                dbSubjectVisit.CurrentActionUserExpireTime = null;

            }
            var success = await _subjectVisitRepository.SaveChangesAsync();
            return ResponseOutput.Result(success);
        }



        [HttpPost]
        public async Task<IResponseOutput> VerifyCRCRequestToQC(CRCRequestToQCCommand cRCRequestToQCCommand)
        {
            var dbSubjectVisitList = await _subjectVisitRepository.Where(t => cRCRequestToQCCommand.SubjectVisitIds.Contains(t.Id), true).ToListAsync();

            //普通提交
            if (dbSubjectVisitList.Count() == 1)
            {
                var sv = dbSubjectVisitList[0];

                var nameList = await _subjectVisitRepository.Where(t => t.SubjectId == sv.SubjectId && t.SubmitState != SubmitStateEnum.Submitted && t.VisitNum < sv.VisitNum).Select(t => t.VisitName).ToListAsync() ?? new List<string>();

                if (sv.PDState == PDStateEnum.PDProgress)
                {

                    if (nameList.Count() > 0)
                    {
                        return ResponseOutput.NotOk($"系统检测发现该受试者存在当前访视之前的访视未提交，未提交访视有：{string.Join('、', nameList)}。疾病进展确认对阅片时限要求很高，请将上述访视提交或标记失访后，再提交当前访视！", 1, ApiResponseCodeEnum.NeedTips);
                    }
                }
                else
                {
                    if (nameList.Count() > 0)
                    {

                        return ResponseOutput.NotOk($"系统检测发现该受试者存在当前访视之前的访视未提交，未提交访视有：{string.Join('、', nameList)}。请在该访视提交后，尽快完成上述访视的影像上传和提交。", 0, ApiResponseCodeEnum.NeedTips);
                    }
                }
            }

            return ResponseOutput.Ok();


        }

        /// <summary>
        /// CRC RequestToQC  批量提交
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> CRCRequestToQC(CRCRequestToQCCommand cRCRequestToQCCommand)
        {
            var trialConfig = (await _trialRepository
                .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification, t.IsUrgent, t.IsHaveFirstGiveMedicineDate, t.ClinicalInformationTransmissionEnum })
                .FirstOrDefaultAsync(t => t.TrialId == cRCRequestToQCCommand.TrialId)).IfNullThrowException();


            var dbSubjectVisitList = await _subjectVisitRepository.Where(t => cRCRequestToQCCommand.SubjectVisitIds.Contains(t.Id), true).Include(t => t.Subject).ToListAsync();


            if (dbSubjectVisitList.Any(t => t.SubmitState == SubmitStateEnum.None))
            {
                return ResponseOutput.NotOk("有访视未上传任何Dicom/非Dicom数据 不允许提交");
            }

            foreach (var dbSubjectVisit in dbSubjectVisitList)
            {

                //基线不验证
                if (trialConfig.IsHaveFirstGiveMedicineDate && !dbSubjectVisit.IsBaseLine && dbSubjectVisit.Subject.FirstGiveMedicineTime == null)
                {
                    return ResponseOutput.NotOk("项目配置了需要填写首次给药日期 但是受试者没有填写首次给药日期，不允许提交");
                }

                //基线  且配置了临床数据  
                if (trialConfig.ClinicalInformationTransmissionEnum != 0 && dbSubjectVisit.IsBaseLine/*&&dbSubjectVisit.ClinicalDataSignUserId==null*/)
                {
                    //已确认临床数据完整性
                    dbSubjectVisit.IsConfirmedClinicalData = true;

                    //var signSuccess = await _repository.UpdateFromQueryAsync<TrialSign>(t => t.Id == cRCRequestToQCCommand.SignId, u => new TrialSign() { IsCompleted = true });


                    ////现在修改为  提交时 设置签名信息
                    //dbSubjectVisit.ClinicalDataSignUserId = _userInfo.Id;
                    //dbSubjectVisit.ClinicalDataSignTime = DateTime.Now;

                    //那么没有录入 不允许提交
                    //if (!await _repository.AnyAsync<SubjectVisit>(t => t.PreviousHistoryList.Any() || t.PreviousOtherList.Any() || t.PreviousSurgeryList.Any()))
                    //{
                    //    return ResponseOutput.NotOk("没有临床数据，不允许提交");
                    //}

                    //return ResponseOutput.NotOk("没有签名临床数据，不允许提交");
                }


                var maxVisit = await _subjectVisitRepository.Where(t => t.SubjectId == dbSubjectVisit.SubjectId && t.SubmitState == SubmitStateEnum.Submitted)
                    .OrderByDescending(t => t.VisitNum).Select(t => new { t.Id, t.VisitNum }).FirstOrDefaultAsync();

                //修改受试者最新访视   
                dbSubjectVisit.Subject.LatestSubjectVisitId = maxVisit == null ? dbSubjectVisit.Id : maxVisit.VisitNum < dbSubjectVisit.VisitNum ? dbSubjectVisit.Id : maxVisit.Id;

                //var maxVisitNum = maxVisit == null ? dbSubjectVisit.VisitNum : maxVisit.VisitNum < dbSubjectVisit.VisitNum ? dbSubjectVisit.VisitNum : maxVisit.VisitNum;

                ////判断是否有缺失影像
                //dbSubjectVisit.Subject.IsMissingImages = await _subjectVisitRepository.AnyAsync(t => (t.VisitNum < maxVisitNum && t.SubmitState != SubmitStateEnum.Submitted && t.IsLostVisit == false));

                //项目或者Subject IsUrgent 提交时 访视也设置为紧急
                if (trialConfig.IsUrgent || dbSubjectVisit.Subject.IsUrgent || (dbSubjectVisit.PDState == PDStateEnum.PDProgress && !dbSubjectVisit.IsBaseLine) || (dbSubjectVisit.IsEnrollmentConfirm && dbSubjectVisit.IsBaseLine))
                {
                    dbSubjectVisit.IsUrgent = true;
                }


                if (dbSubjectVisit.SubmitState == SubmitStateEnum.ToSubmit || dbSubjectVisit.SubmitState == SubmitStateEnum.Submitted)
                {
                    dbSubjectVisit.SubmitState = SubmitStateEnum.Submitted;
                    dbSubjectVisit.SubmitTime = DateTime.Now;

                }

                //不审 直接QC通过  可能一致性核查  也可能不一致性核查
                if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
                {
                    dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;

                    // 不一致性核查 就CVPassed ToForward  否则就是待核查
                    dbSubjectVisit.CheckState = trialConfig.IsImageConsistencyVerification ? CheckStateEnum.ToCheck : CheckStateEnum.CVPassed;

                    dbSubjectVisit.ForwardState = trialConfig.IsImageConsistencyVerification ? ForwardStateEnum.None : ForwardStateEnum.ToForward;

                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
                {
                    dbSubjectVisit.AuditState = AuditStateEnum.ToAudit;
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
                {
                    dbSubjectVisit.AuditState = AuditStateEnum.ToAudit;


                }


            }


            var success = await _repository.SaveChangesAsync();
            return ResponseOutput.Result(success);



        }

        /// <summary>
        /// 设置QC 通过或者不通过   7:QC failed  8：QC passed   [签名  不需要对]
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="auditState"></param>
        /// <returns></returns>
        [HttpPost("{trialId:guid}/{subjectVisitId:guid}/{auditState:int}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> QCPassedOrFailed(Guid trialId, Guid subjectVisitId, [FromRoute] AuditStateEnum auditState)
        {

            if (!await _repository.AnyAsync<TrialUser>(t => t.TrialId == trialId && t.UserId == _userInfo.Id))
            {
                return ResponseOutput.NotOk("您已经被移出项目，不允许该操作");
            }

            //判断质疑是否都关闭了
            if (await _repository.AnyAsync<QCChallenge>(t => t.SubjectVisitId == subjectVisitId && t.IsClosed == false))
            {
                return ResponseOutput.NotOk("有质疑未关闭，不允许该操作");
            }



            var trialConfig = await _trialRepository
                  .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
                  .FirstOrDefaultAsync(t => t.TrialId == trialId)
                  .IfNullThrowException();

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

            await VerifyIsCanQCAsync(dbSubjectVisit);

            //有人QC Passed
            if (auditState == AuditStateEnum.QCPassed)
            {
                //判断 QC流程  不审  单审  双审

                if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
                {
                    return ResponseOutput.NotOk("不审状态下，不允许设置为QC Passed");

                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
                {
                    if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
                    {
                        if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.First))
                        {
                            return ResponseOutput.NotOk("必须填写审核问题，并保存，否则不允许提交");
                        }

                        // 单审 
                        dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;
                        dbSubjectVisit.CheckState = trialConfig.IsImageConsistencyVerification ? CheckStateEnum.ToCheck : CheckStateEnum.CVPassed;
                        dbSubjectVisit.ForwardState = trialConfig.IsImageConsistencyVerification ? ForwardStateEnum.None : ForwardStateEnum.ToForward;
                        dbSubjectVisit.PreliminaryAuditUserId = _userInfo.Id;
                        dbSubjectVisit.PreliminaryAuditTime = DateTime.Now;

                    }
                    else
                    {
                        return ResponseOutput.NotOk("项目配置为单审 当前审核状态不为 InPrimaryQC，不能变更到 QCPassed");
                    }

                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
                {

                    // 双审  如果当前db 状态是 InPrimaryQC  当前操作为 QCPassed  那么设置为 PrimaryQCPassed
                    if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC)
                    {

                        if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.First))
                        {
                            return ResponseOutput.NotOk("必须填写审核问题，并保存，否则不允许提交");
                        }

                        dbSubjectVisit.AuditState = AuditStateEnum.PrimaryQCPassed;
                        dbSubjectVisit.PreliminaryAuditUserId = _userInfo.Id;
                        dbSubjectVisit.PreliminaryAuditTime = DateTime.Now;


                    }
                    else if (dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC)
                    {

                        if (!await _repository.AnyAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.Second))
                        {
                            return ResponseOutput.NotOk("必须填写审核问题，并保存，否则不允许提交");
                        }

                        dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;

                        dbSubjectVisit.CheckState = trialConfig.IsImageConsistencyVerification ? CheckStateEnum.ToCheck : CheckStateEnum.CVPassed;

                        dbSubjectVisit.ForwardState = trialConfig.IsImageConsistencyVerification ? ForwardStateEnum.None : ForwardStateEnum.ToForward;

                        dbSubjectVisit.ReviewAuditUserId = _userInfo.Id;

                        dbSubjectVisit.ReviewAuditTime = DateTime.Now;


                    }
                    else
                    {
                        return ResponseOutput.NotOk($"项目配置为双审 当前审核状态为 {dbSubjectVisit.AuditState}，不能变更到 QCPassed");
                    }
                }
            }

            else if (auditState == AuditStateEnum.QCFailed)
            {
                //判断 QC流程  不审  单审  双审

                if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
                {
                    return ResponseOutput.NotOk("不审状态下，不允许设置为QC Failed");
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit)
                {
                    // 单审 
                    if (dbSubjectVisit.AuditState == AuditStateEnum.ToAudit)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.QCFailed;

                    }
                    else
                    {
                        return ResponseOutput.NotOk("项目配置为单审 当前审核状态不为 ToAudit，不能变更到 QCFailed");
                    }
                }
                else if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit)
                {
                    // 双审 
                    if (dbSubjectVisit.AuditState == AuditStateEnum.InPrimaryQC || dbSubjectVisit.AuditState == AuditStateEnum.InSecondaryQC)
                    {
                        dbSubjectVisit.AuditState = AuditStateEnum.QCFailed;
                    }
                    else
                    {
                        return ResponseOutput.NotOk($"项目配置为双审 当前审核状态为 {dbSubjectVisit.AuditState}，不能变更到 QCFailed");
                    }


                }
            }

            dbSubjectVisit.IsTake = false;
            dbSubjectVisit.CurrentActionUserId = null;
            dbSubjectVisit.CurrentActionUserExpireTime = null;

            //删除 软删除的物理文件



            var instanceIdList = await _repository.Where<DicomInstance>(t => t.DicomSerie.IsDeleted && t.SubjectVisitId == subjectVisitId)
                .Select(t => new { InstanceId = t.Id, t.SeriesId, t.StudyId, t.SubjectId, t.SiteId }).ToListAsync();


            instanceIdList.ForEach(t =>
            {
                var path = _dicomFileStoreHelper.GetInstanceFilePath(new DicomStudy() { Id = t.StudyId, SubjectId = t.SubjectId, TrialId = trialId, SiteId = t.SiteId, SubjectVisitId = subjectVisitId }, t.SeriesId, t.InstanceId.ToString());

                if (System.IO.File.Exists(path))
                {
                    File.Delete(path);
                }

            });

            await _repository.SaveChangesAsync();

            //var success = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == signId, u => new TrialSign() { IsCompleted = true });

            return ResponseOutput.Result(true);


        }


        /// <summary>
        /// 设置、取消 访视紧急
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="setOrCancel"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{setOrCancel:bool}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> SetVisitUrgent(Guid trialId, Guid subjectVisitId, bool setOrCancel)
        {
            var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();

            sv.IsUrgent = setOrCancel;
            var success = await _repository.SaveChangesAsync();
            return ResponseOutput.Ok();
        }

        #endregion


        #region 重传、重传完设置

        /// <summary>验证质疑对话页面  是否可以 跳转到重传页面 进行重传  </summary>
        [HttpGet("{trialId:guid}/{qcChallengeId:guid}")]
        public async Task<IResponseOutput> VerifyReuploadIsCanJump(Guid trialId, Guid qcChallengeId)
        {
            var qcChallenge = (await _qcChallengeRepository.FirstOrDefaultAsync(t => t.Id == qcChallengeId)).IfNullThrowException();

            if (qcChallenge.ReuploadEnum != QCChanllengeReuploadEnum.QCAgreeUpload)
            {
                throw new BusinessValidationFailedException("当前重传状态不为QC同意重传，不允许重传");
            }
            return ResponseOutput.Ok();
        }


        /// <summary>
        /// QA设置  同意重传
        /// </summary>
        /// <param name="trialId"></param> 
        /// <param name="qcChallengeId"></param>
        /// <returns></returns>
        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> SetNeedReupload(Guid trialId, Guid qcChallengeId)
        {
            if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.IQC)
            {
                return ResponseOutput.NotOk("重传 只允许QA 设置!");
            }

            //获取项目配置
            var trialConfig = await _repository.Where<Trial>(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification })
                .FirstOrDefaultAsync().IfNullThrowException();

            if (trialConfig.QCProcessEnum == TrialQCProcess.NotAudit)
            {
                return ResponseOutput.NotOk("不审操作，不会有需要重传的操作!");
            }

            var qcChallenge = (await _qcChallengeRepository.FirstOrDefaultAsync(t => t.Id == qcChallengeId)).IfNullThrowException();

            if (qcChallenge.ReuploadEnum != QCChanllengeReuploadEnum.CRCRequestReupload)
            {
                throw new BusinessValidationFailedException("当前重传状态不为CRC申请重传，不允许设置同意重传");
            }


            if (await _qcChallengeRepository.CountAsync(t => t.ReuploadEnum == QCChanllengeReuploadEnum.QCAgreeUpload && t.SubjectVisitId == qcChallenge.SubjectVisitId && t.IsClosed == false) >= 1)
            {
                return ResponseOutput.NotOk("当前访视,有一个未关闭的质疑 QC设置了同意重传，CRC还未完成上传，当前不允许再次设置");
            }



            qcChallenge.ReuploadEnum = QCChanllengeReuploadEnum.QCAgreeUpload;
            qcChallenge.LatestMsgTime = DateTime.Now;
            qcChallenge.LatestReplyUserId = _userInfo.Id;

            await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == qcChallenge.SubjectVisitId, c => new SubjectVisit() { IsQCConfirmedReupload = true });

            qcChallenge.DialogList.Add(new QCChallengeDialog()
            {
                SubjectVisitId = qcChallenge.SubjectVisitId,
                UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
                QCChallengeId = qcChallenge.Id,
                TalkContent = "QC同意重传"
            });

            //双审 并且是2QC 那么需要回退到1QC  讲1QC数据清除
            if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit && await _repository.AnyAsync<QCChallenge>(t => t.Id == qcChallengeId && t.SubjectVisit.AuditState == AuditStateEnum.InSecondaryQC))
            {

                var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == qcChallenge.SubjectVisitId);

                if (sv == null) return Null404NotFound(sv);

                // //一致性核查质疑状态
                // sv.CheckChallengeState = CheckChanllengeTypeEnum.None;
                //// 一致性核查状态
                // sv.CheckState = CheckStateEnum.None;
                // 审核状态
                sv.AuditState = AuditStateEnum.InPrimaryQC;

                sv.CurrentActionUserExpireTime = DateTime.Now.AddHours(1);
                sv.CurrentActionUserId = _userInfo.Id;
                BackgroundJob.Schedule<IObtainTaskAutoCancelJob>(t => t.CancelQCObtaion(qcChallenge.SubjectVisitId, DateTime.Now), TimeSpan.FromHours(1));
                sv.IsTake = true;

                sv.PreliminaryAuditUserId = null;
                sv.ReviewAuditUserId = null;


                //删除1QC    填写的问题答案

                await _repository.BatchDeleteAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == qcChallenge.SubjectVisitId && t.CurrentQCEnum == CurrentQC.First);

                //2QC 数据变为1QC
                await _repository.BatchUpdateAsync<QCChallenge>(t => t.SubjectVisitId == qcChallenge.SubjectVisitId && t.CurrentQCEnum == CurrentQC.Second, k => new QCChallenge() { CurrentQCEnum = CurrentQC.First });
                await _repository.BatchUpdateAsync<TrialQCQuestionAnswer>(t => t.SubjectVisitId == qcChallenge.SubjectVisitId && t.CurrentQCEnum == CurrentQC.Second, k => new TrialQCQuestionAnswer() { CurrentQCEnum = CurrentQC.First });

            }


            var success = await _repository.SaveChangesAsync();


            return ResponseOutput.Result(success);

        }

        /// <summary>
        /// CRC  设置已经重传完成
        /// </summary>

        /// <returns></returns>
        [HttpPost]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> SetReuploadFinished(CRCReuploadFinishedCommand cRCReuploadFinishedCommand)
        {
            if (_userInfo.UserTypeEnumInt != (int)UserTypeEnum.ClinicalResearchCoordinator)
            {
                throw new BusinessValidationFailedException("重传完成 只允许CRC 设置!");
            }


            var qcChallenge = (await _qcChallengeRepository.FirstOrDefaultAsync(t => t.Id == cRCReuploadFinishedCommand.QCChallengeId)).IfNullThrowException();

            if (qcChallenge.ReuploadEnum != QCChanllengeReuploadEnum.QCAgreeUpload)
            {
                throw new BusinessValidationFailedException("当前重传状态不为QC同意重传，不允许设置重传完成");
            }


            var subjectVisitId = qcChallenge.SubjectVisitId;

            if (await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).SelectMany(t => t.StudyList).CountAsync() == 0 &&
                await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).SelectMany(t => t.NoneDicomStudyList).SelectMany(u => u.NoneDicomFileList).CountAsync() == 0)
            {
                throw new BusinessValidationFailedException("当前没有影像，不允许设置重传完成");
            }

            var trialConfig = await _trialRepository
           .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification, t.IsUrgent, t.IsHaveFirstGiveMedicineDate, t.ClinicalInformationTransmissionEnum })
           .Where(t => t.TrialId == cRCReuploadFinishedCommand.TrialId).FirstOrDefaultAsync();



            qcChallenge.ReuploadEnum = QCChanllengeReuploadEnum.CRCReuploaded;

            qcChallenge.ReUploadedTime = DateTime.Now;

            qcChallenge.ReUploadUserId = _userInfo.Id;

            qcChallenge.ReUploader = _userInfo.RealName;

            qcChallenge.LatestMsgTime = DateTime.Now;

            qcChallenge.LatestReplyUserId = _userInfo.Id;

            var dbSubjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == qcChallenge.SubjectVisitId).IfNullThrowException();


            await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == qcChallenge.SubjectVisitId, c => new SubjectVisit() { IsQCConfirmedReupload = false });

            qcChallenge.DialogList.Add(new QCChallengeDialog()
            {
                SubjectVisitId = qcChallenge.SubjectVisitId,

                UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,

                QCChallengeId = qcChallenge.Id,

                TalkContent = "CRC已重传完成"
            });


            //基线  且配置了临床数据  
            if (trialConfig.ClinicalInformationTransmissionEnum != 0 && dbSubjectVisit.IsBaseLine)
            {
                //已确认临床数据完整性
                dbSubjectVisit.IsConfirmedClinicalData = true;

                //var signSuccess = await _repository.BatchUpdateAsync<TrialSign>(t => t.Id == cRCReuploadFinishedCommand.SignId, u => new TrialSign() { IsCompleted = true });
            }

            var success = await _subjectVisitRepository.SaveChangesAsync();


            return ResponseOutput.Result(success);

        }



        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{qcChallengeId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> CRCRequestReUpload(Guid qcChallengeId)
        {
            var qcChallenge = (await _qcChallengeRepository.FirstOrDefaultAsync(t => t.Id == qcChallengeId)).IfNullThrowException();


            if (qcChallenge.ReuploadEnum != QCChanllengeReuploadEnum.None && qcChallenge.ReuploadEnum != QCChanllengeReuploadEnum.CRCReuploaded)
            {
                throw new BusinessValidationFailedException("当前质疑重传状态不为初始状态|CRC重传完成状态，不允许申请重传");
            }


            if (qcChallenge.ReuploadEnum == QCChanllengeReuploadEnum.CRCReuploaded)
            {
                qcChallenge.ReUploadedTime = null;
            }

            qcChallenge.LatestMsgTime = DateTime.Now;
            qcChallenge.LatestReplyUserId = _userInfo.Id;
            qcChallenge.ReuploadEnum = QCChanllengeReuploadEnum.CRCRequestReupload;

            qcChallenge.DialogList.Add(new QCChallengeDialog()
            {
                SubjectVisitId = qcChallenge.SubjectVisitId,
                UserTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt,
                QCChallengeId = qcChallenge.Id,
                TalkContent = "CRC申请重传/上传影像"
            });

            var isSuccess = await _qcChallengeRepository.SaveChangesAsync();

            return ResponseOutput.Result(isSuccess);
        }

        #endregion



        /// <summary>
        /// 上传界面 更新受试者首次给药日期  是否入组确认，以及访视 是否PD进展
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>

        [HttpPut("{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> UpdateSubjectAndSVInfo(UploadSubjectAndVisitCommand command)
        {
            var dbSubjectVisit = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == command.SubjectVisitId)).IfNullThrowException();

            dbSubjectVisit.PDState = command.PDState;

            if (command.IsEnrollmentConfirm != null)
            {
                if (await _subjectVisitRepository.Where(t => t.Id == command.SubjectVisitId)
               .AnyAsync(t => t.SubmitState == SubmitStateEnum.Submitted && t.IsEnrollmentConfirm != command.IsEnrollmentConfirm))
                {
                    return ResponseOutput.NotOk("CRC已提交了 不能修改入组确认状态");
                }

                if (await _subjectVisitRepository.Where(t => t.Id == command.SubjectVisitId)
               .AnyAsync(t => t.IsEnrollmentConfirm != command.IsEnrollmentConfirm && t.RequestBackState == RequestBackStateEnum.PM_AgressBack))
                {
                    return ResponseOutput.NotOk("回退的访视，不允许修改PD确认状态");
                }

                dbSubjectVisit.IsEnrollmentConfirm = command.IsEnrollmentConfirm.Value;
            }

            if (command.SubjectFirstGiveMedicineTime != null)
            {
                await _subjectRepository.UpdatePartialFromQueryAsync(command.SubjectId, u => new Subject() { FirstGiveMedicineTime = command.SubjectFirstGiveMedicineTime, });
            }

            await _subjectVisitRepository.SaveChangesAsync();

            return ResponseOutput.Ok();
        }







        [HttpPost("{trialId:guid}")]
        public async Task<IResponseOutput> ForwardSVDicomImage(Guid[] subjectVisitIdList)
        {

            bool isSuccess = false;
           

            foreach (var subjectVisitId in subjectVisitIdList)
            {


                var info = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).ProjectTo<DicomTrialSiteSubjectInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
              
              
                var targetPath = "/IMPORT-IMAGES/" + info.TrialCode + "_" + info.SubjectCode + "_" + info.VisitName;

                var path = _dicomFileStoreHelper.GetSubjectVisitPath(info.TrialId, info.SiteId, info.SubjectId, info.SubjectVisitId);

                try
                {
                    // 主机及端口信息后面可以改到 配置文件
                    SessionOptions sessionOptions = new SessionOptions
                    {
                        Protocol = Protocol.Sftp,
                        PortNumber = 8022,
                        HostName = "CS-690-sftp.mint-imaging.com",
                        UserName = "zdong",
                        Password = "Everest@2021",
                        SshHostKeyFingerprint = @"ecdsa-sha2-nistp384 384 59gkjJ5lMwv3jsB8Wz2B35tBAIor5pSd8PcJYtoamPo="
                    };

                    using (Session session = new Session())
                    {
                        var studyFolders = (new DirectoryInfo(path)).GetDirectories();

                        session.Open(sessionOptions);

                        if (!session.FileExists(targetPath))
                        {
                            session.CreateDirectory(targetPath);
                        }

                        foreach (var studyFolder in studyFolders)
                        {
                            var targetFolder = Path.Combine(targetPath, studyFolder.Name);

                            if (!session.FileExists(targetFolder))
                            {
                                session.CreateDirectory(targetFolder);
                            }

                            foreach (var file in studyFolder.GetFiles())
                            {
                                if (file.Extension.Contains("dcm", StringComparison.OrdinalIgnoreCase))
                                {
                                    string remoteFilePath =
                                        RemotePath.TranslateLocalPathToRemote(file.FullName, studyFolder.FullName, targetFolder);

                                    var result = session.PutFiles(file.FullName, remoteFilePath, false);

                                    if (!result.IsSuccess)
                                    {
                                        await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId,
                                              u => new SubjectVisit() { ForwardState = ForwardStateEnum.ForwardFailed });

                                        return ResponseOutput.NotOk("Forward Failed" + result.Failures.ToString() + result.ToJson());
                                    }
                                }
                            }
                        }

                    }
                    await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId,
                        u => new SubjectVisit() { ForwardState = ForwardStateEnum.Forwarded, ForwardUserId = _userInfo.Id, ForwardTime = DateTime.Now });

                    isSuccess = true;
                  
                }
                catch (Exception e)
                {

                    await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId,
                          u => new SubjectVisit() { ForwardState = ForwardStateEnum.ForwardFailed });
                  

                    return ResponseOutput.NotOk("转发失败 " + e.Message);
                }


            }

        

            await _subjectVisitRepository.SaveChangesAsync();

            return isSuccess ? ResponseOutput.Ok() : ResponseOutput.NotOk("转发失败");
        }




    }
}
