using AutoMapper;
using DocumentFormat.OpenXml.Drawing;
using EasyCaching.Core;
using ExcelDataReader;
using IRaCIS.Application.Contracts;
using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Application.Auth;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.Dicom;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.MediatR.CommandAndQueries;
using IRaCIS.Core.Application.MediatR.Handlers;
using IRaCIS.Core.Application.Service;
using IRaCIS.Core.Application.Service.ImageAndDoc;
using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using Magicodes.ExporterAndImporter.Excel;
using MassTransit;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using MiniExcelLibs;
using Newtonsoft.Json;
using SharpCompress.Archives;
using SharpCompress.Common;
using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Path = System.IO.Path;

namespace IRaCIS.Core.API.Controllers
{

    #region 上传基类封装
    [DisableFormValueModelBinding]
    public abstract class UploadBaseController : ControllerBase
    {
        /// <summary>  流式上传  直接返回</summary>
        [Route("base")]
        public virtual async Task<IResponseOutput> SingleFileUploadAsync(Func<string, (string, string)> filePathFunc)
        {
            var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;

            var reader = new MultipartReader(boundary, HttpContext.Request.Body);

            var section = await reader.ReadNextSectionAsync();

            while (section != null)
            {
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);

                if (hasContentDispositionHeader)
                {

                    var (serverFilePath, relativePath) = filePathFunc(contentDisposition.FileName.Value);

                    await FileStoreHelper.WriteFileAsync(section.Body, serverFilePath);

                    //仅仅返回一个文件，如果多文件上传  在最后返回多个路径
                    return ResponseOutput.Ok(new
                    {
                        FilePath = relativePath,
                        FullFilePath = relativePath /*+ "?access_token=" + _userInfo.UserToken*/
                    });

                }
                section = await reader.ReadNextSectionAsync();
            }
            return ResponseOutput.Ok();
        }


        /// <summary>  流式上传   通用封装 不返回任何数据，后续还有事情处理 </summary>
        [Route("base")]
        public virtual async Task FileUploadAsync(Func<string, Task<string>> filePathFunc)
        {
            var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;

            var reader = new MultipartReader(boundary, HttpContext.Request.Body);

            var section = await reader.ReadNextSectionAsync();

            while (section != null)
            {
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
                if (hasContentDispositionHeader)
                {
                    var fileName = contentDisposition.FileName.Value;
                    //处理压缩文件
                    if (fileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || fileName.Contains(".rar", StringComparison.OrdinalIgnoreCase))
                    {
                        var archive = ArchiveFactory.Open(section.Body);

                        foreach (var entry in archive.Entries)
                        {
                            if (!entry.IsDirectory)
                            {
                                var serverFilePath = await filePathFunc(entry.Key);
                                entry.WriteToFile(serverFilePath);

                            }
                        }
                    }
                    //普通单个文件
                    else
                    {
                        var serverFilePath = await filePathFunc(fileName);

                        await FileStoreHelper.WriteFileAsync(section.Body, serverFilePath);
                    }

                }
                section = await reader.ReadNextSectionAsync();
            }
        }



        /// <summary>  流式上传   Dicom上传  </summary>
        [Route("base")]
        public virtual async Task DicomFileUploadAsync(Func<string, Stream, int, Task> filePathFunc, string boundary)
        {

            var fileCount = 0;

            var reader = new MultipartReader(boundary, HttpContext.Request.Body);

            var section = await reader.ReadNextSectionAsync();

            while (section != null)
            {
                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);

                if (hasContentDispositionHeader)
                {

                    var fileName = contentDisposition.FileName.Value ?? String.Empty;

                    string mediaType = section.ContentType ?? String.Empty;


                    //处理压缩文件
                    if (fileName.Contains(".Zip", StringComparison.OrdinalIgnoreCase) || fileName.Contains(".rar", StringComparison.OrdinalIgnoreCase))
                    {
                        var archive = ArchiveFactory.Open(section.Body);

                        foreach (var entry in archive.Entries)
                        {
                            if (!entry.IsDirectory)
                            {
                                ++fileCount;

                                await filePathFunc(entry.Key, entry.OpenEntryStream(), fileCount);
                            }
                        }
                    }
                    //普通单个文件
                    else
                    {
                        if (mediaType.Contains("octet-stream") || mediaType.Contains("dicom"))
                        {
                            ++fileCount;

                            await filePathFunc(fileName, section.Body, fileCount);
                        }

                    }
                }
                section = await reader.ReadNextSectionAsync();
            }



        }


    }

    #endregion

    #region Dicom 影像上传  临床数据  非diocm 

    [ApiExplorerSettings(GroupName = "Image")]
    [ApiController]
    public class StudyController : UploadBaseController
    {
        public IMapper _mapper { get; set; }
        public IUserInfo _userInfo { get; set; }
        private readonly IMediator _mediator;

        private readonly IWebHostEnvironment _hostEnvironment;

        private readonly IRepository _repository;

        private readonly IEasyCachingProvider _provider;
        private readonly QCCommon _qCCommon;
        public StudyController(IMapper mapper, IUserInfo userInfo, IWebHostEnvironment hostEnvironment, IMediator mediator, IEasyCachingProvider provider,
             QCCommon qCCommon,
            IRepository repository)
        {
            _qCCommon = qCCommon;
            _provider = provider;
            _hostEnvironment = hostEnvironment;
            _mediator = mediator;

            _mapper = mapper;
            _userInfo = userInfo;
            _repository = repository;
        }

        [HttpPost, Route("Study/PreArchiveStudy")]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> PreArchiveStudy(PreArchiveStudyCommand preArchiveStudyCommand,
             [FromServices] IStudyService _studyService,
             [FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
        {

            if (_provider.Get<List<SystemAnonymization>>(StaticData.Anonymize.Anonymize_AddFixedFiled).Value == null)
            {
                await _mediator.Send(new AnonymizeCacheRequest());
            }

            var savedInfo = _studyService.GetSaveToDicomInfo(preArchiveStudyCommand.SubjectVisitId);

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

                IsSuccess = false,
                UploadStartTime = DateTime.Now,
                IsDicom = preArchiveStudyCommand.IsDicom,
                IP = _userInfo.IP
            };


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

            return ResponseOutput.Ok(addEntity.Id);

        }


        /// <summary>Dicom 归档</summary>
        [HttpPost, Route("Study/ArchiveStudy")]
        [DisableFormValueModelBinding]
        [DisableRequestSizeLimit]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> ArchiveStudyNew(/*[FromForm] ArchiveStudyCommand archiveStudyCommand,*/ Guid trialId, Guid subjectVisitId, string studyInstanceUid, Guid? abandonStudyId, Guid studyMonitorId,
             [FromServices] ILogger<UploadDownLoadController> _logger,
             [FromServices] IEasyCachingProvider _provider,
             [FromServices] IStudyService _studyService,
             [FromServices] IHubContext<UploadHub, IUploadClient> _uploadHub,
             [FromServices] IDicomArchiveService _dicomArchiveService,
             [FromServices] IRepository<StudyMonitor> _studyMonitorRepository
            )
        {






            if (!HttpContext.Request.HasFormContentType ||
                !MediaTypeHeaderValue.TryParse(HttpContext.Request.ContentType, out var mediaTypeHeader) ||
                string.IsNullOrEmpty(mediaTypeHeader.Boundary.Value))
            {
                //---不支持的MediaType
                return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_UnsupportedMedia"));
            }

            var archiveStudyCommand = new ArchiveStudyCommand() { AbandonStudyId = abandonStudyId, StudyInstanceUid = studyInstanceUid, SubjectVisitId = subjectVisitId };

            string studycode = string.Empty;

            var startTime = DateTime.Now;


            if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}") && _provider.Get<Guid>($"StudyUid_{trialId}_{studyInstanceUid}").Value == _userInfo.Id)
            {
                _provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
            }



            //if (_provider.Exists($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}"))
            //{
            //    //---当前已有人正在上传和归档该检查!
            //    return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_ArchiveInProgress"));
            //}
            //else
            //{
            //    _provider.Set($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}", _userInfo.Id, TimeSpan.FromMinutes(30));
            //}

            //到了接口，代表上传结束了

            var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);

            studyMonitor.UploadFinishedTime = DateTime.Now;


            var (archiveResult, archivedStudyIds) = (new DicomArchiveResult(), new List<Guid>());


            var (seriesInstanceUidList, sopInstanceUidList) = (new List<string>(), new List<string>());

            //重传的时候，找出当前检查已经上传的series instance
            if (archiveStudyCommand.AbandonStudyId != null)
            {
                (seriesInstanceUidList, sopInstanceUidList) = _studyService.GetHasUploadSeriesAndInstance(archiveStudyCommand.AbandonStudyId.Value);
            }

            var savedInfo = _studyService.GetSaveToDicomInfo(archiveStudyCommand.SubjectVisitId);

            try
            {

                await DicomFileUploadAsync(async (fileName, fileStream, receivedCount) =>
                {

                    try
                    {
                        using (var memoryStream = new MemoryStream())
                        {
                            await fileStream.CopyToAsync(memoryStream);

                            memoryStream.Seek(0, SeekOrigin.Begin);

                            var (studyId, studyCode) = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, sopInstanceUidList);
                            if (!archivedStudyIds.Contains(studyId))
                            {
                                archivedStudyIds.Add(studyId);
                                archiveResult.ArchivedDicomStudies.Add(new DicomStudyBasicDTO() { StudyCode = studyCode, Id = studyId });
                            }
                        }

                        //await _uploadHub.Clients.All.ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);


                        await _uploadHub.Clients.User(_userInfo.Id.ToString()).ReceivProgressAsync(archiveStudyCommand.StudyInstanceUid, receivedCount);

                        archiveResult.ReceivedFileCount = receivedCount;

                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e.Message + e.StackTrace);

                        archiveResult.ErrorFiles.Add(fileName);
                    }


                }, mediaTypeHeader.Boundary.Value);


            }
            catch (Exception ex)
            {
                _provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");

                //---请求异常,请重试！
                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_RequestError"));
            }

            studyMonitor.FileSize = (decimal)HttpContext.Request.ContentLength;
            studyMonitor.FileCount = archiveResult.ReceivedFileCount;
            studyMonitor.FailedFileCount = archiveResult.ErrorFiles.Count;
            studyMonitor.IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null;
            studyMonitor.Note = JsonConvert.SerializeObject(archiveResult);


            try
            {

                if (archivedStudyIds.Count > 0) // 上传成功，处理逻辑
                {

                    // 同一个访视 多个线程上传处理  批量保存 可能造成死锁 https://www.cnblogs.com/johnblogs/p/9945767.html

                    await _dicomArchiveService.DicomDBDataSaveChange();

                    archiveResult.ReuploadNewStudyId = archivedStudyIds[0] == archiveStudyCommand.AbandonStudyId ? archivedStudyIds[0] : Guid.Empty;

                    studyMonitor.IsSuccess = true;

                }

            }
            catch (Exception e)
            {

                studyMonitor.Note = JsonConvert.SerializeObject(new { Message = e.Message, Result = archiveResult });
                _logger.LogError(e.Message + e.StackTrace);

            }
            finally
            {
                _provider.Remove($"StudyUid_{trialId}_{archiveStudyCommand.StudyInstanceUid}");

                studyMonitor.StudyId = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.Id ?? Guid.Empty;
                studyMonitor.StudyCode = archiveResult.ArchivedDicomStudies.FirstOrDefault()?.StudyCode;
                studyMonitor.ArchiveFinishedTime = DateTime.Now;

                await _studyMonitorRepository.SaveChangesAsync();
            }



            return ResponseOutput.Result(studyMonitor.IsSuccess, archiveResult);



        }




        #region 废弃



        ///// <summary>
        ///// 上传临床数据  多文件
        ///// </summary>
        ///// <param name="subjectVisitId"></param>
        ///// <returns></returns>
        //[HttpPost("ClinicalData/UploadVisitClinicalData/{trialId:guid}/{subjectVisitId:guid}")]
        //[DisableRequestSizeLimit]
        ////[Authorize(Policy = IRaCISPolicy.CRC)]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]

        //public async Task<IResponseOutput> UploadVisitClinicalData(Guid subjectVisitId)
        //{
        //    await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);
        //    var sv = _repository.Where<SubjectVisit>(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SiteId, t.SubjectId }).FirstOrDefault().IfNullThrowException();

        //    await FileUploadAsync(async (fileName) =>
        //    {
        //        var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetClinicalDataPath(_hostEnvironment, fileName, sv.TrialId, sv.SiteId, sv.SubjectId, subjectVisitId);
        //        //插入临床pdf 路径
        //        await _repository.AddAsync(new PreviousPDF()
        //        {
        //            SubjectVisitId = subjectVisitId,

        //            IsVisist = true,
        //            DataType = ClinicalDataType.MedicalHistory,
        //            UploadType = ClinicalUploadType.PDF,
        //            SubjectId = sv.SubjectId,
        //            TrialId = sv.TrialId,
        //            ClinicalLevel = ClinicalLevel.Subject,
        //            Path = relativePath,
        //            FileName = fileRealName
        //        });
        //        return serverFilePath;
        //    });
        //    await _repository.SaveChangesAsync();
        //    return ResponseOutput.Ok();

        //}

        ///// <summary>
        ///// 上传临床数据模板
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <returns></returns>
        //[HttpPost("ClinicalData/UploadClinicalTemplate")]
        //[DisableRequestSizeLimit]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })]


        //public async Task<IResponseOutput<List<FileDto>>> UploadClinicalTemplate(Guid? trialId)
        //{
        //    if (trialId == null)
        //        trialId = default(Guid);

        //    var filerelativePath = string.Empty;
        //    List<FileDto> fileDtos = new List<FileDto>();
        //    await FileUploadAsync(async (fileName) =>
        //    {
        //        var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetClinicalTemplatePath(_hostEnvironment, fileName, trialId.Value);
        //        //插入临床pdf 路径
        //        filerelativePath = relativePath;

        //        fileDtos.Add(new FileDto()
        //        {
        //            FileName = fileName,
        //            Path = relativePath

        //        });
        //        await Task.CompletedTask;
        //        return serverFilePath;
        //    });

        //    return ResponseOutput.Ok(fileDtos);
        //}



        ///// <summary>
        ///// 上传阅片临床数据
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <param name="subjectId"></param>
        ///// <param name="readingId"></param>
        ///// <returns></returns>
        //[HttpPost("ClinicalData/UploadClinicalData/{trialId:guid}/{subjectId:guid}/{readingId:guid}")]
        //[DisableRequestSizeLimit]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]

        //public async Task<IResponseOutput<List<FileDto>>> UploadReadClinicalData(Guid trialId, Guid subjectId, Guid readingId)
        //{
        //    var filerelativePath = string.Empty;
        //    List<FileDto> fileDtos = new List<FileDto>();

        //    var siteid = await _repository.Where<Subject>(x => x.Id == subjectId).Select(x => x.SiteId).FirstOrDefaultAsync();

        //    await FileUploadAsync(async (fileName) =>
        //     {
        //         var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetReadClinicalDataPath(_hostEnvironment, fileName, trialId, siteid, subjectId, readingId);
        //         //插入临床pdf 路径
        //         filerelativePath = relativePath;

        //         fileDtos.Add(new FileDto()
        //         {
        //             FileName = fileName,
        //             Path = relativePath

        //         });
        //         await Task.CompletedTask;
        //         return serverFilePath;
        //     });

        //    return ResponseOutput.Ok(fileDtos);

        //}


        ///// <summary>
        ///// 上传截图
        ///// </summary>
        ///// <param name="subjectId"></param>
        ///// <returns></returns>
        //[HttpPost("Printscreen/UploadPrintscreen/{subjectId:guid}")]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //public async Task<IResponseOutput<FileDto>> UploadPrintscreen(Guid subjectId)
        //{

        //    var subjectInfo = await this._repository.Where<Subject>(x => x.Id == subjectId).FirstNotNullAsync();

        //    FileDto fileDto = new FileDto();
        //    await FileUploadAsync(async (fileName) =>
        //    {
        //        var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetUploadPrintscreenFilePath(_hostEnvironment, fileName, subjectInfo.TrialId, subjectInfo.SiteId, subjectInfo.Id);
        //        fileDto.Path = relativePath;
        //        fileDto.FileName = fileName;
        //        await Task.CompletedTask;
        //        return serverFilePath;
        //    });


        //    return ResponseOutput.Ok(fileDto);
        //}


        ///// <summary>
        ///// 上传Reading问题的图像
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <param name="visitTaskId"></param>
        ///// <returns></returns>
        //[HttpPost("VisitTask/UploadReadingAnswerImage/{trialId:guid}/{visitTaskId:guid}")]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //public async Task<IResponseOutput<FileDto>> UploadReadingAnswerImage(Guid trialId, Guid visitTaskId)
        //{

        //    FileDto fileDto = new FileDto();
        //    await FileUploadAsync(async (fileName) =>
        //    {
        //        var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetFilePath(_hostEnvironment, fileName, trialId, visitTaskId, StaticData.Folder.JudgeTask);
        //        fileDto.Path = relativePath;
        //        fileDto.FileName = fileName;
        //        await Task.CompletedTask;
        //        return serverFilePath;
        //    });


        //    return ResponseOutput.Ok(fileDto);
        //}

        ///// <summary>
        ///// 上传裁判任务的图像
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <param name="visitTaskId"></param>
        ///// <returns></returns>
        //[HttpPost("VisitTask/UploadJudgeTaskImage/{trialId:guid}/{visitTaskId:guid}")]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //public async Task<IResponseOutput<FileDto>> UploadJudgeTaskImage(Guid trialId, Guid visitTaskId)
        //{

        //    FileDto fileDto = new FileDto();
        //    await FileUploadAsync(async (fileName) =>
        //    {
        //        var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetFilePath(_hostEnvironment, fileName, trialId, visitTaskId, StaticData.Folder.JudgeTask);
        //        fileDto.Path = relativePath;
        //        fileDto.FileName = fileName;

        //        await Task.CompletedTask;

        //        return serverFilePath;
        //    });

        //    return ResponseOutput.Ok(fileDto);
        //}



        ///// <summary>
        ///// 上传医学审核图片
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <param name="taskMedicalReviewId"></param>
        ///// <returns></returns>
        //[HttpPost("TaskMedicalReview/UploadMedicalReviewImage/{trialId:guid}/{taskMedicalReviewId:guid}")]
        //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //public async Task<IResponseOutput<FileDto>> UploadMedicalReviewImage(Guid trialId, Guid taskMedicalReviewId)
        //{
        //    string path = string.Empty;
        //    FileDto fileDto = new FileDto();
        //    await FileUploadAsync(async (fileName) =>
        //    {

        //        var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetMedicalReviewImage(_hostEnvironment, fileName, trialId, taskMedicalReviewId);


        //        //await _repository.UpdatePartialFromQueryAsync<TaskMedicalReview>(x => x.Id == taskMedicalReviewId, x => new TaskMedicalReview()
        //        //{
        //        //    ImagePath = relativePath,
        //        //    FileName = fileName,
        //        //});

        //        path = relativePath;
        //        fileDto.Path = relativePath;
        //        fileDto.FileName = fileName;
        //        return serverFilePath;
        //    });

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





        #endregion

        public class UploadNoneDicomFileCommand
        {
            public Guid TrialId { get; set; }
            public Guid SubjectVisitId { get; set; }
            public Guid NoneDicomStudyId { get; set; }
            public Guid StudyMonitorId { get; set; }


            public List<OSSFileDTO> UploadedFileList { get; set; } = new List<OSSFileDTO>();


            public class OSSFileDTO
            {
                public string FilePath { get; set; }
                public string FileName { get; set; }
                public int FileFize { get; set; }
            }
        }

        /// <summary>
        /// 上传非Dicom 文件 支持压缩包 多文件上传
        /// </summary>
        /// <param name="_noneDicomStudyRepository"></param>
        /// <returns></returns>
        //[DisableRequestSizeLimit]
        [HttpPost("NoneDicomStudy/UploadNoneDicomFile")]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.CRC)]
        public async Task<IResponseOutput> UploadNoneDicomFile(UploadNoneDicomFileCommand incommand,
            [FromServices] IRepository<NoneDicomStudy> _noneDicomStudyRepository, [FromServices] IRepository<StudyMonitor> _studyMonitorRepository)
        {

            var subjectVisitId = incommand.SubjectVisitId;
            var studyMonitorId = incommand.StudyMonitorId;
            var noneDicomStudyId = incommand.NoneDicomStudyId;


            await _qCCommon.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);

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

            var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == studyMonitorId);

            studyMonitor.UploadFinishedTime = DateTime.Now;

            foreach (var item in incommand.UploadedFileList)
            {
                await _repository.AddAsync(new NoneDicomStudyFile() { FileName = item.FileName, Path = item.FilePath, NoneDicomStudyId = noneDicomStudyId });

            }
            var uploadFinishedTime = DateTime.Now;

            var noneDicomStudy = await _noneDicomStudyRepository.FirstOrDefaultAsync((t => t.Id == noneDicomStudyId));

            noneDicomStudy.FileCount = noneDicomStudy.FileCount + incommand.UploadedFileList.Count;

            studyMonitor.FileCount = incommand.UploadedFileList.Count;
            studyMonitor.FileSize = incommand.UploadedFileList.Sum(t => t.FileFize);
            studyMonitor.IsDicom = false;
            studyMonitor.IsDicomReUpload = false;
            studyMonitor.StudyId = noneDicomStudyId;
            studyMonitor.StudyCode = noneDicomStudy.StudyCode;
            studyMonitor.ArchiveFinishedTime = DateTime.Now;
            studyMonitor.IP = _userInfo.IP;

            await _repository.SaveChangesAsync();

            return ResponseOutput.Ok();
        }

        /// <summary>
        /// 一致性核查 excel上传 支持三种格式
        /// </summary>
        /// <param name="trialId"></param>
        /// <returns></returns>
        [HttpPost("QCOperation/UploadVisitCheckExcel/{trialId:guid}")]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM)]
        public async Task<IResponseOutput> UploadVisitCheckExcel(Guid trialId)
        {

            var (serverFilePath, relativePath, fileName) = (string.Empty, string.Empty, string.Empty);
            await FileUploadAsync(async (realFileName) =>
            {
                fileName = realFileName;

                if (!fileName.EndsWith(".xlsx") && !fileName.EndsWith(".csv") && !fileName.EndsWith(".xls"))
                {
                    //---支持.xlsx、.xls、.csv格式的文件上传。
                    throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_SupportedFormats"));
                }

                (serverFilePath, relativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, fileName, trialId);

                await _repository.AddAsync(new UserUploadFile()
                {
                    TrialId = trialId,
                    CreateTime = DateTime.Now,
                    FileName = fileName,
                    FilePath = relativePath,
                    RelativePath = relativePath,
                    CreateUserId = _userInfo.Id
                });

                return serverFilePath;
            });




            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>(System.IO.File.OpenRead(serverFilePath));

                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>(serverFilePath, null, configuration: new MiniExcelLibs.Csv.CsvConfiguration()
                {
                    StreamReaderFunc = (stream) => new StreamReader(stream, Encoding.GetEncoding("gb2312"))
                }).ToList();

                var (csVToXlsxPath, csVToXlsxRelativePath) = FileStoreHelper.GetTrialCheckFilePath(_hostEnvironment, Path.GetFileNameWithoutExtension(fileName) + ".xlsx", trialId);


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


                var Importer = new ExcelImporter();

                var import = await Importer.Import<CheckViewModel>(System.IO.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(serverFilePath, 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
                    }
                }
            }

            if (etcCheckList == null || etcCheckList.Count == 0)
            {
                //---请保证上传数据符合模板文件中的样式，且存在有效数据。
                return ResponseOutput.NotOk(StaticData.International("UploadDownLoad_InvalidData"));
            }
            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(StaticData.International("UploadDownLoad_InvalidData"));
                }

            }


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

            return ResponseOutput.Ok();

        }

    }


    #endregion



    #region 项目 系统  基本文件 上传  下载 预览

    [ApiExplorerSettings(GroupName = "Common")]
    [ApiController]
    public class UploadDownLoadController : UploadBaseController
    {
        public IMapper _mapper { get; set; }
        public IUserInfo _userInfo { get; set; }
        private readonly IMediator _mediator;

        private readonly IWebHostEnvironment _hostEnvironment;



        public UploadDownLoadController(IMapper mapper, IUserInfo userInfo, IMediator mediator, IWebHostEnvironment hostEnvironment)
        {
            _hostEnvironment = hostEnvironment;
            _mediator = mediator;
            _mapper = mapper;
            _userInfo = userInfo;
        }

        [HttpPost, Route("TrialSiteSurvey/TestOOS")]
        public string TestUploadFileToOOS(string path)
        {
            return FileStoreHelper.UploadOOS(path, "testc/test", true);
        }

        [HttpPost, Route("TrialSiteSurvey/UploadTrialSiteSurveyUser")]
        [DisableFormValueModelBinding]
        [UnitOfWork]
        public async Task<IResponseOutput> UploadTrialSiteSurveyUser(Guid trialId, string baseUrl, string routeUrl,
            [FromServices] IRepository<TrialSite> _trialSiteRepository,
             [FromServices] IRepository<UserType> _usertypeRepository,
             [FromServices] ITrialSiteSurveyService _trialSiteSurveyService)
        {
            var (serverFilePath, relativePath, fileName) = (string.Empty, string.Empty, string.Empty);
            await FileUploadAsync(async (realFileName) =>
            {
                fileName = realFileName;

                if (!fileName.EndsWith(".xlsx", StringComparison.OrdinalIgnoreCase))
                {
                    //	 请用提供格式的模板excel上传需要处理的数据
                    throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_TemplateUploadData"));
                }

                (serverFilePath, relativePath) = FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName);

                //FileStoreHelper.UploadOOS(serverFilePath, "testc/test", true);

                return serverFilePath;
            });

            //去掉空白行
            var excelList = MiniExcel.Query<SiteSurveyUserImportDto>(serverFilePath).ToList()
                .Where(t => !(string.IsNullOrWhiteSpace(t.TrialSiteCode) && string.IsNullOrWhiteSpace(t.FirstName) && string.IsNullOrWhiteSpace(t.LastName) && string.IsNullOrWhiteSpace(t.Email)
                && string.IsNullOrWhiteSpace(t.Phone) && string.IsNullOrWhiteSpace(t.UserTypeStr) && string.IsNullOrWhiteSpace(t.OrganizationName))).ToList();

            if (excelList.Any(t => string.IsNullOrWhiteSpace(t.TrialSiteCode) || string.IsNullOrWhiteSpace(t.FirstName) || string.IsNullOrWhiteSpace(t.LastName) || string.IsNullOrWhiteSpace(t.Email) || string.IsNullOrWhiteSpace(t.UserTypeStr)))
            {
                //请确保Excel中 每一行的 中心编号，姓名，邮箱，用户类型数据记录完整再进行上传
                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_EnsureCompleteData"));
            }

            var siteCodeList = excelList.Select(t => t.TrialSiteCode.Trim().ToUpper()).Distinct().ToList();

            if (_trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode.ToUpper())).Count() != siteCodeList.Count)
            {
                //在项目中未找到该Excel中部分或全部中心
                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidCenters"));
            }

            if (excelList.GroupBy(t => new {t.TrialSiteCode, t.UserTypeStr, t.Email }).Any(g => g.Count() > 1))
            {
                //	同一邮箱，同一用户类型，只能生成一个账户,请核查Excel数据

                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_CheckDuplicateAccounts"));
            }

            if (excelList.Any(t => !t.Email.Contains("@")))
            {
                //有邮箱不符合邮箱格式,请核查Excel数据
                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidEmail"));
            }
            var generateUserTypeList = new List<string>() { "CRC", "SR", "CRA" };

            if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
            {
                //用户类型仅能为 CRC,SR,CRA 请核查Excel数据
                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_InvalidUserType"));
            }
            if (excelList.Count == 0)
            {
                throw new BusinessValidationFailedException(StaticData.International("UploadDownLoad_NoValiddata"));
            }
            //处理好 用户类型  和用户类型枚举
            var sysUserTypeList = _usertypeRepository.Where(t => t.UserTypeEnum == UserTypeEnum.CRA || t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator || t.UserTypeEnum == UserTypeEnum.SR).Select(t => new { UserTypeId = t.Id, t.UserTypeEnum }).ToList();
            var siteList = _trialSiteRepository.Where(t => t.TrialId == trialId && siteCodeList.Contains(t.TrialSiteCode)).Select(t => new { t.TrialSiteCode, t.SiteId }).ToList();

            foreach (var item in excelList)
            {
                switch (item.UserTypeStr.ToUpper())
                {
                    case "CRC":

                        item.UserTypeId = sysUserTypeList.FirstOrDefault(t => t.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).UserTypeId;
                        item.UserTypeEnum = UserTypeEnum.ClinicalResearchCoordinator;
                        break;

                    case "CRA":
                        item.UserTypeId = sysUserTypeList.FirstOrDefault(t => t.UserTypeEnum == UserTypeEnum.CRA).UserTypeId;
                        item.UserTypeEnum = UserTypeEnum.CRA;
                        break;

                    case "SR":
                        item.UserTypeId = sysUserTypeList.FirstOrDefault(t => t.UserTypeEnum == UserTypeEnum.SR).UserTypeId;
                        item.UserTypeEnum = UserTypeEnum.SR;
                        break;

                }

                item.SiteId = siteList.FirstOrDefault(t => t.TrialSiteCode.ToUpper() == item.TrialSiteCode.ToUpper()).SiteId;
            }



            await _trialSiteSurveyService.ImportGenerateAccountAndJoinTrialAsync(trialId, baseUrl, routeUrl, excelList.ToList());

            return ResponseOutput.Ok();


        }


        #region 废弃

        ///// <summary>  缩略图 </summary>
        //[AllowAnonymous]
        //[HttpGet("Common/LocalFilePreview")]
        //public async Task<FileContentResult> LocalFilePreview(string relativePath)
        //{

        //    var _fileStorePath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, relativePath);

        //    var storePreviewPath = _fileStorePath + ".preview.jpeg";

        //    if (!System.IO.File.Exists(storePreviewPath))
        //    {
        //        ImageHelper.ResizeSave(_fileStorePath, storePreviewPath);
        //    }

        //    return new FileContentResult(await System.IO.File.ReadAllBytesAsync(storePreviewPath), "image/jpeg");

        //}


        ///// <summary>  通用文件下载 </summary>
        //[AllowAnonymous]
        //[HttpGet("CommonDocument/DownloadCommonDoc")]
        //public async Task<IActionResult> DownloadCommonFile(string code, [FromServices] IRepository<CommonDocument> _commonDocumentRepository)
        //{
        //    var (filePath, fileName) = await FileStoreHelper.GetCommonDocPhysicalFilePathAsync(_hostEnvironment, _commonDocumentRepository, code);

        //    new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filePath), out var contentType);

        //    return File(System.IO.File.OpenRead(filePath), contentType ?? "application/octet-stream", fileName);

        //}

        ///// <summary>
        ///// 下载项目临床数据文件
        ///// </summary>
        ///// <param name="clinicalDataTrialSetId"></param>
        ///// <param name="_clinicalDataTrialSetRepository"></param>
        ///// <returns></returns>
        //[AllowAnonymous]
        //[HttpGet("CommonDocument/DownloadTrialClinicalFile")]
        //public async Task<IActionResult> DownloadTrialClinicalFile(Guid clinicalDataTrialSetId, [FromServices] IRepository<ClinicalDataTrialSet> _clinicalDataTrialSetRepository)
        //{
        //    var (filePath, fileName) = await FileStoreHelper.GetTrialClinicalPathAsync(_hostEnvironment, _clinicalDataTrialSetRepository, clinicalDataTrialSetId);

        //    new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filePath), out var contentType);

        //    return File(System.IO.File.OpenRead(filePath), contentType ?? "application/octet-stream", fileName);

        //}


        ///// <summary>
        ///// 下载系统临床数据文件
        ///// </summary>
        ///// <param name="clinicalDataSystemSetId"></param>
        ///// <param name="_clinicalDataSystemSetRepository"></param>
        ///// <returns></returns>
        //[AllowAnonymous]
        //[HttpGet("CommonDocument/DownloadSystemClinicalFile")]
        //public async Task<IActionResult> DownloadSystemClinicalFile(Guid clinicalDataSystemSetId, [FromServices] IRepository<ClinicalDataSystemSet> _clinicalDataSystemSetRepository)
        //{
        //    var (filePath, fileName) = await FileStoreHelper.GetSystemClinicalPathAsync(_hostEnvironment, _clinicalDataSystemSetRepository, clinicalDataSystemSetId);

        //    new FileExtensionContentTypeProvider().Mappings.TryGetValue(Path.GetExtension(filePath), out var contentType);

        //    return File(System.IO.File.OpenRead(filePath), contentType ?? "application/octet-stream", fileName);

        //}

        ///// <summary>
        /////上传项目签名文档
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <returns></returns>
        //[HttpPost("TrialDocument/UploadTrialDoc/{trialId:guid}")]
        //[DisableRequestSizeLimit]
        //[DisableFormValueModelBinding]
        //public async Task<IResponseOutput> UploadTrialDoc(Guid trialId)
        //{

        //    return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetTrialSignDocPath(_hostEnvironment, trialId, fileName));

        //}

        ///// <summary>
        ///// 上传系统签名文档
        ///// </summary>
        ///// <returns></returns>
        //[HttpPost("TrialDocument/UploadSystemDoc")]
        //[DisableRequestSizeLimit]
        //[DisableFormValueModelBinding]
        //public async Task<IResponseOutput> UploadSysTemDoc()
        //{

        //    return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemSignDocPath(_hostEnvironment, fileName));

        //}
        ///// <summary>
        ///// 上传系统通知文档
        ///// </summary>
        ///// <returns></returns>
        //[HttpPost("SystemNotice/UploadSystemNoticeDoc")]
        //[DisableRequestSizeLimit]
        //[DisableFormValueModelBinding]
        //public async Task<IResponseOutput> UploadSystemNoticeDoc()
        //{

        //    return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemNoticePath(_hostEnvironment, fileName));

        //}
        #endregion



        /// <summary>
        /// 上传通用文档  比如一致性核查的 比如导出的excel 模板
        /// </summary>
        /// <returns></returns>
        [HttpPost("CommonDocument/UploadCommonDoc")]
        [DisableRequestSizeLimit]
        [DisableFormValueModelBinding]
        public async Task<IResponseOutput> UploadCommonDoc()
        {
            return await SingleFileUploadAsync((fileName) => FileStoreHelper.GetCommonDocPath(_hostEnvironment, fileName));
        }




        public enum UploadFileType
        {
            DataUpload = 1,

            DataDownload = 2,

            EmailAttachment = 3,

            EmailBodyHtml = 4,

            Other = 5
        }

        /// <summary>
        /// 1：数据上传  2：导出、 3：邮件附件  4：邮件Html     通过 ----new
        /// </summary>
        /// <returns></returns>
        [HttpPost("SystemFile/Upload")]
        [DisableRequestSizeLimit]
        [DisableFormValueModelBinding]
        public async Task<IResponseOutput> Upload(UploadFileType fileType)
        {
            IResponseOutput result = null;

            switch (fileType)
            {
                case UploadFileType.DataUpload:
                    result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));

                    break;
                case UploadFileType.DataDownload:
                    result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName));

                    break;
                case UploadFileType.EmailAttachment:
                    result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));

                    break;

                case UploadFileType.EmailBodyHtml:
                    result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName));
                    break;

                default:
                    result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName));

                    break;
            }

            return result;

        }



    }
    #endregion

}
