public Task ExecuteAsync(
            NhbkAction action,
            ActionContext context,
            INotificationSession notificationSession
            )
        {
            if (action.Type != ActionType)
            {
                throw new InvalidActionTypeException(action.Type, ActionType);
            }
            if (action.Data?.Modifier == null)
            {
                throw new InvalidActionDataException(action.Type);
            }

            var modifier          = action.Data.Modifier;
            var characterModifier = new CharacterModifier
            {
                Name                = modifier.Name,
                Permanent           = false,
                DurationType        = modifier.DurationType,
                Duration            = modifier.Duration,
                Type                = modifier.Type,
                Description         = modifier.Description,
                Reusable            = modifier.Reusable,
                IsActive            = true,
                CombatCount         = modifier.CombatCount,
                CurrentCombatCount  = modifier.CombatCount,
                TimeDuration        = modifier.TimeDuration,
                CurrentTimeDuration = modifier.TimeDuration,
                LapCount            = modifier.LapCount,
                CurrentLapCount     = modifier.LapCount,
                Values              = modifier.Values.Select(v => new CharacterModifierValue
                {
                    Type     = v.Type,
                    StatName = v.Stat,
                    Value    = v.Value
                }).ToList()
            };

            if (context.TargetCharacter.Modifiers == null)
            {
                context.TargetCharacter.Modifiers = new List <CharacterModifier>();
            }

            context.TargetCharacter.Modifiers.Add(characterModifier);

            context.TargetCharacter.AddHistoryEntry(_characterHistoryUtil.CreateLogAddModifier(context.TargetCharacter, characterModifier));
            notificationSession.NotifyCharacterAddModifier(context.TargetCharacter.Id, characterModifier, true);

            return(Task.CompletedTask);
        }
        public async Task ExecuteAsync(
            NhbkAction action,
            ActionContext context,
            INotificationSession notificationSession
            )
        {
            if (action.Type != ActionType)
            {
                throw new InvalidActionTypeException(action.Type, ActionType);
            }
            if (action.Data == null)
            {
                throw new InvalidActionDataException(action.Type);
            }
            if (!action.Data.EffectId.HasValue)
            {
                throw new InvalidActionDataException(action.Type);
            }
            if (action.Data.EffectData == null)
            {
                throw new InvalidActionDataException(action.Type);
            }

            var effect = await context.UnitOfWork.Effects.GetWithEffectWithModifiersAsync(action.Data.EffectId.Value);

            if (effect == null)
            {
                throw new EffectNotFoundException();
            }

            var combatCount  = effect.CombatCount;
            var timeDuration = effect.TimeDuration;
            var duration     = effect.Duration;
            var lapCount     = effect.LapCount;

            var customDurationType = action.Data.EffectData.Value <string?>("durationType");

            if (!string.IsNullOrEmpty(customDurationType))
            {
                timeDuration = null;
                duration     = null;
                combatCount  = null;
                lapCount     = null;
                switch (customDurationType)
                {
                case "combat":
                    combatCount = action.Data.EffectData.Value <int?>("combatCount");
                    break;

                case "time":
                    timeDuration = action.Data.EffectData.Value <int?>("timeDuration");
                    break;

                case "custom":
                    duration = action.Data.EffectData.Value <string>("duration");
                    break;

                case "lap":
                    lapCount = action.Data.EffectData.Value <int?>("lapCount");
                    break;

                case "forever":
                    break;

                default:
                    throw new InvalidCustomDurationActionException(customDurationType);
                }
            }



            var characterModifier = new CharacterModifier
            {
                Name                = effect.Name,
                Permanent           = false,
                DurationType        = customDurationType ?? effect.DurationType,
                Duration            = duration,
                Type                = effect.SubCategory.Name,
                Description         = effect.Description,
                Reusable            = false,
                IsActive            = true,
                CombatCount         = combatCount,
                CurrentCombatCount  = combatCount,
                TimeDuration        = timeDuration,
                CurrentTimeDuration = timeDuration,
                LapCount            = lapCount,
                CurrentLapCount     = lapCount,
                Values              = effect.Modifiers.Select(v => new CharacterModifierValue
                {
                    Type     = v.Type,
                    StatName = v.StatName,
                    Value    = v.Value
                }).ToList()
            };

            if (context.TargetCharacter.Modifiers == null)
            {
                context.TargetCharacter.Modifiers = new List <CharacterModifier>();
            }

            context.TargetCharacter.Modifiers.Add(characterModifier);

            context.TargetCharacter.AddHistoryEntry(_characterHistoryUtil.CreateLogAddModifier(context.TargetCharacter, characterModifier));
            notificationSession.NotifyCharacterAddModifier(context.TargetCharacter.Id, characterModifier, true);
        }