using IRaCIS.Application.Interfaces;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using Microsoft.Net.Http.Headers;
using Microsoft.AspNetCore.WebUtilities;
using System.Threading.Tasks;
using IRaCIS.Core.Application.Contracts.Dicom;
using System.IO;
using System.IO.Compression;
using IRaCIS.Core.Application.Dicom;
using Microsoft.Extensions.Logging;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Infrastructure.Extention;
using EasyCaching.Core;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Application.Service.Inspection.Interface;
using Newtonsoft.Json;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Domain.Common;

namespace IRaCIS.Api.Controllers
{
    /// <summary>
    /// Study
    /// </summary>
    [Route("study")]
    [ApiController, Authorize, ApiExplorerSettings(GroupName = "Image")]
    public class StudyController : ControllerBase
    {
        private readonly IStudyService _studyService;
        private readonly IDicomArchiveService _dicomArchiveService;
        private readonly ILogger<StudyController> _logger;
        private readonly IDictionaryService _dictionaryService;
        private readonly IInspectionService _inspectionService;
        private IEasyCachingProvider _provider;
        private IUserInfo _userInfo;
        private static object _locker = new object();


        public StudyController(IStudyService studyService,
            IDicomArchiveService dicomArchiveService,
            ILogger<StudyController> logger,
                IDictionaryService dictionaryService,
              IInspectionService inspectionService,
            IEasyCachingProvider provider, IUserInfo userInfo
            )
        {
            _userInfo = userInfo;
            _provider = provider;
            _studyService = studyService;
            _dicomArchiveService = dicomArchiveService;
            _logger = logger;
            this._dictionaryService = dictionaryService;
            this._inspectionService = inspectionService;
        }






        /// <summary> 归档</summary>
        [HttpPost, Route("archiveStudy/{trialId:guid}")]
        [DisableFormValueModelBinding]
        [DisableRequestSizeLimit]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> ArchiveStudy([FromForm] ArchiveStudyCommand archiveStudyCommand)
        {

            string studycode = string.Empty;
            var startTime = DateTime.Now;

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

            var archiveResult = new DicomArchiveResult();
            var archivedStudyIds = new List<Guid>();
            var seriesInstanceUidList = new List<string>();
            var instanceUidList = new List<string>();

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

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


            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)
            {
                //采用post方式  这里多加一个判断   过滤其他参数   
                if (string.IsNullOrEmpty(section.ContentType))
                {
                    section = await reader.ReadNextSectionAsync();
                    continue;
                }

                var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
                if (hasContentDispositionHeader)
                {
                    string fileName = contentDisposition.FileName.Value;
                    try
                    {

                        string mediaType = section.ContentType;

                        if (mediaType.Contains("zip"))
                        {
                            var partStream = section.Body;
                            using (var zipArchive = new ZipArchive(partStream, ZipArchiveMode.Read))
                            {
                                foreach (var entry in zipArchive.Entries)
                                {
                                    if (entry.FullName.EndsWith("/")) continue;
                                    try
                                    {
                                        ++archiveResult.ReceivedFileCount;
                                        using (var memoryStream = new MemoryStream())
                                        {
                                            await section.Body.CopyToAsync(memoryStream);

                                            memoryStream.Seek(0, SeekOrigin.Begin);

                                            var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, instanceUidList);
                                            studycode = archiveStudyId.Item2;
                                            if (!archivedStudyIds.Contains(archiveStudyId.Item1))
                                                archivedStudyIds.Add(archiveStudyId.Item1);
                                        }
                                    }
                                    catch
                                    {
                                        archiveResult.ErrorFiles.Add($"{fileName}/{entry.FullName}");
                                    }
                                }
                            }
                        }

                        ++archiveResult.ReceivedFileCount;


                        if (mediaType.Contains("octet-stream"))
                        {
                            using (var memoryStream = new MemoryStream())
                            {
                                await section.Body.CopyToAsync(memoryStream);

                                memoryStream.Seek(0, SeekOrigin.Begin);

                                var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, instanceUidList);
                                studycode = archiveStudyId.Item2;


                                if (!archivedStudyIds.Contains(archiveStudyId.Item1))
                                    archivedStudyIds.Add(archiveStudyId.Item1);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        _logger.LogError(e.Message + e.StackTrace);

                        archiveResult.ErrorFiles.Add(fileName);

                        _provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);

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

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


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

                    await _dicomArchiveService.DicomDBDataSaveChange();

                    //sw.Stop();
                    _studyService.UploadOrReUploadNeedTodo(archiveStudyCommand, archivedStudyIds, ref archiveResult, new StudyMonitor()
                    {
                        TrialId = savedInfo.TrialId,
                        SiteId = savedInfo.SiteId,
                        SubjectId = savedInfo.SubjectId,
                        SubjectVisitId = savedInfo.SubjectVisitId,
                        StudyId = archivedStudyIds[0],

                        StudyCode= studycode,
                        UploadStartTime = startTime,
                        UploadFinishedTime = DateTime.Now,
                        //TotalMillisecondsInterval = (DateTime.Now- startTime).TotalMilliseconds,
                        FileSize = (decimal)HttpContext.Request.ContentLength,
                        FileCount = archiveResult.ReceivedFileCount,
                        IsDicom = true,
                        IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null,
                        IP = _userInfo.IP
                    });

                    _provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);

                }
                else
                {
                    return ResponseOutput.NotOk("未完成该检查的归档");
                }


            }
            catch (Exception e)
            {

                _logger.LogError(e.Message + e.StackTrace);

                _provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);

                return ResponseOutput.NotOk(e.Message, ApiResponseCodeEnum.ProgramException);

            }
             
            return ResponseOutput.Ok(archiveResult);
        }








        #region   2021.12.14 整理废弃

        //[Obsolete]
        //[HttpGet, Route("forwardStudy/{studyId:guid}/{trialId:guid}")]
        //[TrialAudit(AuditType.StudyAudit, AuditOptType.Forwarded)]
        //[TypeFilter(typeof(TrialResourceFilter))]

        //public IResponseOutput ForwardStudy(Guid studyId)
        //{
        //    return _studyService.ForwardStudy(studyId);
        //}

        ///// <summary> 指定资源Id,获取Dicom检查信息 </summary>
        ///// <param name="studyId"> Dicom检查的Id </param>
        //[HttpGet, Route("item/{studyId:guid}")]
        //[Obsolete]
        //public IResponseOutput<DicomStudyDTO> GetStudyItem(Guid studyId)
        //{
        //    return ResponseOutput.Ok(_studyService.GetStudyItem(studyId));
        //}

        //[Obsolete]
        //[HttpDelete, Route("deleteStudy/{id:guid}/{trialId:guid}")]
        //public IResponseOutput DeleteStudy(Guid id)
        //{
        //    return _studyService.DeleteStudy(id);
        //}

        //[Obsolete]
        //[HttpPost, Route("getStudyList")]
        //public IResponseOutput<PageOutput<StudyDTO>> GetStudyList(StudyQueryDTO queryDto)
        //{
        //    return ResponseOutput.Ok(_studyService.GetStudyList(queryDto));
        //}


        /////// <summary> 指定资源Id,渲染Dicom检查的Jpeg预览图像  </summary>
        /////// <param name="studyId"> Dicom检查的Id </param>
        ////[HttpGet, Route("preview/{studyId:guid}")]
        ////[AllowAnonymous]
        ////public FileContentResult GetStudyPreview(Guid studyId)
        ////{
        ////    string path = _studyService.GetStudyPreview(studyId);
        ////    using (var sw = DicomRenderingHelper.RenderPreviewJpeg(path))
        ////    {
        ////        var bytes = new byte[sw.Length];
        ////        sw.Read(bytes, 0, bytes.Length);
        ////        sw.Close();
        ////        return new FileContentResult(bytes, "image/jpeg");
        ////    }
        ////}

        ///// <summary>
        ///// Dicom匿名化
        ///// </summary>
        ///// <param name="studyId">需要匿名化的检查Id</param>
        ///// <returns></returns>
        //[HttpPost, Route("dicomAnonymize/{studyId:guid}/{trialId:guid}")]
        //[TrialAudit(AuditType.StudyAudit, AuditOptType.Anonymized)]
        //[Obsolete]
        //[TypeFilter(typeof(TrialResourceFilter))]
        //public async Task<IResponseOutput> DicomAnonymize(Guid studyId)
        //{
        //    string userName = User.FindFirst("realName").Value; ;
        //    return await _studyService.DicomAnonymize(studyId, userName);
        //}


        ///// <summary>
        ///// 获取受试者 这次访视 对应的study  modality 列表
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <param name="siteId"></param>
        ///// <param name="subjectId"></param>
        ///// <param name="subjectVisitId"></param>
        ///// <returns></returns>
        //[HttpPost, Route("getSubjectVisitStudyList/{trialId:guid}/{siteId:guid}/{subjectId:guid}/{subjectVisitId:guid}")]
        //[Obsolete]
        //[AllowAnonymous]
        //public IResponseOutput<List<SubjectVisitStudyDTO>> GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId,
        //    Guid subjectVisitId)
        //{
        //    return ResponseOutput.Ok(_studyService.GetSubjectVisitStudyList(trialId, siteId, subjectId, subjectVisitId));
        //}

        //[HttpPost, Route("getDistributeStudyList")]
        //[Obsolete]
        //public IResponseOutput<PageOutput<DistributeReviewerStudyStatusDTO>> GetDistributeStudyList(StudyStatusQueryDTO studyStatusQueryDto)
        //{
        //    return ResponseOutput.Ok(_studyService.GetDistributeStudyList(studyStatusQueryDto));
        //}

        /////// <summary> 删除检查</summary>
        ////[HttpDelete, Route("deleteStudy/{id:guid}/{trialId:guid}")]
        ////
        ////[TypeFilter(typeof(TrialResourceFilter))]
        ////public IResponseOutput DeleteStudy(Guid id)
        ////{
        ////    return _studyService.DeleteStudy(id);
        ////}

        ///// <summary> 更新Study状态,并保存状态变更信息 </summary>
        ///// <param name="studyStatusDetailCommand"></param>

        //[HttpPost, Route("updateStudyStatus/{trialId:guid}")]

        //[TrialAudit(AuditType.StudyAudit, AuditOptType.ChangeStudyStatus)]
        //[Obsolete]
        //[TypeFilter(typeof(TrialResourceFilter))]
        //public IResponseOutput UpdateStudyStatus(StudyStatusDetailCommand studyStatusDetailCommand)
        //{
        //    return _studyService.UpdateStudyStatus(studyStatusDetailCommand);
        //}

        ///// <summary>
        ///// 根据项目Id 获取可选医生列表
        ///// </summary>
        ///// <param name="trialId"></param>
        ///// <returns></returns>
        //[HttpGet, Route("GetReviewerList/{trialId:guid}")]
        //[Obsolete]
        //public IResponseOutput<List<ReviewerDistributionDTO>> GetReviewerListByTrialId(Guid trialId)
        //{
        //    var result = _studyService.GetReviewerListByTrialId(trialId);
        //    return ResponseOutput.Ok(result);
        //}

        ///// <summary>
        ///// 根据StudyId获取该Study的操作记录,时间倒序
        ///// </summary>
        ///// <param name="studyId"></param>
        ///// <returns></returns>
        //[HttpGet, Route("getStudyStatusDetailList/{studyId:guid}")]
        //[Obsolete]
        //public IResponseOutput<List<StudyStatusDetailDTO>> GetStudyStatusDetailList(Guid studyId)
        //{
        //    var result = _studyService.GetStudyStatusDetailList(studyId);
        //    return ResponseOutput.Ok(result);
        //}

        ///// <summary>
        ///// 获取某个访视的关联访视
        ///// 用于获取关联影像(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表)
        ///// </summary>
        ///// <param name="visitNum"></param>
        ///// <param name="tpCode"></param>
        ///// <returns></returns>
        //[HttpGet, Route("getRelationVisitList/{visitNum}/{tpCode}")]
        //[Obsolete]
        //[AllowAnonymous]
        //public IResponseOutput<IEnumerable<RelationVisitDTO>> GetRelationVisitList(decimal visitNum, string tpCode)
        //{
        //    return ResponseOutput.Ok(_studyService.GetRelationVisitList(visitNum, tpCode));
        //}

        ///// <summary>
        ///// 保存标记(跟删除合并,每次保存最新的标记),会删除替换之前的标记
        ///// 外层的TPcode 必须传,里面的标记数组可为空数组,表示删除该Study的所有标记
        ///// </summary>
        ///// <param name="imageLabelCommand"></param>
        ///// <returns></returns>
        //[HttpPost, Route("saveImageLabelList")]
        //[AllowAnonymous]
        //[Obsolete]

        //public IResponseOutput SaveImageLabelList(ImageLabelCommand imageLabelCommand)
        //{
        //    return ResponseOutput.Result(_studyService.SaveImageLabelList(imageLabelCommand));
        //}

        ///// <summary>
        ///// 根据TPCode 获取所有的标记
        ///// </summary>
        ///// <param name="tpCode"></param>
        ///// <returns></returns>
        //[HttpGet, Route("getImageLabelList/{tpCode}")]
        //[Obsolete]
        //[AllowAnonymous]
        //public IResponseOutput<IEnumerable<ImageLabelDTO>> GetImageLabelList(string tpCode)
        //{
        //    return ResponseOutput.Ok(_studyService.GetImageLabel(tpCode));
        //}

        #endregion




    }
}