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

namespace IRaCIS.Core.Application.Service
{
    [ApiExplorerSettings(GroupName = "Trial")]
    public class SubjectService(IRepository<Subject> _subjectRepository,
        IRepository<Trial> _trialRepository,
        IRepository<SubjectVisit> _subjectVisitRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ISubjectService
    {


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

        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_CRC_QC)]
        public async Task<IResponseOutput<string>> AddOrUpdateSubject([FromBody] SubjectCommand subjectCommand)
        {
            var svlist = new List<SubjectVisit>();
            if (await _trialRepository.AnyAsync(t => t.Id == subjectCommand.TrialId && !t.VisitPlanConfirmed))
            {
                //---项目访视计划没有确认。请联系项目经理确认项目访视计划后，再添加受试者。
                return ResponseOutput.NotOk(_localizer["Subject_NoConfirmedPlan"]);
            }

            var verifyExp1 = new EntityVerifyExp<Subject>()
            {
                VerifyExp = u => u.Code == subjectCommand.Code && u.TrialId == subjectCommand.TrialId,
                //---已存在具有相关受试者编号的受试者。
                VerifyMsg = _localizer["Subject_DuplicateSubjectNum"]
            };


            Subject? mapedSubject = null;

            if (subjectCommand.Id == null) //insert
            {


                mapedSubject = await _subjectRepository.InsertFromDTOAsync(subjectCommand, false, verifyExp1);


            }
            else //update
            {

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

            }

            await _subjectRepository.SaveChangesAsync();

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

        }

        [HttpPut]
        [UnitOfWork]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_CRC_QC)]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        public async Task<IResponseOutput> UpdateSubjectStatus(SubjectStatusChangeCommand subjectStatusChangeCommand)
        {
            await _subjectRepository.UpdateFromDTOAsync(subjectStatusChangeCommand, true);
            return ResponseOutput.Ok();
        }


        [HttpDelete("{trialId:guid}/{id:guid}")]
        [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
        [UnitOfWork]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_CRC)]
        public async Task<IResponseOutput> DeleteSubject(Guid id)
        {

            if (await _subjectVisitRepository.AnyAsync(u => u.SubjectId == id && u.VisitExecuted == VisitExecutedEnum.Executed))
            {
                //---该受试者已经有访视已经上传影像，不允许删除。
                return ResponseOutput.NotOk(_localizer["Subject_UploadedVisitNoDelete"]);
            }

            await _subjectRepository.UpdatePartialFromQueryAsync(id, x => new Subject
            {
                IsDeleted = true,
            });
            await _subjectVisitRepository.UpdatePartialFromQueryAsync(u => u.SubjectId == id, x => new SubjectVisit()
            {
                IsDeleted = true,
            });

            var isSuccess = await _subjectRepository.SaveChangesAsync();

            return ResponseOutput.Result(isSuccess);
        }

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

            var subjectQuery = _subjectRepository.Where(u => u.TrialId == inQuery.TrialId)
                  .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Code), t => t.Code.Contains(inQuery.Code))
                  .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Name), t => t.ShortName.Contains(inQuery.Name))
                  .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Sex), t => t.Sex.Contains(inQuery.Sex))
                  .WhereIf(inQuery.Status != null, t => t.Status == inQuery.Status)

                  .WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
                  // CRC  只负责他管理site的受试者
                  .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id))
                  .ProjectTo<SubjectQueryView>(_mapper.ConfigurationProvider)
                 .WhereIf(inQuery.IsMissingImages != null, t => t.IsMissingImages == inQuery.IsMissingImages);


            var pageList = await subjectQuery.ToPagedListAsync(inQuery, nameof(SubjectQueryView.Code));

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

            return ResponseOutput.Ok(pageList, trialConfig);

        }



        /// <summary>
        /// 计划外访视  获取受试者选择下拉框列表
        /// </summary>
        [HttpGet("{trialSiteId:guid}/{trialId:guid}")]
        public List<SubjectSelect> GetSubjectListBySiteId(Guid trialSiteId, Guid trialId)
        {
            var query = _subjectRepository.Where(t => t.TrialSiteId == trialSiteId && 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();
        }




    }
}
