private static object GetCustomExpressionValue(Account account, ClientPayloadData payloadData,
                                                       string keyExpression)
        {
            //e.g. keyExpression can be $.Extra.active or $.Balance or $.Payload.Amount, etc
            //see https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm
            JObject extraJson = null;

            if (!string.IsNullOrEmpty(account.Extra))
            {
                extraJson = JObject.Parse(account.Extra);
            }

            var json = JObject.Parse(JsonConvert.SerializeObject(new
            {
                account.AccountNumber,
                account.Balance,
                account.Alias,
                account.CreatedAt,
                Extra   = extraJson,
                Payload = payloadData
            }));

            var result = json.SelectToken(keyExpression);

            return(result.ToObject <object>());
        }
        private static bool EvaluateConditions(Account account, List <Condition> conditions, ClientPayloadData payloadData, decimal sumOfCreditTransactions = 0, long countOfCreditTransactions = 0, decimal sumOfDebitTransactions = 0, long countOfDebitTransactions = 0, long countOfTransactions = 0)
        {
            bool conditionResult;

            ConditionConnector previousOperator = ConditionConnector.None;

            Expression previousExpression = null;
            Expression finalExpression    = null;

            foreach (var condition in conditions)
            {
                //var activityConditionComparatorValue = JsonConvert.DeserializeObject<ActivityConditionComparatorValue>(condition.ConditionValue);

                object activityConditionKey;
                switch (condition.Key)
                {
                case  ComparatorKey.Balance:

                    activityConditionKey = account.Balance;
                    break;

                case ComparatorKey.CreditTransactionsCount:

                    activityConditionKey = countOfCreditTransactions;
                    break;

                case ComparatorKey.CreditTransactionsSum:

                    activityConditionKey = sumOfCreditTransactions;
                    break;

                case ComparatorKey.DebitTransactionsCount:
                    activityConditionKey = countOfDebitTransactions;
                    break;

                case ComparatorKey.DebitTransactionsSum:

                    activityConditionKey = sumOfDebitTransactions;
                    break;

                case ComparatorKey.TransactionsCount:
                    activityConditionKey = countOfTransactions;
                    break;

                case ComparatorKey.Custom:
                    //pick from Extras on Account object
                    var v = GetCustomExpressionValue(account, payloadData,
                                                     condition.KeyExpression);


                    activityConditionKey = v;
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                Expression leftExpression = Expression.Constant(activityConditionKey,
                                                                activityConditionKey.GetType());

                var convertedValueType = Convert.ChangeType(condition.Value, activityConditionKey.GetType());
                var rightConstant      = Expression.Constant(convertedValueType, activityConditionKey.GetType());

                switch (condition.Type)
                {
                case ComparatorType.EqualTo:


                    Expression eqleft = leftExpression;

                    //Expression eqright = Expression.Constant(condition.Value,condition.Value.GetType());
                    Expression eqright = rightConstant;

                    Expression eqResult = Expression.Equal(eqleft,
                                                           eqright);

                    if (previousOperator == ConditionConnector.And)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.And(finalExpression,
                                                             eqResult);
                        }
                        else
                        {
                            finalExpression = Expression.And(previousExpression,
                                                             eqResult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.Or)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.Or(finalExpression,
                                                            eqResult);
                        }
                        else
                        {
                            finalExpression = Expression.Or(previousExpression,
                                                            eqResult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.None)
                    {
                        if (finalExpression != null)
                        {
                        }
                        else
                        {
                            finalExpression = eqResult;
                        }
                    }
                    previousExpression = eqResult;
                    break;

                case ComparatorType.GreaterThan:

                    //Expression gtleft = Expression.PropertyOrField(cachedCopy, whereClauseItem.Field);
                    Expression gtleft = leftExpression;
                    //Expression gtright = Expression.Constant(condition.Value,condition.Value.GetType());
                    Expression gtright  = rightConstant;
                    Expression gtresult = Expression.GreaterThan(gtleft,
                                                                 gtright);

                    if (previousOperator == ConditionConnector.And)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.And(finalExpression,
                                                             gtresult);
                        }
                        else
                        {
                            finalExpression = Expression.And(previousExpression,
                                                             gtresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.Or)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.Or(finalExpression,
                                                            gtresult);
                        }
                        else
                        {
                            finalExpression = Expression.Or(previousExpression,
                                                            gtresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.None)
                    {
                        if (finalExpression != null)
                        {
                        }
                        else
                        {
                            finalExpression = gtresult;
                        }
                    }

                    previousExpression = gtresult;
                    break;

                case ComparatorType.LessThan:

                    //Expression ltleft = Expression.PropertyOrField(cachedCopy, whereClauseItem.Field);
                    Expression ltleft = leftExpression;
                    //Expression ltright = Expression.Constant(condition.Value,condition.Value.GetType());
                    Expression ltright  = rightConstant;
                    Expression ltresult = Expression.LessThan(ltleft,
                                                              ltright);

                    if (previousOperator == ConditionConnector.And)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.And(finalExpression,
                                                             ltresult);
                        }
                        else
                        {
                            finalExpression = Expression.And(previousExpression,
                                                             ltresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.Or)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.Or(finalExpression,
                                                            ltresult);
                        }
                        else
                        {
                            finalExpression = Expression.Or(previousExpression,
                                                            ltresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.None)
                    {
                        if (finalExpression != null)
                        {
                        }
                        else
                        {
                            finalExpression = ltresult;
                        }
                    }
                    previousExpression = ltresult;
                    break;

                case ComparatorType.GreaterThanOrEqualTo:
                    //Expression gtoreqleft = Expression.PropertyOrField(cachedCopy, whereClauseItem.Field);
                    Expression gtoreqleft = leftExpression;
                    //Expression gtoreqright = Expression.Constant(condition.Value,condition.Value.GetType());
                    Expression gtoreqright  = rightConstant;
                    Expression gtoreqresult = Expression.LessThanOrEqual(gtoreqleft,
                                                                         gtoreqright);

                    if (previousOperator == ConditionConnector.And)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.And(finalExpression,
                                                             gtoreqresult);
                        }
                        else
                        {
                            finalExpression = Expression.And(previousExpression,
                                                             gtoreqresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.Or)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.Or(finalExpression,
                                                            gtoreqresult);
                        }
                        else
                        {
                            finalExpression = Expression.Or(previousExpression,
                                                            gtoreqresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.None)
                    {
                        if (finalExpression != null)
                        {
                        }
                        else
                        {
                            finalExpression = gtoreqresult;
                        }
                    }

                    previousExpression = gtoreqresult;
                    break;

                case ComparatorType.LessThanOrEqualTo:

                    // Expression ltoreqleft = Expression.PropertyOrField(cachedCopy, whereClauseItem.Field);
                    Expression ltoreqleft = leftExpression;
                    //Expression ltoreqright = Expression.Constant(condition.Value,condition.Value.GetType());
                    Expression ltoreqright  = rightConstant;
                    Expression ltoreqresult = Expression.LessThanOrEqual(ltoreqleft,
                                                                         ltoreqright);

                    if (previousOperator == ConditionConnector.And)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.And(finalExpression,
                                                             ltoreqresult);
                        }
                        else
                        {
                            finalExpression = Expression.And(previousExpression,
                                                             ltoreqresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.Or)
                    {
                        if (finalExpression != null)
                        {
                            finalExpression = Expression.Or(finalExpression,
                                                            ltoreqresult);
                        }
                        else
                        {
                            finalExpression = Expression.Or(previousExpression,
                                                            ltoreqresult);
                        }
                    }
                    else if (previousOperator == ConditionConnector.None)
                    {
                        if (finalExpression != null)
                        {
                        }
                        else
                        {
                            finalExpression = ltoreqresult;
                        }
                    }
                    previousExpression = ltoreqresult;
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                previousOperator = condition.ConditionConnector;
            }



            if (finalExpression != null)
            {
                var t = Expression.Condition(finalExpression,
                                             Expression.Constant(true),
                                             Expression.Constant(false));

                conditionResult = Expression.Lambda <Func <decimal, bool> >(t, new ParameterExpression[] { Expression.Parameter(typeof(decimal)) }).Compile()(decimal.Zero);
            }
            else
            {
                conditionResult = false;
            }



            return(conditionResult);
        }
        public static List <int> EvaluateConditionAndGetOutcomeIds(Account account, List <Condition> conditions, ClientPayloadData payloadData, decimal sumOfCreditTransactions = 0, long countOfCreditTransactions = 0, decimal sumOfDebitTransactions = 0, long countOfDebitTransactions = 0, long countOfTransactions = 0)
        {
            //Log(CommonLogLevel.Info, $"received request to {nameof(DoGetCount)} for {_tableName}", null);
            try
            {
                //bool conditionResult;


                //we have to group the conditions in steps that belong to the same outcome
                //var conditions = activity.Conditions.Where(c => c.Active).ToList();


                var steps = conditions.GroupBy(k => k.OutcomeId);

                var stepResults = new List <Tuple <bool, int> >();
                foreach (var step in steps)
                {
                    var stepConditions = step.Where(c => c.Active);

                    var exeResult = EvaluateConditions(account, stepConditions.ToList(), payloadData, sumOfCreditTransactions, countOfCreditTransactions, sumOfDebitTransactions, countOfDebitTransactions, countOfTransactions);

                    stepResults.Add(new Tuple <bool, int>(exeResult,
                                                          step.Key.Value));
                }

                var res = stepResults.Where(s => s.Item1);

                if (!res.Any())
                {
                    return(new List <int>());
                }

                return(res.Select(r => r.Item2).ToList());
            }
            catch (Exception e) { return(new List <int>()); }
        }