using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Services;
using EasyCaching.Core;
using System.Linq.Expressions;
using IRaCIS.Core.Application.Helper;

namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
    [ApiExplorerSettings(GroupName = "Image")]
    public class StudyService : BaseService, IStudyService
    {

        private readonly IEasyCachingProvider _provider;


        private readonly IRepository<SubjectVisit> _subjectVisitRepository;
        private readonly IRepository<DicomInstance> _dicomInstanceRepository;
        private readonly IRepository<DicomSeries> _dicomSeriesRepository;

        public StudyService( IEasyCachingProvider provider
            , IRepository<SubjectVisit> subjectVisitRepository,
            IRepository<DicomInstance> dicomInstanceRepository,
            IRepository<DicomSeries> dicomSeriesRepository)
        {
            _provider = provider;
            _subjectVisitRepository = subjectVisitRepository;
            _dicomInstanceRepository = dicomInstanceRepository;
            _dicomSeriesRepository = dicomSeriesRepository;
        }






        [HttpPost]
        public async Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery)
        {

            var svExpression = QCCommon.GetDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray);

            var dicomStudyQuery = _repository.Where<DicomStudy>(t => t.TrialId == studyQuery.TrialId)
                    .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                      //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
                      .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression)
                    .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))
                    .Select(t => new UnionStudyViewModel()
                    {
                        TrialId = t.TrialId,
                        SiteId = t.SiteId,
                        SubjectId = t.SubjectId,
                        SubjectVisitId = t.SubjectVisitId,
                        VisitName = t.SubjectVisit.VisitName,
                        VisitNum = t.SubjectVisit.VisitNum,

                        IsDicom = true,

                        SubjectCode = t.Subject.Code,

                        Id = t.Id,

                        Bodypart = t.BodyPartExamined,

                        Modalities = t.Modalities,

                        Count = t.SeriesCount,

                        StudyCode = t.StudyCode,

                        //DicomStudyCode = t.StudyCode,
                        //NoneDicomCode = 0,

                        StudyTime = t.StudyTime,

                        TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,

                        TrialSiteCode = t.TrialSite.TrialSiteCode,

                        Uploader = t.Uploader.UserName,

                        UploadTime = t.CreateTime

                    });


            //.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);
            var svExpression2 = QCCommon.GetNoneDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray);


            var nodeDicomStudyQuery = _repository.Where<NoneDicomStudy>(t => t.TrialId == studyQuery.TrialId)
                .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                 //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
                 .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression2)
                 .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))

                 .Select(t => new UnionStudyViewModel()
                 {
                     TrialId = t.TrialId,
                     SiteId = t.SiteId,
                     SubjectId = t.SubjectId,
                     SubjectVisitId = t.SubjectVisitId,
                     VisitName = t.SubjectVisit.VisitName,
                     VisitNum = t.SubjectVisit.VisitNum,

                     IsDicom = false,

                     SubjectCode = t.Subject.Code,

                     Id = t.Id,

                     Bodypart = t.BodyPart,

                     Modalities = t.Modality,

                     Count = t.NoneDicomFileList.Count(),

                     StudyCode = t.StudyCode,

                     //NoneDicomCode = t.Code,
                     //DicomStudyCode = string.Empty,

                     StudyTime = t.ImageDate,

                     TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,

                     TrialSiteCode = t.TrialSite.TrialSiteCode,

                     Uploader = t.CreateUser.UserName,

                     UploadTime = t.CreateTime

                 });

            //.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);


            var unionQuery = dicomStudyQuery.Union(nodeDicomStudyQuery)
                .WhereIf(studyQuery.SubjectId != null, t => t.SubjectId == studyQuery.SubjectId)
                .WhereIf(studyQuery.SubjectVisitId != null, t => t.SubjectId == studyQuery.SubjectVisitId)
                .WhereIf(studyQuery.SiteId != null, t => t.SiteId == studyQuery.SiteId);

            return await unionQuery.ToPagedListAsync(studyQuery.PageIndex, studyQuery.PageSize, studyQuery.SortField, studyQuery.Asc);
        }


        [HttpPost]
        public async Task<PageOutput<UnionStudyMonitorModel>> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery)
        {
            var svExpression = QCCommon.GetStudyMonitorSubjectVisitFilter(studyQuery.VisitPlanArray);
            var StudyMonitorQuery = _repository.Where<StudyMonitor>(t => t.TrialId == studyQuery.TrialId)
                 .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                  //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
                  .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression)
                 .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))
                 .WhereIf(studyQuery.SubjectId != null, t => t.SubjectId == studyQuery.SubjectId)
                 .WhereIf(studyQuery.SubjectVisitId != null, t => t.SubjectId == studyQuery.SubjectVisitId)
                 .WhereIf(studyQuery.SiteId != null, t => t.SiteId == studyQuery.SiteId)
                 .Select(t => new UnionStudyMonitorModel()
                 {
                     TrialId = t.TrialId,
                     SiteId = t.SiteId,
                     SubjectId = t.SubjectId,
                     SubjectVisitId = t.SubjectVisitId,
                     VisitName = t.SubjectVisit.VisitName,
                     VisitNum = t.SubjectVisit.VisitNum,



                     SubjectCode = t.Subject.Code,


                     TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,

                     TrialSiteCode = t.TrialSite.TrialSiteCode,

                     Uploader = t.Uploader.UserName,

                     UploadTime = t.CreateTime,

                     IsSuccess=t.IsSuccess,
                     Note=t.Note,
                     IP = t.IP,
                     FileCount = t.FileCount,
                     FileSize = t.FileSize,
                     UploadFinishedTime = t.UploadFinishedTime,
                     UploadStartTime = t.UploadStartTime,

                     TotalMillisecondsInterval = t.TotalMillisecondsInterval,

                     IsDicomReUpload = t.IsDicomReUpload,
                     StudyId = t.Id,
                     IsDicom = t.IsDicom,

                     StudyCode = t.StudyCode


                 });

            return await StudyMonitorQuery.ToPagedListAsync(studyQuery.PageIndex, studyQuery.PageSize, string.IsNullOrEmpty(studyQuery.SortField) ? "UploadTime" : studyQuery.SortField, studyQuery.Asc);



            #region 冗余查询
            //var dicomStudyQuery = _repository.Where<StudyMonitor>(t => t.TrialId == studyQuery.TrialId && t.IsDicom)
            //     .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
            //     .WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
            //     .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))
            //     .Select(t => new UnionStudyMonitorModel()
            //     {
            //         TrialId = t.TrialId,
            //         SiteId = t.SiteId,
            //         SubjectId = t.SubjectId,
            //         SubjectVisitId = t.SubjectVisitId,
            //         VisitName = t.SubjectVisit.VisitName,
            //         VisitNum = t.SubjectVisit.VisitNum,



            //         SubjectCode = t.Subject.Code,


            //         TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,

            //         TrialSiteCode = t.TrialSite.TrialSiteCode,

            //         Uploader = t.Uploader.FullName,

            //         UploadTime = t.CreateTime,


            //         IP = t.IP,
            //         FileCount = t.FileCount,
            //         FileSize = t.FileSize,
            //         UploadFinishedTime = t.UploadFinishedTime,
            //         UploadStartTime = t.UploadStartTime,

            //         TotalMillisecondsInterval = t.TotalMillisecondsInterval,

            //         IsDicomReUpload = t.IsDicomReUpload,
            //         StudyId = t.Id,
            //         IsDicom = t.IsDicom,

            //         StudyCode = t.DicomStudy.StudyCode
            //            //DicomStudyCode = t.DicomStudy.StudyCode,
            //            //NoneDicomCode = 0,

            //        });

            ////.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);



            //var nodeDicomStudyQuery = _repository.Where<StudyMonitor>(t => t.TrialId == studyQuery.TrialId && t.IsDicom == false)
            //    .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
            //    .WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo))
            //    .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))

            //     .Select(t => new UnionStudyMonitorModel()
            //     {

            //         TrialId = t.TrialId,
            //         SiteId = t.SiteId,
            //         SubjectId = t.SubjectId,
            //         SubjectVisitId = t.SubjectVisitId,
            //         VisitName = t.SubjectVisit.VisitName,
            //         VisitNum = t.SubjectVisit.VisitNum,
            //         SubjectCode = t.Subject.Code,
            //         TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,
            //         TrialSiteCode = t.TrialSite.TrialSiteCode,
            //         Uploader = t.Uploader.FullName,
            //         UploadTime = t.CreateTime,

            //         IP = t.IP,
            //         FileCount = t.FileCount,
            //         FileSize = t.FileSize,
            //         UploadFinishedTime = t.UploadFinishedTime,
            //         UploadStartTime = t.UploadStartTime,

            //         TotalMillisecondsInterval = t.TotalMillisecondsInterval,

            //         IsDicomReUpload = t.IsDicomReUpload,
            //         StudyId = t.Id,
            //         IsDicom = t.IsDicom,

            //         StudyCode = t.NoneDicomStudy.StudyCode

            //         //DicomStudyCode = string.Empty,
            //         //NoneDicomCode = t.NoneDicomStudy.Code,

            //     });

            ////.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);


            //var unionQuery = dicomStudyQuery.Union(nodeDicomStudyQuery)
            //    .WhereIf(studyQuery.SubjectId != null, t => t.SubjectId == studyQuery.SubjectId)
            //    .WhereIf(studyQuery.SubjectVisitId != null, t => t.SubjectId == studyQuery.SubjectVisitId)
            //    .WhereIf(studyQuery.SiteId != null, t => t.SiteId == studyQuery.SiteId);

            //return await unionQuery.ToPagedListAsync(studyQuery.PageIndex, studyQuery.PageSize, string.IsNullOrEmpty(studyQuery.SortField) ? "UploadTime" : studyQuery.SortField, studyQuery.Asc);

            #endregion



        }


        /// <summary> 指定资源Id,渲染Dicom检查的Jpeg预览图像  </summary>
        /// <param name="studyId"> Dicom检查的Id </param>
        [HttpGet("{studyId:guid}")]
        public async Task<FileContentResult> Preview(Guid studyId)
        {
            string path = String.Empty;

            DicomInstance dicomInstance = await _repository.FirstOrDefaultAsync<DicomInstance>(s => s.StudyId == studyId);

            if (dicomInstance != null)
            {
                DicomStudy dicomStudy = await _repository.FirstOrDefaultAsync<DicomStudy>(s => s.Id == dicomInstance.StudyId);
                if (dicomStudy != null)
                {
                    path = FileStoreHelper.GetDicomInstanceFilePath(_hostEnvironment, dicomStudy.TrialId, dicomStudy.SiteId, dicomStudy.SubjectId, dicomStudy.SubjectVisitId, dicomStudy.Id, dicomInstance.Id);
                }
            }

            using (var sw = ImageHelper.RenderPreviewJpeg(path))
            {
                var bytes = new byte[sw.Length];
                sw.Read(bytes, 0, bytes.Length);
                sw.Close();
                return new FileContentResult(bytes, "image/jpeg");
            }
        }


        /// <summary>
        /// 获取某个检查的关联检查列表(该受试者在这个想项目下的所有检查)
        /// 点击检查检查列表中的一个检查获取对应的序列列表(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表)
        /// </summary>
        /// <returns></returns>
        [HttpGet("{subjectVisitId:guid}")]
        [AllowAnonymous]
        public IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId)
        {
            #region 废弃
            //var studylist = _studyRepository.Where(u => u.SubjectVisitId == subjectVisitId && u.IsDeleted == false).Select(t => new { StudyId = t.Id, t.SubjectId, t.TrialId }).ToList();
            //var subjectId = studylist.FirstOrDefault().SubjectId;
            //var trialId = studylist.FirstOrDefault().TrialId;
            //var studyIds = studylist.Select(t => t.StudyId).ToList();


            //var query = from studyItem in _studyRepository.Where(u => u.SubjectId == subjectId
            //                                                                   && u.TrialId == trialId && u.IsDeleted == false &&
            //                                                                   !studyIds.Contains(u.Id)
            //                                                                    /* && u.Status != (int)StudyStatus.Abandon*/)
            //            join visitItem in _subjectVisitRepository.AsQueryable()
            //                on studyItem.SubjectVisitId equals visitItem.Id
            //            select new RelationStudyDTO
            //            {
            //                StudyId = studyItem.Id,
            //                StudyCode = studyItem.StudyCode,
            //                VisitName = visitItem.VisitName,
            //                Modalities = studyItem.Modalities,
            //                Description = studyItem.Description,
            //                SeriesCount = studyItem.SeriesCount
            //            };
            #endregion

            var studyInfo = _repository.Where<DicomStudy>(u => u.SubjectVisitId == subjectVisitId).Select(t => new { t.SubjectId, t.TrialId }).FirstOrDefault().IfNullThrowException();

            var query = _repository.Where<DicomStudy>(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId)
                .ProjectTo<RelationStudyDTO>(_mapper.ConfigurationProvider).ToList();

            var list = query.OrderBy(u => u.VisitName).ThenBy(s => s.StudyCode).ToList();

            return ResponseOutput.Ok(list);
        }


        /// <summary> 指定资源Id,获取Dicom检查信息 </summary>
        /// <param name="studyId"> Dicom检查的Id </param>
        [HttpGet, Route("{studyId:guid}")]
        [AllowAnonymous]
        public IResponseOutput<DicomStudyDTO> Item(Guid studyId)
        {
            return ResponseOutput.Ok(_mapper.Map<DicomStudyDTO>(_repository.Where<DicomStudy>().FirstOrDefault(s => s.Id == studyId)));
        }



        /// <summary>
        /// 批量验证 检查是否可以上传 并告知原因
        /// </summary>
        [HttpPost]
        public IResponseOutput<List<VerifyStudyUploadResult>> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo)
        {
            var trialInfo = _repository.Where<Trial>().FirstOrDefault(t => t.Id == verifyInfo.TrialId).IfNullThrowException();

            var result = new List<VerifyStudyUploadResult>();

            var visitList = _repository.Where<SubjectVisit>(t => t.SubjectId == verifyInfo.SubjectId).Select(t => new { t.VisitNum, t.EarliestScanDate, t.LatestScanDate, t.Id }).ToList();


            verifyInfo.StudyInstanceUidList.ForEach(waitUploadItem =>
            {

                if (trialInfo.IsVerifyVisitImageDate)
                {

                    //小于当前访视 最近的最晚拍片
                    var before = visitList.Where(u => u.VisitNum < verifyInfo.VisitNum).Max(k => k.LatestScanDate);

                    if (before != null && waitUploadItem.StudyDate != null && before > waitUploadItem.StudyDate)
                    {
                        result.Add(new VerifyStudyUploadResult() { ErrorMesseage = $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能早于前序访视检查时间{before?.ToString("yyyy-MM-dd")},请核对检查数据是否有误", StudyInstanceUid = waitUploadItem.StudyInstanceUid });
                        return;
                    }

                    //大于当前访视 最近的最早拍片日期  
                    var after = visitList.Where(u => u.VisitNum > verifyInfo.VisitNum).Min(k => k.EarliestScanDate);

                    if (after != null && waitUploadItem.StudyDate != null && after < waitUploadItem.StudyDate)
                    {
                        result.Add(new VerifyStudyUploadResult() { ErrorMesseage = $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能晚于该访视之后的检查时间{after?.ToString("yyyy-MM-dd")},请核对检查数据是否有误", StudyInstanceUid = waitUploadItem.StudyInstanceUid });
                        return;
                    }
                }

                var temp = VerifyStudyUpload(waitUploadItem.StudyInstanceUid, verifyInfo.TrialId, verifyInfo.SubjectVisitId, verifyInfo.SubjectId);

                result.Add(temp);
            });

            return ResponseOutput.Ok(result);
        }


        private VerifyStudyUploadResult VerifyStudyUpload(string studyInstanceUid, Guid trialId, Guid currentSubjectVisitId, Guid SubjectId)
        {

            var result = new VerifyStudyUploadResult();

            if (_provider.Exists("StudyUid_" + studyInstanceUid))
            {
                result.AllowUpload = false;

                result.AllowReUpload = false;
                result.StudyInstanceUid = studyInstanceUid;
                result.ErrorMesseage = "当前有人正在上传归档该检查!";

                return result;
            }

            if (_repository.Where<Subject>(t => t.Id == SubjectId).Select(t => t.Status).FirstOrDefault() == SubjectStatus.EndOfVisit)
            {
                result.AllowUpload = false;

                result.AllowReUpload = false;
                result.StudyInstanceUid = studyInstanceUid;
                result.ErrorMesseage = "受试者访视结束,不允许上传!";

                return result;
            }

            Guid expectStudyId = IdentifierHelper.CreateGuid(studyInstanceUid.Trim(), trialId.ToString());



            var verifyStudyInfo = _repository.Where<DicomStudy>(t => t.TrialId == trialId && t.Id == expectStudyId).ProjectTo<VerifyStudyDto>(_mapper.ConfigurationProvider).FirstOrDefault();
            result.StudyInfo = verifyStudyInfo;


            //数据库不存在该检查  允许上传
            if (verifyStudyInfo == null)
            {
                result.AllowUpload = true;
            }
            //数据库该项目有该检查  看是否支持重传
            else
            {
                //是同一个受试者  支持重传
                if (verifyStudyInfo.SubjectId == SubjectId && verifyStudyInfo.SubjectVisitId == currentSubjectVisitId)
                {
                    result.AllowReUpload = true;
                }
                //不是同一个受试者
                else
                {
                    //有默认值,其实不用写,这里为了好理解
                    result.AllowUpload = false;

                    result.AllowReUpload = false;

                    result.ErrorMesseage = $"此处不可以上传。当前影像检查已经上传给受试者{verifyStudyInfo.SubjectCode}的{verifyStudyInfo.VisitName}";
                }
            }
            result.StudyInstanceUid = studyInstanceUid;
            return result;
        }




        /// <summary>
        /// 获取保存到Dicom文件中的信息
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <returns></returns>
        public DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId)
        {
            //6表连接 subject trial trialSite sponsor subjectVisit   site 
            var info = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).ProjectTo<DicomTrialSiteSubjectInfo>(_mapper.ConfigurationProvider).FirstOrDefault().IfNullThrowException();

            return info;
        }

        public (List<string> SeriesInstanceUid, List<string> SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId)
        {
            var seriesInstanceUidList = _dicomSeriesRepository.Where(t => t.StudyId == studyId).Select(t => t.SeriesInstanceUid).ToList();

            var sopInstanceUidList = _dicomInstanceRepository.Where(t => t.StudyId == studyId).Select(t => t.SopInstanceUid).ToList();

            return (seriesInstanceUidList, sopInstanceUidList);
        }

    }
}