using IRaCIS.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;

namespace IRaCIS.Application.Services
{
    [ApiExplorerSettings(GroupName = "Trial")]
    public class SubjectService : BaseService, ISubjectService
    {
        private readonly IRepository<Subject> _subjectRepository;

        public SubjectService(IRepository<Subject> subjectRepository)
        {
            _subjectRepository = subjectRepository;
        }

        /// <summary>
        ///  添加或更新受试者信息[New]
        /// </summary>
        /// <param name="subjectCommand">state:1-访视中,2-出组。0-全部</param>
        /// <returns></returns>

        [TrialAudit(AuditType.SubjectAudit, AuditOptType.AddOrUpdateSubject)]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> AddOrUpdateSubject([FromBody] SubjectCommand subjectCommand)
        {

            if (await _repository.AnyAsync<Trial>(t => t.Id == subjectCommand.TrialId && !t.VisitPlanConfirmed))
            {
                return ResponseOutput.NotOk("The trial visit plan has not been confirmed yet.Please contact the project manager to confirm the visit plan before adding subject.");
            }

            var verifyExp1 = new EntityVerifyExp<Subject>()
            {
                VerifyExp = u => u.Code == subjectCommand.Code && u.TrialId == subjectCommand.TrialId,
                VerifyMsg = "A subjects with the same subject ID already existed in this trial."
            };

           

            var mapedSubject = await _subjectRepository.InsertOrUpdateAsync(subjectCommand, false, verifyExp1/*, verifyExp2*/);

            if (subjectCommand.Id == null) //insert
            {
                var IsEnrollementQualificationConfirm = await _repository.Where<Trial>(t => t.Id == mapedSubject.TrialId).Select(u => u.IsEnrollementQualificationConfirm).FirstOrDefaultAsync();



                //添加受试者的时候,获取访视计划列表,添加到受试者访视表。
                var visitPlan = await _repository.Where<VisitStage>(t => t.TrialId == subjectCommand.TrialId).ToListAsync();

                var svlist = _mapper.Map<List<SubjectVisit>>(visitPlan);

                svlist.ForEach(t =>
                {
                    t.TrialId = subjectCommand.TrialId;
                    t.SiteId = subjectCommand.SiteId;
                    t.IsEnrollmentConfirm = t.IsBaseLine ? IsEnrollementQualificationConfirm : false;
                });

                mapedSubject.SubjectVisitList = svlist;
            }
            else //update
            {
                //变更site 
                if (mapedSubject.SiteId != subjectCommand.SiteId)
                {

                    await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == mapedSubject.Id,
                        u => new SubjectVisit() { SiteId = mapedSubject.SiteId });

                    await _repository.UpdateFromQueryAsync<DicomStudy>(t => t.SubjectId == mapedSubject.Id,
                        u => new DicomStudy() { SiteId = mapedSubject.SiteId });


                };
                ////如果访视结束了   需要删除计划外未执行的访视
                //if (mapedSubject.Status == SubjectStatus.EndOfVisit)
                //{
                //    await _repository.DeleteFromQueryAsync<SubjectVisit>(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == mapedSubject.Id && t.InPlan == false);
                //}

                ////如果是出组了  将受试者未执行的 设置为不可用
                //if (mapedSubject.Status == SubjectStatus.OutOfEnrollment)
                //{
                //    await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == mapedSubject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
                //}

            }



            await _repository.SaveChangesAsync();

            return ResponseOutput.Ok(mapedSubject.Id.ToString());

        }

        [HttpPut("{trialId:guid}")]
        public async Task<IResponseOutput> UpdateSubjectStatus(SubjectStatusChangeCommand subjectStatusChangeCommand)
        {
            var subject = await _subjectRepository.FirstOrDefaultAsync(t => t.Id == subjectStatusChangeCommand.SubjectId);

            if (subject == null) return Null404NotFound(subject);

            _mapper.Map(subjectStatusChangeCommand, subject);

            ////如果访视结束了   需要删除计划外未执行的访视
            //if (subjectStatusChangeCommand.Status == SubjectStatus.EndOfVisit)
            //{
            //    await _repository.DeleteFromQueryAsync<SubjectVisit>(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == subject.Id && t.InPlan == false);
            //}

            //如果是出组了  
            if (subjectStatusChangeCommand.Status == SubjectStatus.OutOfVisit)
            {

                if (subjectStatusChangeCommand.FinalSubjectVisitId != null)
                {

                    if (await _repository.AnyAsync<SubjectVisit>(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.IsFinalVisit))
                    {
                        return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视");
                    }

                    var sv = await _repository.FirstOrDefaultAsync<SubjectVisit>(t => t.Id == subjectStatusChangeCommand.FinalSubjectVisitId).IfNullThrowException();

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

                    sv.IsFinalVisit = true;

                    //末次访视后的  访视设置为不可用
                    await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });

                }


                //将受试者未执行的 设置为不可用
                await _repository.UpdateFromQueryAsync<SubjectVisit>(t => t.SubjectId == subject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
            }
            else
            {

            }
            await _repository.SaveChangesAsync();

            return ResponseOutput.Ok();


        }


        [Obsolete]
        [HttpGet("{trialId:guid}/{subjectId:guid}/{finalSubjectVisitId:guid}")]
        public async Task<IResponseOutput> VerifySubjectFinalVisit(Guid subjectId, Guid finalSubjectVisitId)
        {

            if (await _repository.AnyAsync<SubjectVisit>(t => t.SubjectId == subjectId && t.IsFinalVisit))
            {
                return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视");
            }

            var sv = (await _repository.FirstOrDefaultAsync<SubjectVisit>(t => t.Id == finalSubjectVisitId)).IfNullThrowException();

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

            return ResponseOutput.Ok();
        }


        [HttpDelete("{id:guid}/{trialId:guid}")]

        [TrialAudit(AuditType.SubjectAudit, AuditOptType.DeleteSubject)]
        [TypeFilter(typeof(TrialResourceFilter))]
        public async Task<IResponseOutput> DeleteSubject(Guid id)
        {

            if (await _repository.AnyAsync<SubjectVisit>(u => u.SubjectId == id && u.VisitExecuted == VisitExecutedEnum.Executed))
            {
                return ResponseOutput.NotOk("This subject has executed a visit with uploading study images,and couldn't be deleted.");
            }

            var isSuccess = await _subjectRepository.DeleteFromQueryAsync(u => u.Id == id);
            await _repository.DeleteFromQueryAsync<SubjectVisit>(u => u.SubjectId == id);
            return ResponseOutput.Result(isSuccess);
        }

        /// <summary> 分页获取受试者列表[New] </summary>
        /// /// <param name="param">state:1-访视中,2-出组。0-全部</param>
        [HttpPost]
        public async Task<IResponseOutput<PageOutput<SubjectQueryView>, TrialSubjectConfig>> GetSubjectList(SubjectQueryParam param)
        {

            var subjectQuery = _subjectRepository.Where(u => u.TrialId == param.TrialId)
                  .WhereIf(!string.IsNullOrWhiteSpace(param.Code), t => t.Code.Contains(param.Code))
                  .WhereIf(!string.IsNullOrWhiteSpace(param.Name), t => t.ShortName.Contains(param.Name))
                  .WhereIf(!string.IsNullOrWhiteSpace(param.Sex), t => t.Sex.Contains(param.Sex))
                  .WhereIf(param.Status != null, t => t.Status == param.Status)
                  .WhereIf(param.SiteId != null, t => t.SiteId == param.SiteId)
                  // CRC  只负责他管理site的受试者
                  .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                  .ProjectTo<SubjectQueryView>(_mapper.ConfigurationProvider);


            var pageList = await subjectQuery.ToPagedListAsync(param.PageIndex, param.PageSize, param.SortField == string.Empty ? "Code" : param.SortField, param.Asc);

            var trialConfig = await _repository.Where<Trial>(t => t.Id == param.TrialId).ProjectTo<TrialSubjectConfig>(_mapper.ConfigurationProvider).FirstOrDefaultAsync().IfNullThrowException();

            return ResponseOutput.Ok(pageList, trialConfig);

        }



        /// <summary>
        /// 计划外访视  获取受试者选择下拉框列表
        /// </summary>
        [HttpGet("{siteId:guid}/{trialId:guid}")]
        public List<SubjectSelect> GetSubjectListBySiteId(Guid siteId, Guid trialId)
        {
            var query = _subjectRepository.Where(t => t.SiteId == siteId && t.TrialId == trialId && t.Status == SubjectStatus.OnVisit).Select(u => new SubjectSelect()
            {
                Code = u.Code,
                FirstName = u.FirstName,
                LastName = u.LastName,
                Sex = u.Sex,
                SubjectId = u.Id,
                Age = u.Age,
                MRN = u.MedicalNo,
                Status = u.Status,

                FirstGiveMedicineTime = u.FirstGiveMedicineTime

            });
            return query.ToList();



        }


    }
}