//--------------------------------------------------------------------
//     此代码由T4模板自动生成  byzhouhang 20210918
//	   生成时间 2021-12-06 10:54:55 
//     对此文件的更改可能会导致不正确的行为，并且如果重新生成代码，这些更改将会丢失。
//--------------------------------------------------------------------
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using IRaCIS.Core.Domain.Share;
using SharpCompress.Archives;
using IRaCIS.Core.Application.Filter;
using Newtonsoft.Json;
using IRaCIS.Core.Application.Service.Inspection.Interface;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using Nito.AsyncEx;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Infrastructure;

namespace IRaCIS.Core.Application.Contracts
{
    /// <summary>
    /// NoneDicomStudyService
    /// </summary>	
    [ApiExplorerSettings(GroupName = "Image")]
    public class NoneDicomStudyService : BaseService, INoneDicomStudyService
    {
        private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository;
        private readonly IHttpContextAccessor _httpContext;
        private readonly IDictionaryService _dictionaryService;
        private readonly IInspectionService _inspectionService;
        private readonly IRepository<StudyMonitor> _studyMonitorRepository;
        private readonly IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository;
        private readonly IRepository<SubjectVisit> _subjectVisitRepository;
        private readonly AsyncLock _mutex = new AsyncLock();


        public NoneDicomStudyService(IRepository<NoneDicomStudy> noneDicomStudyRepository,
            IHttpContextAccessor httpContext,
            IDictionaryService dictionaryService,
            IInspectionService inspectionService,
            IRepository<StudyMonitor> studyMonitorRepository,
            IRepository<NoneDicomStudyFile> noneDicomStudyFileRepository,IRepository<SubjectVisit> subjectVisitRepository)
        {
            _noneDicomStudyRepository = noneDicomStudyRepository;
           
            this._httpContext = httpContext;
            this._dictionaryService = dictionaryService;
            this._inspectionService = inspectionService;
            this._studyMonitorRepository = studyMonitorRepository;
            _noneDicomStudyFileRepository = noneDicomStudyFileRepository;
            this._subjectVisitRepository = subjectVisitRepository;
        }


        private void VerifyIsCanQC(SubjectVisit? subjectVisit, Guid? sujectVisitId = null)
        {
            if (sujectVisitId != null)
            {
                subjectVisit = _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == sujectVisitId).Result.IfNullThrowException();
            }

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

        [HttpGet("{subjectVisitId:guid}")]
        public async Task<List<NoneDicomStudyView>> GetNoneDicomStudyList(Guid subjectVisitId)
        {

            var noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.SubjectVisitId == subjectVisitId)
                .ProjectTo<NoneDicomStudyView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken });

            return await noneDicomStudyQueryable.ToListAsync();
        }


        [UnitOfWork]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput<NoneDicomStudyAddReturnDto>> AddOrUpdateNoneDicomStudy(NoneDicomStudyAddOrEdit addOrEditNoneDicomStudy)
        {

            NoneDicomStudy? optEntity = null;
            using (await _mutex.LockAsync())
            {
                if (addOrEditNoneDicomStudy.Id == Guid.Empty || addOrEditNoneDicomStudy.Id == null)
                {
                    //默认会是0  
                    var code = await _noneDicomStudyRepository.Where(t => t.TrialId == addOrEditNoneDicomStudy.TrialId).Select(x => x.Code).DefaultIfEmpty().MaxAsync();

                    addOrEditNoneDicomStudy.Code = code + 1;

                    optEntity = await _noneDicomStudyRepository.InsertFromDTOAsync(addOrEditNoneDicomStudy);

                    optEntity.StudyCode = "NST" + optEntity.Code.ToString("D5");
                }
                else
                {

                    if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IQC)
                    {
                        VerifyIsCanQC(null, addOrEditNoneDicomStudy.SubjectVisitId);
                    }

                    optEntity = await _noneDicomStudyRepository.UpdateFromDTOAsync(addOrEditNoneDicomStudy);
                }

                await _noneDicomStudyRepository.SaveChangesAsync();
            }


            NoneDicomStudyAddReturnDto noneDicom = new NoneDicomStudyAddReturnDto()
            {
                StudyCode = optEntity.StudyCode,
                Id = optEntity.Id
            };
            return ResponseOutput.Ok(noneDicom);

        }

        [TypeFilter(typeof(TrialResourceFilter))]
        [HttpDelete("{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyId:guid}")]
        public async Task<IResponseOutput> DeleteNoneDicomStudy(Guid noneDicomStudyId)
        {


            await _noneDicomStudyRepository.DeleteFromQueryAsync( noneDicomStudyId);

            await _noneDicomStudyFileRepository.DeleteFromQueryAsync(t => t.NoneDicomStudyId == noneDicomStudyId);

            //确认需求 不删除
            //await _studyMonitorRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == noneDicomStudyId);

            await _noneDicomStudyRepository.SaveChangesAsync();

            return ResponseOutput.Ok();
        }


        [HttpDelete("{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyFileId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> DeleteNoneDicomStudyFile(Guid noneDicomStudyFileId)
        {
            //var subjectVisitId = await _noneDicomStudyFileRepository.Where(t => t.Id == noneDicomStudyFileId).Select(t => t.NoneDicomStudy.SubjectVisitId).FirstOrDefaultAsync();

            var success = await _noneDicomStudyFileRepository.DeleteFromQueryAsync(t => t.Id == noneDicomStudyFileId,true);

            return ResponseOutput.Ok();
        }

        /// <summary>
        /// 非Dicom检查 文件列表
        /// </summary>
        /// <param name="noneDicomStudyId"></param>
        /// <returns></returns>
        [HttpGet("{noneDicomStudyId:guid}")]
        public async Task<List<NoneDicomStudyFileView>> GetNoneDicomStudyFileList(Guid noneDicomStudyId)
        {
            return await _noneDicomStudyFileRepository.Where(t => t.NoneDicomStudyId == noneDicomStudyId)
                .ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken }).ToListAsync();
        }

        [HttpGet("{subjectVisitId:guid}")]
        public async Task<List<NoneDicomStudyFileView>> GetVisitNoneDicomStudyFileList(Guid subjectVisitId)
        {
            return await _repository.Where<NoneDicomStudyFile>(t => t.NoneDicomStudy.SubjectVisitId == subjectVisitId).ProjectTo<NoneDicomStudyFileView>(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken }).ToListAsync();
        }



        /// <summary>
        /// 上传非Dicom 文件 支持压缩包
        /// </summary>
        /// <param name="formCollection"></param>
        /// <param name="subjectVisitId"></param>
        /// <param name="noneDicomStudyId"></param>
        /// <returns></returns>
        //[DisableRequestSizeLimit]
        [RequestSizeLimit(1_073_741_824)]
        [HttpPost("{trialId:guid}/{subjectVisitId:guid}/{noneDicomStudyId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> UploadNoneDicomFile(IFormCollection formCollection, Guid subjectVisitId, Guid noneDicomStudyId)
        {
            var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;

            //上传根路径
            var _fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);

            var sv = await _repository.Where<SubjectVisit>(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefaultAsync().IfNullThrowConvertException();

            string uploadFolderPath = Path.Combine(_fileStorePath, sv.TrialId.ToString(), sv.SiteId.ToString(), sv.SubjectId.ToString(), subjectVisitId.ToString(), StaticData.NoneDicomFolder);

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

            var startTime = DateTime.Now;

            foreach (IFormFile file in formCollection.Files)
            {
                if (file.FileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || file.FileName.Contains(".rar", StringComparison.OrdinalIgnoreCase))
                {
                    var archive = ArchiveFactory.Open(file.OpenReadStream());

                    foreach (var entry in archive.Entries)
                    {
                        if (!entry.IsDirectory)
                        {
                            DealCompressFile(entry, sv, subjectVisitId, noneDicomStudyId, uploadFolderPath);
                        }
                    }
                }
                else
                {
                    var trustedFileNameForFileStorage = GetStoreFileName(file.FileName);
                    var relativePath = $"/{StaticData.TrialDataFolder}/{sv.TrialId}/{sv.SiteId}/{sv.SubjectId}/{subjectVisitId}/{StaticData.NoneDicomFolder}/{trustedFileNameForFileStorage}";

                    var filePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);

                    using (FileStream fs = System.IO.File.Create(filePath))
                    {
                        await file.CopyToAsync(fs);
                        await fs.FlushAsync();
                    }

                    await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = file.FileName, Path = relativePath, NoneDicomStudyId = noneDicomStudyId });

                }
            }

            // 上传非Dicom 后  将状态改为待提交 分为普通上传 和QC后重传  普通上传时才改为待提交
            await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId && t.SubmitState == SubmitStateEnum.None, u => new SubjectVisit() { SubmitState = SubmitStateEnum.ToSubmit });

            var studyCode= await  _noneDicomStudyRepository.Where(t=>t.Id== noneDicomStudyId).Select(t => t.StudyCode).FirstOrDefaultAsync();

            await _studyMonitorRepository.AddAsync(new StudyMonitor()
            {
                FileCount = formCollection.Files.Count,
                FileSize = formCollection.Files.Sum(t => t.Length),
                IsDicom = false,
                IsDicomReUpload = false,
                StudyId = noneDicomStudyId,
                StudyCode= studyCode,
                UploadStartTime = startTime,
                UploadFinishedTime = DateTime.Now,
                IP = _userInfo.IP,
                TrialId = sv.TrialId,
                SiteId = sv.SiteId,
                SubjectId = sv.SubjectId,
                SubjectVisitId = subjectVisitId,
            });

            await _noneDicomStudyFileRepository.SaveChangesAsync();

            return ResponseOutput.Ok(/*list*/);
        }

        private string GetStoreFileName(string fileName)
        {
            var realName = fileName;

            var fileNameEX = Path.GetExtension(realName);

            var trustedFileNameForFileStorage = Guid.NewGuid().ToString() + fileNameEX;

            return trustedFileNameForFileStorage;
        }

        private async void DealCompressFile(IArchiveEntry entry, dynamic sv, Guid subjectVisitId, Guid noneDicomStudyId, string uploadFolderPath)
        {
            var trustedFileNameForFileStorage = GetStoreFileName(entry.Key);

            var relativePath = $"/{StaticData.TrialDataFolder}/{sv.TrialId}/{sv.SiteId}/{sv.SubjectId}/{subjectVisitId}/{StaticData.NoneDicomFolder}/{trustedFileNameForFileStorage}";

            var filePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage);

            entry.WriteToFile(filePath);

            var fileName = string.Empty;

            if (entry.Key.Contains("\\"))
            {
                fileName = entry.Key.Split("\\").Last();
            }


            await _noneDicomStudyFileRepository.AddAsync(new NoneDicomStudyFile() { FileName = fileName, Path = relativePath, NoneDicomStudyId = noneDicomStudyId });
        }



        /// <summary>
        /// 上传非Dicom 文件 支持压缩包
        /// </summary>
        [HttpPost]
        [Obsolete]
        public async Task<IResponseOutput> NewUploadNoneDicomFile([FromForm] UploadNoneDicomFileDto fileDto)
        {
            var file = this._httpContext.HttpContext?.Request.Form;
            var result = await UploadNoneDicomFile(file, fileDto.subjectVisitId, fileDto.noneDicomStudyId);
            if (result.IsSuccess)
            {
                var data = JsonConvert.DeserializeObject<DataInspectionAddDTO>(fileDto.AuditInfo);
                data.GeneralId = fileDto.noneDicomStudyId;
                await _inspectionService.AddInspectionRecordAsync(data);
            }

            return result;
        }

    }
}
