using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Application.Filter;

using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Interfaces;

namespace IRaCIS.Core.Application.Services
{
    [ApiExplorerSettings(GroupName = "Trial")]
    public class SubjectVisitService : BaseService, ISubjectVisitService
    {
        private readonly IRepository<SubjectVisit> _subjectVisitRepository;

        public SubjectVisitService(IRepository<SubjectVisit> subjectVisitRepository)
        {
            _subjectVisitRepository = subjectVisitRepository;
        }

        [HttpPost]
        [TypeFilter(typeof(TrialResourceFilter))]
        [UnitOfWork]
        public async Task<IResponseOutput> AddOrUpdateSV(SubjectVisitCommand svCommand)
        {

            var verifyExp1 = new EntityVerifyExp<SubjectVisit>()
            {
                VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId,
                VerifyMsg = "This subject's visit plan already contains a visit with the same visitnum."
            };

            var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
            {
                VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit,
                VerifyMsg = "该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视",
                IsVerify=svCommand.IsFinalVisit              
            };

            #region 废弃
            //var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
            //{
            //    verifyType = VerifyEnum.OnlyUpdate,
            //    VerifyExp = t => t.StudyList.Any(k => k.SubjectVisitId == svCommand.Id) && svCommand.SVSTDTC == null,
            //    VerifyMsg = "This visit is associated with the uploaded study images, and the visit start date is not allowed to be modified."
            //};

            //if (needDealEntity.SVSTDTC == null && needDealEntity.VisitExecuted == 1)
            //{
            //    return ResponseOutput.NotOk("VisitExecuted must have Start Date ");
            //}


            //if (needDealEntity.IsOutEnromentVisit)
            //{
            //    needDealEntity.VisitNum = _subjectVisitRepository.Where(t => t.SubjectId == svCommand.SubjectId).Max(t => t.VisitNum) + (decimal)0.1;
            //}

            //没有EndOfVisit  
            //if (svCommand.IsFinalVisit)
            //{
            //    //if (svCommand.InPlan)
            //    //{
            //  await  _repository.UpdateFromQueryAsync<Subject>(t => t.Id == svCommand.SubjectId, u => new Subject() { Status = SubjectStatus.EndOfVisit });
            //    //}
            //    //else
            //    //{
            //    //    return ResponseOutput.NotOk("计划外访视不允许设置为最后一次访视");

            //    //}
            //}
            #endregion


            svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3");

            var subject = (await _repository.FirstOrDefaultAsync<Subject>(t => t.Id == svCommand.SubjectId)).IfNullThrowException();


            //不管是否 都是执行,只是失访的时候  设置Subject状态为失去访视
            //if (svCommand.IsLostVisit)
            //{
            //    svCommand.VisitExecuted = VisitExecutedEnum.Executed;

            //    subject.IsMissingImages = true;

            //}
            //else
            //{
            //    svCommand.VisitExecuted = VisitExecutedEnum.Executed;
            //}

            svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted;

            //设置末次评估后,不允许添加计划外访视
            if (svCommand.InPlan == false && svCommand.Id == null)
            {
                if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit))
                {
                    return ResponseOutput.NotOk("设置末次评估后,不允许添加计划外访视");
                }
            }

            //更新的时候,返回的是数据库此时的实体数据
            var needDealEntity = await _subjectVisitRepository.InsertOrUpdateAsync(svCommand, false, verifyExp1, verifyExp2);

           
            if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.SubmitState == SubmitStateEnum.Submitted)
            {
                return ResponseOutput.NotOk("CRC提交后,不允许修改PD确认状态");
            }

            if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack)
            {
                return ResponseOutput.NotOk("回退的访视,不允许修改PD确认状态");
            }

            if (svCommand.IsFinalVisit)
            {
                    
                if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit))
                {
                    return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视");
                }


                subject.Status = SubjectStatus.OutOfVisit;

                //末次访视后的  访视设置为不可用
                await _subjectVisitRepository.UpdateFromQueryAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
                
            }
            else
            {
                //回退
                subject.Status = SubjectStatus.OnVisit;

                await _subjectVisitRepository.UpdateFromQueryAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitExecuted == VisitExecutedEnum.Unavailable, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.UnExecuted });
            }

            //更新受试者 首次给药日期 是否入组确认
            if (svCommand.SubjectFirstGiveMedicineTime != null)
            {

                subject.FirstGiveMedicineTime = svCommand.SubjectFirstGiveMedicineTime;
            
            }

            if (svCommand.IsEnrollmentConfirm != null)
            {

               await _subjectVisitRepository.UpdateFromQueryAsync(t => t.SubjectId == svCommand.SubjectId && t.IsBaseLine , u => new SubjectVisit() { IsEnrollmentConfirm = svCommand.IsEnrollmentConfirm.Value });

             
                //needDealEntity.IsUrgent = true;
            }

            
            await _repository.SaveChangesAsync();

            // 保存数据后,重新算下是否缺失影像  应对状态撤回
            //if (svCommand.IsLostVisit == false)
            //{

            //    var currentSubmittedVisitNum = await _repository.Where<SubjectVisit>(t => t.SubmitState == SubmitStateEnum.Submitted).MaxAsync(t => t.VisitNum);

            //    var isMissing = await _repository.AnyAsync<SubjectVisit>(t => (t.VisitNum < currentSubmittedVisitNum && t.SubmitState != SubmitStateEnum.Submitted) || t.IsLostVisit);

            //    await _repository.UpdateFromQueryAsync<Subject>(t => t.Id == svCommand.SubjectId, u => new Subject()
            //    {
            //        IsMissingImages = isMissing
            //    });
            //}


           

            return ResponseOutput.Ok();


        }


        [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{isUrgent:bool}")]
        public async Task<IResponseOutput> SetSubjectVisitUrgent(Guid subjectVisitId, bool isUrgent)
        {
            await _subjectVisitRepository.UpdateFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { IsUrgent = isUrgent });

            return ResponseOutput.Ok();
        }


        [HttpDelete, Route("{id:guid}/{trialId:guid}")]
        [TrialAudit(AuditType.SubjectAudit, AuditOptType.DeleteSubjectOutPlanVisit)]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> DeleteSV(Guid id)
        {
            if (await _repository.AnyAsync<DicomStudy>(t => t.SubjectVisitId == id))
            {
                return ResponseOutput.NotOk("This visit is associated with the uploaded study images and couldn't be deleted.");
            }
            if (await _subjectVisitRepository.AnyAsync(t => t.Id == id && t.InPlan))
            {
                return ResponseOutput.NotOk("This visit is InPlan and couldn't be deleted.");
            }
            return ResponseOutput.Result(await _repository.DeleteFromQueryAsync<SubjectVisit>(s => s.Id == id));
        }

        /// <summary>
        /// 设置受试者访视已执行  也就是将studyUploaded状态置为true  为了那些没有影像 人工设置准备
        /// </summary>
        /// <param name="subjectVisitId"></param>
        /// <returns></returns>
        [HttpPost("{subjectVisitId:guid}/{trialId:guid}")]
        [TrialAudit(AuditType.SubjectAudit, AuditOptType.SetSVExecuted)]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> SetSVExecuted(Guid subjectVisitId)
        {
            return ResponseOutput.Result(await _subjectVisitRepository.UpdateFromQueryAsync(s => s.Id == subjectVisitId, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Executed }));
        }


        /// <summary>
        /// 获取访视下的Dicom 检查信息   分所有的, 阅片的 不阅片   isReading : 0 查询所有 1 查询仅仅阅片的
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="sujectVisitId"></param>
        /// <param name="isReading"></param>
        /// <returns></returns>
        [HttpGet, Route("{trialId:guid}/{sujectVisitId:guid}/{isReading}")]
        [AllowAnonymous]
        public async Task<List<VisitStudyDTO>> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading)
        {
            var studyList = await _repository.Where<DicomStudy>(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).Select(k => new VisitStudyDTO()
            {
                InstanceCount = k.InstanceCount,
                Modalities = k.Modalities,
                SeriesCount = k.SeriesCount,
                StudyCode = k.StudyCode,
                StudyId = k.Id
            }).ToListAsync();
            var studyIds = studyList.Select(t => t.StudyId).ToList();

            var instanceList = await _repository.Where<DicomInstance>(t => studyIds.Contains(t.StudyId))
                   .Select(t => new { t.SeriesId, t.Id, t.InstanceNumber }).ToListAsync();

            foreach (var t in studyList)
            {
                t.SeriesList = await _repository.Where<DicomSeries>(s => s.StudyId == t.StudyId)
               .WhereIf(isReading == 1, s => s.IsReading).OrderBy(s => s.SeriesNumber).
               ThenBy(s => s.SeriesTime)
               .ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();


                t.SeriesList.ForEach(series => series.InstanceList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => k.Id).ToList());

                //设置为阅片与否 不更改数据库检查  的instance数量 和 SeriesCount  所以这里要实时统计
                t.SeriesCount = t.SeriesList.Count();
                t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceList).Count();
            }




            return studyList;

            //return ResponseOutput.Ok(studyList.Where(t => t.SeriesList.Count > 0).ToList());

        }


    }
}