using IRaCIS.Application.Interfaces;
using IRaCIS.Core.Infra.EFCore;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Service.WorkLoad.DTO;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Auth;
using System.Text.RegularExpressions;

namespace IRaCIS.Application.Services
{
    [ApiExplorerSettings(GroupName = "Enroll")]
    public class EnrollService : BaseService, IEnrollService
    {
        private readonly IRepository<Trial> _trialRepository;
        private readonly IRepository<TrialStatusDetail> _trialDetailRepository;

        private readonly IRepository<TrialPaymentPrice> _TrialPaymentPriceRepository;
        private readonly IRepository<Enroll> _enrollRepository;
        private readonly IRepository<Doctor> _doctorRepository;
        private readonly IRepository<EnrollDetail> _enrollDetailRepository;
        private readonly IRepository<Workload> _workloadRepository;
        private readonly IMailVerificationService _mailVerificationService;

        //private readonly IRepository<TrialUser> _trialUserRepository;


        public EnrollService(IRepository<Trial> clinicalTrialProjectRepository,
            IRepository<TrialStatusDetail> clinicalProjectDetailRepository,
             IRepository<Enroll> intoGroupRepository,
                IRepository<Doctor> doctorRepository,
                IRepository<TrialPaymentPrice> TrialPaymentPriceRepository,
            IRepository<EnrollDetail> intoGroupDetailRepository, 
            IRepository<Workload> workloadRepository,
            IMailVerificationService mailVerificationService)
        {
            _trialRepository = clinicalTrialProjectRepository;
            _TrialPaymentPriceRepository = TrialPaymentPriceRepository;
            _doctorRepository = doctorRepository;

            _trialDetailRepository = clinicalProjectDetailRepository;
            _enrollRepository = intoGroupRepository;
            _enrollDetailRepository = intoGroupDetailRepository;
            _workloadRepository = workloadRepository;

            _mailVerificationService = mailVerificationService;
            //_trialUserRepository = trialUserRepository;

        }



        /// <summary>
        /// 添加或更新项目医生项目价格
        /// </summary>
        [HttpPost]
        public async Task<IResponseOutput> AddOrUpdateEnroll(EnrollCommand addOrUpdateModel)
        {

            var trialDoctoritem = await _enrollRepository.FirstOrDefaultAsync(u => u.Id == addOrUpdateModel.Id);
            if (trialDoctoritem == null)//insert
            {
                await _enrollRepository.InsertFromDTOAsync(addOrUpdateModel);
            }
            else//update
            {
                await _enrollRepository.UpdateFromDTOAsync(addOrUpdateModel);
            }
            var success = await _enrollRepository.SaveChangesAsync();
            return ResponseOutput.Result(success);
        }



        /// <summary>
        /// 获取医生项目列表
        /// </summary>
        /// <param name="challengeQuery"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<PageOutput<EnrollViewModel>> GetTrialDoctorList(EnrollGetQuery challengeQuery)
        {
            var costStatisticsQueryable = from enroll in _enrollRepository.Where(t => t.TrialId == challengeQuery.TrialId)
                                          join dociorc in _doctorRepository.Where() on enroll.DoctorId equals dociorc.Id
                                          join price in _TrialPaymentPriceRepository.Where() on enroll.TrialId equals price.TrialId
                                          select new EnrollViewModel()
                                          {
                                              ChineseName = dociorc.ChineseName,
                                              AdjustmentMultiple = enroll.AdjustmentMultiple,
                                              FirstName = dociorc.FirstName,
                                              LastName = dociorc.LastName,
                                              DoctorId = dociorc.Id,
                                              TrialId = challengeQuery.TrialId,
                                              Id = enroll.Id,
                                              Training = enroll.Training,
                                              RefresherTraining = enroll.RefresherTraining,
                                              Timepoint = enroll.Timepoint,
                                              Timepoint48H = enroll.Timepoint48H,
                                              Timepoint24H = enroll.Timepoint24H,
                                              Adjudication = enroll.Adjudication,
                                              Adjudication48H = enroll.Adjudication48H,
                                              Adjudication24H = enroll.Adjudication24H,
                                              Global = enroll.Global,
                                              Code = dociorc.Code,
                                              ReviewerCode = dociorc.ReviewerCode,
                                              Downtime = enroll.Downtime,
                                          };
            return await costStatisticsQueryable.ToPagedListAsync(challengeQuery.PageIndex, challengeQuery.PageSize, "ChineseName");



            //var query2 = _repository.Where<EnrollViewModel>(x => x.TrialId == challengeQuery.TrialId)
            //    .WhereIf(challengeQuery.TrialId != null, t => t.TrialId == challengeQuery.TrialId)
            //    .WhereIf(challengeQuery.DoctorId != null, t => t.DoctorId == challengeQuery.DoctorId)

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

            //var pageList = await query2.ToListAsync();


            //    return new PageOutput<EnrollViewModel>(challengeQuery.pageIndex, challengeQuery.pageSize,
            //costStatisticsQueryable);


        }


        #region Reviewer 入组审核流程(select-submit-approve-confirm)

        /// <summary> 为项目筛选医生 提交 【select】 </summary>
        /// <param name="trialId">项目Id</param>
        /// <param name="doctorIdArray">医生Id数组</param>
        /// <returns></returns>

        [HttpPost("{trialId:guid}")]
         [TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
        public async Task<IResponseOutput> SelectReviewers(Guid trialId, Guid[] doctorIdArray)
        {
            var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);

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

            //_trialRepository.Attach(trial);

            //更新项目状态
            trial.TrialEnrollStatus = (int)TrialEnrollStatus.HasApplyDownLoadResume;

            //_trialRepository.Update(trial);

            //添加项目状态变化记录
            var trialDetail = new TrialStatusDetail()
            {
                TrialId = trial.Id,
                TrialStatus = (int)TrialEnrollStatus.HasApplyDownLoadResume,
            };
            await _trialDetailRepository.AddAsync(trialDetail);

            // 入组表  入组状态跟踪表
            foreach (var doctorId in doctorIdArray)
            {
                await _enrollRepository.AddAsync(new Enroll()
                {
                    DoctorId = doctorId,
                    TrialId = trialId,
                    EnrollStatus = EnrollStatus.HasApplyDownloadResume,

                    DoctorUserId = _repository.Where<User>(t => t.DoctorId == doctorId).Select(t => t.Id).FirstOrDefault()
                }); ;

                await _enrollDetailRepository.AddAsync(new EnrollDetail()
                {
                    DoctorId = doctorId,
                    TrialId = trialId,
                    EnrollStatus = EnrollStatus.HasApplyDownloadResume,
                    OptUserType = (int)SystemUserType.AdminUser,
                });
            }

            return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());

        }

        /// <summary>
        /// 入组流程-向CRO提交医生[Submit]
        /// </summary>

        [HttpPost("{trialId:guid}/{commitState:int}")]
         [TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
        public async Task<IResponseOutput> SubmitReviewer(Guid trialId, Guid[] doctorIdArray, int commitState)
        {

            var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);


            if (trial != null)
            {
                if (commitState == 1) //确认提交CRO
                {
                    //更新项目状态
                    trial.TrialEnrollStatus = (int)TrialEnrollStatus.HasCommitCRO;

                    //添加项目详细记录
                    var trialDetail = new TrialStatusDetail()
                    {
                        TrialId = trial.Id,
                        TrialStatus = (int)TrialEnrollStatus.HasCommitCRO
                    };
                    await _trialDetailRepository.AddAsync(trialDetail);

                    //更新入组表  跟踪了 所以不用下面的_enrollRepository.Update(intoGroupItem);
                    var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId, true).ToListAsync();

                    foreach (var intoGroupItem in intoGroupList)
                    {
                        if (doctorIdArray.Contains(intoGroupItem.DoctorId))
                        {
                            intoGroupItem.EnrollStatus = EnrollStatus.HasCommittedToCRO;
                            //_enrollRepository.Update(intoGroupItem);

                            await _enrollDetailRepository.AddAsync(new EnrollDetail()
                            {
                                TrialDetailId = trialDetail.Id,
                                DoctorId = intoGroupItem.DoctorId,
                                TrialId = trialId,
                                EnrollStatus = EnrollStatus.HasCommittedToCRO,
                                OptUserType = (int)SystemUserType.AdminUser, //后台用户
                            });
                        }
                    }


                }
                else if (commitState == 0)//回退上一步
                {
                    //更新入组表
                    var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId, true).ToListAsync();

                    foreach (var intoGroupItem in intoGroupList)
                    {
                        if (doctorIdArray.Contains(intoGroupItem.DoctorId))
                        {
                            intoGroupItem.EnrollStatus = EnrollStatus.HasApplyDownloadResume;

                            //_enrollRepository.Update(intoGroupItem);


                            var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
                                t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
                                t.EnrollStatus == EnrollStatus.HasCommittedToCRO);

                            await _enrollDetailRepository.DeleteAsync(deleteItem);
                        }
                    }


                }
                return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());
            }
            //$"Cannot find trial {trialId}"
            return ResponseOutput.NotOk(_localizer["Enroll_NotFound", trialId]);
        }

        /// <summary>
        /// 入组流程-CRO确定医生名单 [ Approve]
        /// </summary>

        [HttpPost("{trialId:guid}/{auditState:int}")]
         [TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
        public async Task<IResponseOutput> ApproveReviewer(Guid trialId, Guid[] doctorIdArray, int auditState)
        {

            var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);

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

            if (auditState == 1) //确认入组
            {
                //var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames);
                //if (existItem == null)
                //{
                //    trial.TrialStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames;
                //    trial.TrialStatusStr = "Approved";
                //}
                //_trialRepository.Update(trial);

                //更新项目状态
                trial.TrialEnrollStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames;

                //添加项目详细记录
                var trialDetail = new TrialStatusDetail()
                {
                    TrialId = trialId,
                    TrialStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames
                };
              await  _trialDetailRepository.AddAsync(trialDetail);

                //更新入组表 跟踪方式,不用下面的_enrollRepository.Update(intoGroupItem);
                var intoGroupList = _enrollRepository.Where(t => t.TrialId == trialId, true).ToList();


                foreach (var intoGroupItem in intoGroupList)
                {
                    if (doctorIdArray.Contains(intoGroupItem.DoctorId))
                    {
                        intoGroupItem.EnrollStatus = EnrollStatus.InviteIntoGroup;
                        //_enrollRepository.Update(intoGroupItem);

                        await _enrollDetailRepository.AddAsync(new EnrollDetail()
                        {
                            DoctorId = intoGroupItem.DoctorId,
                            TrialId = trialId,
                            EnrollStatus = EnrollStatus.InviteIntoGroup,
                            OptUserType = (int)SystemUserType.AdminUser, //后台用户
                        });
                    }
                }

            }
            else if (auditState == 0)//回退上一步
            {
                //更新入组表
                var intoGroupList = _enrollRepository.Where(t => t.TrialId == trialId, true).ToList();

                foreach (var intoGroupItem in intoGroupList)
                {
                    if (doctorIdArray.Contains(intoGroupItem.DoctorId))
                    {
                        intoGroupItem.EnrollStatus = EnrollStatus.HasCommittedToCRO;

                        //_enrollRepository.Update(intoGroupItem);

                        var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
                        t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
                        t.EnrollStatus == EnrollStatus.InviteIntoGroup);

                        await _enrollDetailRepository.DeleteAsync(deleteItem);
                    }
                }

     
            }
            return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());



        }

        /// <summary>
        /// 入组流程-后台确认医生入组[Confirm]
        /// </summary>

        [HttpPost]
         [TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
        [UnitOfWork]
        public async Task<IResponseOutput> ConfirmReviewer(ConfirmReviewerCommand confirmReviewerCommand,
            [FromServices] IRepository<TrialUser> _trialUserRepository,
             [FromServices] IRepository<TaskAllocationRule> _taskAllocationRuleRepository)
        {
            //var trial = _trialRepository.FirstOrDefault(t => t.Id == trialId);
            //var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames);

            //trial.TrialStatusStr = "Reading";
            ////trial.TrialStatus = (int)TrialStatus.HasConfirmedDoctorNames;
            //_trialRepository.Update(trial);

            var trialId = confirmReviewerCommand.TrialId;

            var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);

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


            //更新入组表
            var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId,true).ToListAsync();

            //验证邮件
            var emaiList = await _doctorRepository.Where(t => intoGroupList.Select(t => t.DoctorId).Contains(t.Id))
                .Select(t => new { t.EMail, t.FirstName, t.LastName }).ToListAsync();


            var errorList = emaiList.Where(t => !Regex.IsMatch(t.EMail, @"^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$"))
                .ToList();

            if (errorList.Count() > 0)
            {
                // errorList.Select(c => c.LastName+" / "+c.FirstName)) +"邮箱格式存在问题"
                return ResponseOutput.NotOk(string.Join(',', _localizer["Enroll_EmailFormat"], errorList.Select(c => c.LastName + " / " + c.FirstName))) ;
            }

            if (confirmReviewerCommand.ConfirmState == 1) //确认入组
            {
                foreach (var intoGroupItem in intoGroupList)
                {
                    if (confirmReviewerCommand.DoctorIdArray.Contains(intoGroupItem.DoctorId))
                    {

                        //当邮件发送没有问题的时候,才修改状态  如果有问题,就当前不做处理
                        try
                        {
                            var userId = await _mailVerificationService.DoctorJoinTrialEmail(trialId, intoGroupItem.DoctorId, confirmReviewerCommand.BaseUrl, confirmReviewerCommand.RouteUrl);

                            if (!await _trialUserRepository.AnyAsync(t => t.TrialId == trialId && t.UserId == userId, true))
                            {
                                await _trialUserRepository.AddAsync(new TrialUser() { TrialId = trialId, UserId = userId, JoinTime = DateTime.Now });
                            }

                            await _enrollRepository.BatchUpdateNoTrackingAsync(t => t.Id == intoGroupItem.Id, u => new Enroll() { DoctorUserId = userId });

                            if (!await _taskAllocationRuleRepository.AnyAsync(t => t.TrialId == trialId && t.DoctorUserId == userId && t.EnrollId == intoGroupItem.Id, true))
                            {
                                await _taskAllocationRuleRepository.AddAsync(new TaskAllocationRule() { TrialId = trialId, DoctorUserId = userId, EnrollId = intoGroupItem.Id });

                            }

                            await _enrollDetailRepository.AddAsync(new EnrollDetail()
                            {
                                DoctorId = intoGroupItem.DoctorId,
                                TrialId = trialId,
                                EnrollStatus = EnrollStatus.ConfirmIntoGroup,
                                OptUserType = (int)SystemUserType.AdminUser, //后台用户
                            });

                            intoGroupItem.EnrollStatus = EnrollStatus.ConfirmIntoGroup;
                            intoGroupItem.EnrollTime = DateTime.Now;
                        }
                        catch (Exception )
                        {
                            intoGroupItem.EnrollStatus = EnrollStatus.ConfirmIntoGroupFailed;

                        }
                                        
                    }
                }
              
            }
            else if (confirmReviewerCommand.ConfirmState == 0)//回退上一步
            {
                foreach (var intoGroupItem in intoGroupList)
                {
                    if (confirmReviewerCommand.DoctorIdArray.Contains(intoGroupItem.DoctorId))
                    {
                        intoGroupItem.EnrollStatus = EnrollStatus.InviteIntoGroup;
                        intoGroupItem.EnrollTime = null;


                        var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
                              t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
                              t.EnrollStatus == EnrollStatus.ConfirmIntoGroup);

                        await _enrollDetailRepository.DeleteAsync(deleteItem);
                    }
                }

               
            }

            await _enrollRepository.SaveChangesAsync();
            return ResponseOutput.Ok();

        }



        /// <summary>
        /// optType  0表示入组,列表没这条数据了, 1表示出组,需要填写出组时间  废弃
        /// </summary>
        /// <param name="trialId"></param>
        /// <param name="doctorId"></param>
        /// <param name="optType"></param>
        /// <param name="outEnrollTime"></param>
        /// <returns></returns>
        [HttpPost("{trialId:guid}/{doctorId:guid}/{optType:int}")]
         [TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "AfterStopCannNotOpt" })]
        //[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM)]
        [Obsolete]
        public async Task<IResponseOutput> EnrollBackOrOut(Guid trialId, Guid doctorId, int optType, DateTime? outEnrollTime)
        {
            var intoGroupItem = await _enrollRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.DoctorId == doctorId);
            if (optType == 0)
            {
                var sum = _workloadRepository.Where(t =>
                          t.TrialId == trialId && t.DoctorId == doctorId &&
                          t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm)
                       .Sum(u => u.Adjudication + u.AdjudicationIn24H + u.AdjudicationIn48H + u.Timepoint +
                                 u.TimepointIn24H + u.TimepointIn48H + u.RefresherTraining + u.Training + u.Global +
                                 u.Downtime);
                if (sum != 0)
                {
                //---Reviewers with workload cannot go back
                    return ResponseOutput.NotOk(_localizer["Enroll_CannotRollback"]);
                }

                intoGroupItem.EnrollStatus = EnrollStatus.InviteIntoGroup;
                intoGroupItem.EnrollTime = null;

                var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
                   t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
                   t.EnrollStatus == EnrollStatus.ConfirmIntoGroup);

                await _enrollDetailRepository.DeleteAsync(deleteItem);

            }
            else if (optType == 1)
            {
                intoGroupItem.OutEnrollTime = outEnrollTime;
            }
            return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());
        }
        #endregion

    }
}