

using IRaCIS.Core.Domain;
using IRaCIS.Core.Domain.BaseModel;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure.Extention;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Newtonsoft.Json;

namespace IRaCIS.Core.Infra.EFCore;



public static class DBContext_Ext
{
    public static void AddDomainEvents(this DbContext context)
    {
        var dbContext = (IRaCISDBContext)context;

        var changeTracker = context.ChangeTracker;

        //记录要保存到数据库的事件
        var eventStoreList = new List<EventStoreRecord>();

        #region 中心调研邮件通知

        foreach (var entry in changeTracker.Entries<TrialSiteSurvey>())
        {
            var trialSiteSurvey = entry.Entity;

            var originState = entry.Property(p => p.State).OriginalValue;

            //状态从待提交 变为CRC提交  （驳回也会变为已提交，所以必须设置前置状态是待提交）
            if (trialSiteSurvey.State == TrialSiteSurveyEnum.CRCSubmitted && originState == TrialSiteSurveyEnum.ToSubmit)
            {
                trialSiteSurvey.AddDomainEvent(new UserSiteSurveySubmitedEvent() { TrialSiteSurveyId = trialSiteSurvey.Id });
            }

            //SPM CPM 提交的时候
            else if (trialSiteSurvey.State == TrialSiteSurveyEnum.SPMApproved && originState == TrialSiteSurveyEnum.CRCSubmitted)
            {
                trialSiteSurvey.AddDomainEvent(new SiteSurveySPMSubmitedEvent() { TrialSiteSurveyId = trialSiteSurvey.Id });
            }

            //PM 驳回 
            else if ((trialSiteSurvey.State == TrialSiteSurveyEnum.CRCSubmitted || trialSiteSurvey.State == TrialSiteSurveyEnum.ToSubmit) && originState == TrialSiteSurveyEnum.SPMApproved)
            {
                trialSiteSurvey.AddDomainEvent(new SiteSurverRejectedEvent() { TrialSiteSurveyId = trialSiteSurvey.Id, IsHaveSPMOrCPM = trialSiteSurvey.State == TrialSiteSurveyEnum.CRCSubmitted });
            }
            //SPM 驳回
            else if (trialSiteSurvey.State == TrialSiteSurveyEnum.ToSubmit && originState == TrialSiteSurveyEnum.CRCSubmitted)
            {
                trialSiteSurvey.AddDomainEvent(new SiteSurverRejectedEvent() { TrialSiteSurveyId = trialSiteSurvey.Id, IsHaveSPMOrCPM = true });
            }

            //添加进记录
            eventStoreList.AddRange(GetStoreEvents(trialSiteSurvey.DomainEvents));
        }


        #endregion


        #region PD 入组发送邮件（不侵入之前的代码，有些判断过于复杂的，在代码里面有的，就手动 在跟踪的实体添加领域事件）

        foreach (var entry in changeTracker.Entries<SubjectVisit>())
        {
            var subjectVisit = entry.Entity;

            var originSubmitState = entry.Property(p => p.SubmitState).OriginalValue;
            var originAuditState = entry.Property(p => p.AuditState).OriginalValue;
            var originCheckState = entry.Property(p => p.CheckState).OriginalValue;

            //入组或者PD 才执行下面的逻辑
            if ((subjectVisit.IsEnrollmentConfirm || subjectVisit.PDState == PDStateEnum.PDProgress))
            {
                //质控状态变为待审核的时候

                if (originSubmitState == SubmitStateEnum.ToSubmit && subjectVisit.SubmitState == SubmitStateEnum.Submitted &&
                    originAuditState == AuditStateEnum.None && subjectVisit.AuditState == AuditStateEnum.ToAudit
                    )
                {
                    subjectVisit.AddDomainEvent(new CRCSubmitedAndQCToAuditEvent() { SubjectVisitId = subjectVisit.Id });
                }

                //一致性核查通知PM发送邮件
                if (originCheckState == CheckStateEnum.None && subjectVisit.CheckState == CheckStateEnum.ToCheck
                   )
                {
                    subjectVisit.AddDomainEvent(new CheckStateChangedToAuditEvent() { SubjectVisitId = subjectVisit.Id });
                }

                //添加进记录
                eventStoreList.AddRange(GetStoreEvents(subjectVisit.DomainEvents));
            }

        }

        foreach (var entry in changeTracker.Entries<QCChallengeDialog>())
        {
            var qCChallengeDialog = entry.Entity;

            var findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == qCChallengeDialog.SubjectVisitId)
                        .Select(t => new { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState, t.Id, t.TrialId }).FirstOrDefault().IfNullThrowException();

            //入组或者PD 才执行下面的逻辑
            if ((findSubjectVisit.IsEnrollmentConfirm || findSubjectVisit.PDState == PDStateEnum.PDProgress))
            {
                //CRC 针对质控质疑进行回复
                if (entry.State == EntityState.Added && qCChallengeDialog.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator)
                {
                    qCChallengeDialog.AddDomainEvent(new CRCRepliedQCChallengeEvent() { QCChallengeDialogId = qCChallengeDialog.Id, SubjectVisitId = findSubjectVisit.Id, TrialId = findSubjectVisit.TrialId });
                }
                //QC 针对质控质疑进行回复
                else if (entry.State == EntityState.Added && qCChallengeDialog.UserTypeEnum == UserTypeEnum.IQC)
                {
                    qCChallengeDialog.AddDomainEvent(new QCRepliedQCChallengeEvent() { QCChallengeDialogId = qCChallengeDialog.Id, SubjectVisitId = findSubjectVisit.Id, TrialId = findSubjectVisit.TrialId });

                }

                //添加进记录
                eventStoreList.AddRange(GetStoreEvents(qCChallengeDialog.DomainEvents));
            }

        }

        foreach (var entry in changeTracker.Entries<CheckChallengeDialog>())
        {
            var checkChallengeDialog = entry.Entity;

            var findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == checkChallengeDialog.SubjectVisitId)
                        .Select(t => new { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState, t.Id, t.TrialId }).FirstOrDefault().IfNullThrowException();

            //入组或者PD 才执行下面的逻辑
            if ((findSubjectVisit.IsEnrollmentConfirm || findSubjectVisit.PDState == PDStateEnum.PDProgress))
            {
                //CRC 针对质控质疑进行回复
                if (entry.State == EntityState.Added && checkChallengeDialog.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator)
                {
                    checkChallengeDialog.AddDomainEvent(new CRCRepliedCheckChallengeEvent() { CheckChallengeDialogId = checkChallengeDialog.Id, SubjectVisitId = findSubjectVisit.Id, TrialId = findSubjectVisit.TrialId });
                }
                else if (entry.State == EntityState.Added && checkChallengeDialog.UserTypeEnum == UserTypeEnum.ProjectManager)
                {
                    checkChallengeDialog.AddDomainEvent(new PMRepliedCheckChallengeEvent() { CheckChallengeDialogId = checkChallengeDialog.Id, SubjectVisitId = findSubjectVisit.Id, TrialId = findSubjectVisit.TrialId });
                }

                //添加进记录
                eventStoreList.AddRange(GetStoreEvents(checkChallengeDialog.DomainEvents));
            }

        }


        //医学审核任务
        foreach (var entry in changeTracker.Entries<TaskMedicalReview>())
        {
            var taskMedicalReview = entry.Entity;

            if (entry.State == EntityState.Added)
            {
                var findVisitTask = dbContext.VisitTask.Where(t => t.Id == taskMedicalReview.VisitTaskId).Select(t => new { t.SourceSubjectVisitId, t.SouceReadModuleId }).FirstOrDefault().IfNullThrowException();

                var findSubjectVisit = new EnrollmentConfirmAndPD();
                if (findVisitTask.SourceSubjectVisitId != null)
                {
                    findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == findVisitTask.SourceSubjectVisitId)
                            .Select(t => new EnrollmentConfirmAndPD { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState }).FirstOrDefault();
                }
                else
                {
                    var subjectVisitId = dbContext.ReadModule.Where(t => t.Id == findVisitTask.SouceReadModuleId).Select(t => t.SubjectVisitId).FirstOrDefault();

                    findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == subjectVisitId)
                        .Select(t => new EnrollmentConfirmAndPD { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState }).FirstOrDefault();
                }


                //入组或者PD 才执行下面的逻辑
                if (findSubjectVisit.IsEnrollmentConfirm || findSubjectVisit.PDState == PDStateEnum.PDProgress)
                {

                    taskMedicalReview.AddDomainEvent(new UrgentMedicalReviewAddedEvent() { MedicalReviewId = taskMedicalReview.Id, VisitTaskId = taskMedicalReview.VisitTaskId });

                    //添加进记录
                    eventStoreList.AddRange(GetStoreEvents(taskMedicalReview.DomainEvents));
                }
            }
        }

        //医学反馈
        foreach (var entry in changeTracker.Entries<ReadingMedicalReviewDialog>())
        {
            var readingMedicalReviewDialog = entry.Entity;



            var findVisitTask = dbContext.VisitTask.Where(t => t.Id == readingMedicalReviewDialog.VisitTaskId).Select(t => new { t.SourceSubjectVisitId, t.SouceReadModuleId }).FirstOrDefault().IfNullThrowException();

            var findSubjectVisit = new EnrollmentConfirmAndPD();
            if (findVisitTask.SourceSubjectVisitId != null)
            {
                findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == findVisitTask.SourceSubjectVisitId)
                        .Select(t => new EnrollmentConfirmAndPD { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState }).FirstOrDefault();
            }
            else
            {
                var subjectVisitId = dbContext.ReadModule.Where(t => t.Id == findVisitTask.SouceReadModuleId).Select(t => t.SubjectVisitId).FirstOrDefault();

                findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == subjectVisitId)
                    .Select(t => new EnrollmentConfirmAndPD { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState }).FirstOrDefault();
            }

            //入组或者PD 才执行下面的逻辑
            if (findSubjectVisit.IsEnrollmentConfirm || findSubjectVisit.PDState == PDStateEnum.PDProgress)
            {
                if (entry.State == EntityState.Added && readingMedicalReviewDialog.UserTypeEnumInt == (int)UserTypeEnum.MIM)
                {
                    readingMedicalReviewDialog.AddDomainEvent(new UrgentMIMRepliedMedicalReview() { ReadingMedicalReviewDialogId = readingMedicalReviewDialog.Id });
                }
                else if (entry.State == EntityState.Added && readingMedicalReviewDialog.UserTypeEnumInt == (int)UserTypeEnum.IndependentReviewer)
                {
                    readingMedicalReviewDialog.AddDomainEvent(new UrgentIRRepliedMedicalReview() { ReadingMedicalReviewDialogId = readingMedicalReviewDialog.Id });
                }

                //添加进记录
                eventStoreList.AddRange(GetStoreEvents(readingMedicalReviewDialog.DomainEvents));
            }

        }

        //任务 申请重阅ReReadingApplyState

        foreach (var entry in changeTracker.Entries<VisitTask>())
        {

            var visitTask = entry.Entity;

            var originReReadingApplyState = entry.Property(p => p.ReReadingApplyState).OriginalValue;

            if (originReReadingApplyState == ReReadingApplyState.Default && (visitTask.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed || visitTask.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed))
            {
                var findSubjectVisit = new EnrollmentConfirmAndPD();

                if (visitTask.SourceSubjectVisitId != null)
                {
                    findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == visitTask.SourceSubjectVisitId)
                        .Select(t => new EnrollmentConfirmAndPD { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState }).FirstOrDefault();
                }
                else
                {
                    var subjectVisitId = dbContext.ReadModule.Where(t => t.Id == visitTask.SouceReadModuleId).Select(t => t.SubjectVisitId).FirstOrDefault();

                    findSubjectVisit = dbContext.SubjectVisit.Where(t => t.Id == subjectVisitId)
                        .Select(t => new EnrollmentConfirmAndPD { IsEnrollmentConfirm = t.IsEnrollmentConfirm, PDState = t.PDState }).FirstOrDefault();
                }

                //入组或者PD 才执行下面的逻辑
                if (findSubjectVisit.IsEnrollmentConfirm || findSubjectVisit.PDState == PDStateEnum.PDProgress)
                {

                    visitTask.AddDomainEvent(new UrgentApplyedReReading() { VisitTaskId = visitTask.Id, ReReadingApplyState= visitTask.ReReadingApplyState });

                    //添加进记录
                    eventStoreList.AddRange(GetStoreEvents(visitTask.DomainEvents));
                }
            }

        }

        #endregion
        //跟随事务一起保存数据库
        dbContext.EventStoreRecord.AddRange(eventStoreList);
    }

    private static List<EventStoreRecord> GetStoreEvents(IReadOnlyCollection<DomainEvent> domainEvents)
    {
        return domainEvents.Select(t => new EventStoreRecord() { Id = t.EventId, EventType = t.GetType().AssemblyQualifiedName, EventTypeName=t.GetType().Name, EventData = t.ToJsonStr() }).ToList();
    }
    public class EnrollmentConfirmAndPD
    {
        public bool IsEnrollmentConfirm { get; set; }

        public PDStateEnum PDState { get; set; }
    }
    #region 暂时废弃
    /// <summary>
    /// 暂时废弃，没有场景使用
    /// </summary>
    /// <param name="context"></param>
    public static void AddDomainCommands(this DbContext context)
    {
        var changeTracker = context.ChangeTracker;





        //遍历 ChangeTracker 中的实体
        //foreach (var entry in changeTracker.Entries<UserLog>())
        //{
        //    var userLog = entry.Entity;

        //    if (entry.State == EntityState.Added)
        //    {
        //        // 受试者添加 触发访视自动添加
        //        var addCommand = new AddUserLogTriggerCommand { UserLog=userLog };

        //        userLog.AddDomainCommand(addCommand);
        //    }
        //}

        //foreach (var entry in changeTracker.Entries<Subject>())
        //{
        //    var subject = entry.Entity;

        //    if (entry.State == EntityState.Added)
        //    {
        //        // 受试者添加 触发访视自动添加
        //        var addedEvent = new AddSubjectTriggerCommand { SubjectId = subject.Id, TrialId = subject.TrialId, TrialSiteId = subject.TrialSiteId };

        //        subject.AddDomainCommand(addedEvent);
        //    }
        //}
    }

    #endregion

}