using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.Third_partyProject.DTO;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
using Microsoft.AspNetCore.Mvc;
using ZiggyCreatures.Caching.Fusion;

namespace IRaCIS.Core.Application.Service.Third_partyProject
{

    [ApiExplorerSettings(GroupName = "Trial")]
    public class UltrasonicDicomService(IRepository<Trial> _trialRepository,
        IRepository<DicomStudy> _studyRepository,
        IRepository<Dictionary> _dictionaryRepository,
        IRepository<VisitTask> _visitTaskRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService
    {


        /// <summary>
        /// 项目列表
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IResponseOutput<PageOutput<TrialListDTO_UltrasonicDicom>>> GetTrialList(TrialToBeDoneQuery inQuery)
        {

            var isPM = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.ProjectManager || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.APM;
            var isCRC = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator;
            var isIQC = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.IQC;
            var isMIM = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.MIM;
            var isSPMOrCPM = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SPM || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CPM;


            var query = _trialRepository.AsQueryable().IgnoreQueryFilters()

             .WhereIf(inQuery.SponsorId != null, o => o.SponsorId == inQuery.SponsorId)
             .WhereIf(!string.IsNullOrEmpty(inQuery.Code), o => o.TrialCode.Contains(inQuery.Code))
             .WhereIf(!string.IsNullOrEmpty(inQuery.ResearchProgramNo), o => o.ResearchProgramNo.Contains(inQuery.ResearchProgramNo))
             .WhereIf(!string.IsNullOrWhiteSpace(inQuery.ExperimentName), o => o.ExperimentName.Contains(inQuery.ExperimentName))
             .WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialIdentityUserList.Any(t => t.IdentityUserId == _userInfo.IdentityUserId && t.IsDeleted == false) && t.IsDeleted == false)
             .Select(t => new TrialListDTO_UltrasonicDicom()
             {
                 TrialId = t.Id,
                 ResearchProgramNo = t.ResearchProgramNo,
                 ExperimentName = t.ExperimentName,
                 TrialCode = t.TrialCode,
                 CreateTime = t.CreateTime,
                 Sponsor = _userInfo.IsEn_Us ? t.Sponsor.SponsorName : t.Sponsor.SponsorNameCN,
                 TrialStatusStr = t.TrialStatusStr
             });

            var result = await query.ToPagedListAsync(inQuery);

            return ResponseOutput.Ok(result);
        }


        /// <summary>
        /// 任务列表  第一层级
        /// </summary>
        /// <param name="inQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<PageOutput<VisitTaskDTO_UltrasonicDicom>> GetVisitTaskList(VisitTaskQuery_UltrasonicDicom inQuery)
        {
            var visitTaskQueryable = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && t.TaskAllocationState == TaskAllocationState.Allocated && t.SourceSubjectVisitId != null)

              .WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
              .WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
              .WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent)
              .WhereIf(inQuery.DoctorUserId != null, t => t.DoctorUserId == inQuery.DoctorUserId)
              .WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
              .WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => (t.BlindTrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate) || (t.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate == false))
              .WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName))
              .WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => (t.Subject.Code.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate))

              .ProjectTo<VisitTaskDTO_UltrasonicDicom>(_mapper.ConfigurationProvider);

            var defalutSortArray = new string[] { nameof(VisitTask.SubjectId), nameof(VisitTask.VisitTaskNum) };

            var pageList = await visitTaskQueryable.ToPagedListAsync(inQuery, defalutSortArray);

            return pageList;
        }

        /// <summary>
        /// 检查列表   第二层级
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<List<StudyDTO_UltrasonicDicom>> GetDicomAndNoneDicomStudyList(Guid visiTaskId, [FromServices] IRepository<VisitTask> _visitTaskRepository)
        {

            var query = from dicomStudy in _visitTaskRepository.Where(t => t.Id == visiTaskId).Select(t => t.SourceSubjectVisit).SelectMany(t => t.StudyList)
                        select new StudyDTO_UltrasonicDicom()
                        {
                            TrialId = dicomStudy.TrialId,
                            TrialSiteId = dicomStudy.Subject.TrialSiteId,
                            SubjectId = dicomStudy.SubjectId,
                            SubjectVisitId = dicomStudy.SubjectVisitId,
                            VisitName = dicomStudy.SubjectVisit.VisitName,
                            VisitNum = dicomStudy.SubjectVisit.VisitNum,
                            IsDicom = true,
                            SubjectCode = dicomStudy.Subject.Code,

                            Id = dicomStudy.Id,

                            Bodypart = dicomStudy.BodyPartExamined,

                            Modalities = dicomStudy.Modalities,

                            Count = dicomStudy.SeriesCount,

                            StudyCode = dicomStudy.StudyCode,

                            StudyTime = dicomStudy.StudyTime,

                            TrialSiteAliasName = dicomStudy.Subject.TrialSite.TrialSiteAliasName,

                            TrialSiteCode = dicomStudy.Subject.TrialSite.TrialSiteCode,

                            Uploader = dicomStudy.CreateUserRole.IdentityUser.UserName,

                            UploadTime = dicomStudy.CreateTime
                        };





            return await query.ToListAsync();
        }

        /// <summary>
        /// 修改任务上的   影像上传状态
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        [HttpPut]
        public async Task<IResponseOutput> UpdateTaskImageState(UpdateTaskImageStateCommand command)
        {
            await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.Id == command.VisitTaskId, u => new VisitTask() { ImageStudyState = command.ImageStudyState });

            return ResponseOutput.Ok();
        }

        /// <summary>
        /// 通过任务Id  获取检查模态下拉框
        /// </summary>
        /// <returns></returns>
        public async Task<List<StudySeriesModality>> GetStudyModalityList(Guid visiTaskId)
        {

            var list = await _visitTaskRepository.Where(t => t.Id == visiTaskId).Select(t => t.SourceSubjectVisit).SelectMany(t => t.StudyList).Select(t => new StudySeriesModality
            {
                StudyId = t.Id,
                SeriesCount = t.SeriesCount,
                StudyCode = t.StudyCode,
                SeriesModalityList = t.SeriesList.Select(t => new SeriesModality { SeriesId = t.Id, Modality = t.Modality }).ToList()

            }).ToListAsync();

            return list;
        }

        /// <summary>
        /// 通过选择的序列Id 数组，获取下面的Instance 路径
        /// </summary>
        /// <param name="seriesIdList"></param>
        /// <param name="_dicomSeriesRepository"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<List<InstancePathDTO>> GetStudyModalityOSSPath(List<Guid> seriesIdList, [FromServices] IRepository<DicomSeries> _dicomSeriesRepository)
        {
            return await _dicomSeriesRepository.Where(t => seriesIdList.Contains(t.Id)).SelectMany(t => t.DicomInstanceList).Select(t => new InstancePathDTO() { InstancePath = t.Path, StudyCode = t.DicomStudy.StudyCode, SopInstanceUid = t.SopInstanceUid, StudyInstanceUid = t.StudyInstanceUid }).ToListAsync();
        }


        /// <summary>
        /// 归档接口 -new 一份 序列层级增加了一个参数VisitTaskId  用于绑定从TomTec拉取来的序列（两个人公用的影像，不应该绑定）
        /// </summary>
        /// <param name="incommand"></param>
        /// <param name="_studyMonitorRepository"></param>
        /// <param name="_distributedLockProvider"></param>
        /// <param name="_fusionCache"></param>
        /// <param name="_dicomSeriesRepository"></param>
        /// <param name="_dicomInstanceRepository"></param>
        /// <returns></returns>

        [TrialGlobalLimit( "AfterStopCannNotOpt" )]
        public async Task<IResponseOutput> AddOrUpdateArchiveStudy(NewArchiveStudyCommand incommand,
           [FromServices] IRepository<StudyMonitor> _studyMonitorRepository,
           [FromServices] IDistributedLockProvider _distributedLockProvider,
           [FromServices] IFusionCache _fusionCache,
           [FromServices] IRepository<DicomSeries> _dicomSeriesRepository,
           [FromServices] IRepository<DicomInstance> _dicomInstanceRepository)
        {


            try
            {
                var trialId = incommand.TrialId;

                var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
                studyMonitor.UploadFinishedTime = DateTime.Now;
                studyMonitor.ArchiveFinishedTime = DateTime.Now;
                studyMonitor.FailedFileCount = incommand.FailedFileCount;
                studyMonitor.IsSuccess = true;

                //上传
                if (studyMonitor.IsDicomReUpload == false)
                {
                    var study = _mapper.Map<DicomStudy>(incommand.Study);

                    var @lock = _distributedLockProvider.CreateLock($"StudyCode");

                    using (await @lock.AcquireAsync())
                    {
                        //查询数据库获取最大的Code 没有记录则为0
                        var dbStudyCodeIntMax = _studyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max();

                        //获取缓存中的值 并发的时候，需要记录，已被占用的值 这样其他线程在此占用的最大的值上递增
                        var cacheMaxCodeInt = await _fusionCache.GetOrDefaultAsync<int>(CacheKeys.TrialStudyMaxCode(trialId));

                        int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1;

                        study.Code = currentNextCodeInt;
                        study.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy));

                        await _fusionCache.SetAsync<int>(CacheKeys.TrialStudyMaxCode(trialId), study.Code, TimeSpan.FromMinutes(30));

                    }


                    study.Id = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString());
                    study.TrialId = incommand.TrialId;
                    study.SubjectId = incommand.SubjectId;
                    study.SubjectVisitId = incommand.SubjectVisitId;


                    //特殊处理逻辑
                    study.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Distinct());
                    SpecialArchiveStudyDeal(study);

                    await _studyRepository.AddAsync(study);


                    studyMonitor.StudyId = study.Id;
                    studyMonitor.StudyCode = study.StudyCode;


                    foreach (var seriesItem in incommand.Study.SeriesList)
                    {
                        var series = _mapper.Map<DicomSeries>(seriesItem);

                        series.Id = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, incommand.TrialId.ToString());
                        series.StudyId = study.Id;

                        series.TrialId = incommand.TrialId;
                        series.SubjectId = incommand.SubjectId;
                        series.SubjectVisitId = incommand.SubjectVisitId;

                        await _dicomSeriesRepository.AddAsync(series);

                        foreach (var instanceItem in seriesItem.InstanceList)
                        {
                            var isntance = _mapper.Map<DicomInstance>(instanceItem);

                            Guid instanceId = IdentifierHelper.CreateGuid(study.StudyInstanceUid, series.SeriesInstanceUid, isntance.SopInstanceUid, study.TrialId.ToString());

                            isntance.Id = instanceId;
                            isntance.StudyId = study.Id;
                            isntance.SeriesId = series.Id;

                            isntance.TrialId = incommand.TrialId;
                            isntance.SubjectId = incommand.SubjectId;
                            isntance.SubjectVisitId = incommand.SubjectVisitId;

                            await _dicomInstanceRepository.AddAsync(isntance);
                        }
                    }




                }
                else
                {

                    var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString()); ;

                    var study = await _studyRepository.FirstOrDefaultAsync(t => t.Id == studyId);


                    //特殊处理逻辑
                    study.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Union(study.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct());
                    SpecialArchiveStudyDeal(study);



                    // 少了整个序列

                    //某个序列下少了instance
                    foreach (var seriesItem in incommand.Study.SeriesList)
                    {
                        var seriesId = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, trialId.ToString());

                        DicomSeries dicomSeries = await _dicomSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);

                        //判断重复
                        if (dicomSeries == null)
                        {
                            var series = _mapper.Map<DicomSeries>(seriesItem);

                            series.Id = seriesId;
                            series.StudyId = study.Id;

                            series.TrialId = incommand.TrialId;
                            series.SubjectId = incommand.SubjectId;
                            series.SubjectVisitId = incommand.SubjectVisitId;


                            dicomSeries = await _dicomSeriesRepository.AddAsync(series);

                            //新的序列 那么  检查的序列数量+1
                            study.SeriesCount += 1;
                        }
                        else
                        {
                            //该序列掉了instance
                            dicomSeries.InstanceCount += seriesItem.InstanceList.Count;
                        }

                        foreach (var instanceItem in seriesItem.InstanceList)
                        {
                            var insntance = _mapper.Map<DicomInstance>(instanceItem);
                            insntance.Id = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString());
                            insntance.StudyId = study.Id;
                            insntance.SeriesId = dicomSeries.Id;

                            insntance.TrialId = incommand.TrialId;
                            insntance.SubjectId = incommand.SubjectId;
                            insntance.SubjectVisitId = incommand.SubjectVisitId;

                            await _dicomInstanceRepository.AddAsync(insntance);
                        }


                        //  不管是新的序列  还是 该序列 掉了Instance   重传的时候 检查的instance 数量都会增加
                        study.InstanceCount += seriesItem.InstanceList.Count;

                    }


                }

                var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit");

                using (await @lock2.AcquireAsync())
                {
                    await _dicomInstanceRepository.SaveChangesAsync();
                }
            }
            catch (Exception ex)
            {

                return ResponseOutput.NotOk(ex.Message);
            }
            finally
            {
                await _fusionCache.RemoveAsync(CacheKeys.TrialStudyUidUploading(incommand.TrialId, incommand.Study.StudyInstanceUid));
            }



            return ResponseOutput.Ok();
        }

        private void SpecialArchiveStudyDeal(DicomStudy study)
        {
            #region 特殊逻辑


            if (study.PatientBirthDate.Length == 8)
            {
                study.PatientBirthDate = $"{study.PatientBirthDate[0]}{study.PatientBirthDate[1]}{study.PatientBirthDate[2]}{study.PatientBirthDate[3]}-{study.PatientBirthDate[4]}{study.PatientBirthDate[5]}-{study.PatientBirthDate[6]}{study.PatientBirthDate[7]}";
            }

            var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();


            var modality = study.Modalities;

            var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;

            if (modality == "MR")
            {
                modalityForEdit = "MRI";
            }

            if (modality == "PT")
            {
                modalityForEdit = "PET";
            }
            if (modality == "PT、CT")
            {
                modalityForEdit = "PET-CT";
            }

            study.ModalityForEdit = modalityForEdit;
            #endregion
        }
    }
}
