@SuppressWarnings("unchecked")
  @Override
  public InternalAggregation reduce(InternalAggregation aggregation, ReduceContext reduceContext) {
    if (aggregation instanceof InternalMultiBucketAggregation) {
      @SuppressWarnings("rawtypes")
      InternalMultiBucketAggregation multiBucketsAgg = (InternalMultiBucketAggregation) aggregation;
      List<? extends Bucket> buckets = multiBucketsAgg.getBuckets();
      List<Bucket> newBuckets = new ArrayList<>();
      for (int i = 0; i < buckets.size(); i++) {
        InternalMultiBucketAggregation.InternalBucket bucket =
            (InternalMultiBucketAggregation.InternalBucket) buckets.get(i);
        InternalAggregation aggToAdd = doReduce(bucket.getAggregations(), reduceContext);
        List<InternalAggregation> aggs =
            StreamSupport.stream(bucket.getAggregations().spliterator(), false)
                .map(
                    (p) -> {
                      return (InternalAggregation) p;
                    })
                .collect(Collectors.toList());
        aggs.add(aggToAdd);
        InternalMultiBucketAggregation.InternalBucket newBucket =
            multiBucketsAgg.createBucket(new InternalAggregations(aggs), bucket);
        newBuckets.add(newBucket);
      }

      return multiBucketsAgg.create(newBuckets);
    } else if (aggregation instanceof InternalSingleBucketAggregation) {
      InternalSingleBucketAggregation singleBucketAgg =
          (InternalSingleBucketAggregation) aggregation;
      InternalAggregation aggToAdd = doReduce(singleBucketAgg.getAggregations(), reduceContext);
      List<InternalAggregation> aggs =
          StreamSupport.stream(singleBucketAgg.getAggregations().spliterator(), false)
              .map(
                  (p) -> {
                    return (InternalAggregation) p;
                  })
              .collect(Collectors.toList());
      aggs.add(aggToAdd);
      return singleBucketAgg.create(new InternalAggregations(aggs));
    } else {
      throw new IllegalStateException(
          "Aggregation ["
              + aggregation.getName()
              + "] must be a bucket aggregation ["
              + aggregation.type().name()
              + "]");
    }
  }
  @Override
  public InternalAggregation reduce(InternalAggregation aggregation, ReduceContext reduceContext) {
    InternalMultiBucketAggregation<
            InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket>
        originalAgg =
            (InternalMultiBucketAggregation<
                    InternalMultiBucketAggregation, InternalMultiBucketAggregation.InternalBucket>)
                aggregation;
    List<? extends Bucket> buckets = originalAgg.getBuckets();

    CompiledScript compiledScript =
        reduceContext.scriptService().compile(script, ScriptContext.Standard.AGGS, reduceContext);
    List newBuckets = new ArrayList<>();
    for (Bucket bucket : buckets) {
      Map<String, Object> vars = new HashMap<>();
      if (script.getParams() != null) {
        vars.putAll(script.getParams());
      }
      boolean skipBucket = false;
      for (Map.Entry<String, String> entry : bucketsPathsMap.entrySet()) {
        String varName = entry.getKey();
        String bucketsPath = entry.getValue();
        Double value = resolveBucketValue(originalAgg, bucket, bucketsPath, gapPolicy);
        if (GapPolicy.SKIP == gapPolicy && (value == null || Double.isNaN(value))) {
          skipBucket = true;
          break;
        }
        vars.put(varName, value);
      }
      if (skipBucket) {
        newBuckets.add(bucket);
      } else {
        ExecutableScript executableScript =
            reduceContext.scriptService().executable(compiledScript, vars);
        Object returned = executableScript.run();
        if (returned == null) {
          newBuckets.add(bucket);
        } else {
          if (!(returned instanceof Number)) {
            throw new AggregationExecutionException(
                "series_arithmetic script for reducer [" + name() + "] must return a Number");
          }
          List<InternalAggregation> aggs =
              new ArrayList<>(eagerTransform(bucket.getAggregations().asList(), FUNCTION));
          aggs.add(
              new InternalSimpleValue(
                  name(),
                  ((Number) returned).doubleValue(),
                  formatter,
                  new ArrayList<PipelineAggregator>(),
                  metaData()));
          InternalMultiBucketAggregation.InternalBucket newBucket =
              originalAgg.createBucket(
                  new InternalAggregations(aggs),
                  (InternalMultiBucketAggregation.InternalBucket) bucket);
          newBuckets.add(newBucket);
        }
      }
    }
    return originalAgg.create(newBuckets);
  }