// Copyright (C) 2015 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.metrics.dropwizard;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.metrics.Description;
import com.google.gerrit.metrics.Field;

import com.codahale.metrics.Counter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.Meter;
import com.codahale.metrics.Metric;
import com.codahale.metrics.Snapshot;
import com.codahale.metrics.Timer;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

class MetricJson {
  String description;
  String unit;
  Boolean constant;
  Boolean rate;
  Boolean gauge;
  Boolean cumulative;

  Long count;
  Object value;

  Double rate_1m;
  Double rate_5m;
  Double rate_15m;
  Double rate_mean;

  Double p50;
  Double p75;
  Double p95;
  Double p98;
  Double p99;
  Double p99_9;

  Double min;
  Double avg;
  Double max;
  Double sum;
  Double std_dev;

  List<FieldJson> fields;
  Map<String, Object> buckets;

  MetricJson(Metric metric, ImmutableMap<String, String> atts, boolean dataOnly) {
    if (!dataOnly) {
      description = atts.get(Description.DESCRIPTION);
      unit = atts.get(Description.UNIT);
      constant = toBool(atts, Description.CONSTANT);
      rate = toBool(atts, Description.RATE);
      gauge = toBool(atts, Description.GAUGE);
      cumulative = toBool(atts, Description.CUMULATIVE);
    }
    init(metric, atts);
  }

  private void init(Metric metric, ImmutableMap<String, String> atts) {
    if (metric instanceof BucketedMetric) {
      BucketedMetric m = (BucketedMetric) metric;
      if (m.getTotal() != null) {
        init(m.getTotal(), atts);
      }

      Field<?>[] fieldList = m.getFields();
      fields = new ArrayList<>(fieldList.length);
      for (Field<?> f : fieldList) {
        fields.add(new FieldJson(f));
      }
      buckets = makeBuckets(fieldList, m.getCells(), atts);

    } else if (metric instanceof Counter) {
      Counter c = (Counter) metric;
      count = c.getCount();

    } else if (metric instanceof Gauge) {
      Gauge<?> g = (Gauge<?>) metric;
      value = g.getValue();

    } else if (metric instanceof Meter) {
      Meter m = (Meter) metric;
      count = m.getCount();
      rate_1m = m.getOneMinuteRate();
      rate_5m = m.getFiveMinuteRate();
      rate_15m = m.getFifteenMinuteRate();

    } else if (metric instanceof Timer) {
      Timer m = (Timer) metric;
      Snapshot s = m.getSnapshot();
      count = m.getCount();
      rate_1m = m.getOneMinuteRate();
      rate_5m = m.getFiveMinuteRate();
      rate_15m = m.getFifteenMinuteRate();

      double div =
          Description.getTimeUnit(atts.get(Description.UNIT)).toNanos(1);
      p50 = s.getMedian() / div;
      p75 = s.get75thPercentile() / div;
      p95 = s.get95thPercentile() / div;
      p98 = s.get98thPercentile() / div;
      p99 = s.get99thPercentile() / div;
      p99_9 = s.get999thPercentile() / div;

      min = s.getMin() / div;
      max = s.getMax() / div;
      std_dev = s.getStdDev() / div;

    } else if (metric instanceof Histogram) {
      Histogram m = (Histogram) metric;
      Snapshot s = m.getSnapshot();
      count = m.getCount();

      p50 = s.getMedian();
      p75 = s.get75thPercentile();
      p95 = s.get95thPercentile();
      p98 = s.get98thPercentile();
      p99 = s.get99thPercentile();
      p99_9 = s.get999thPercentile();

      min = (double) s.getMin();
      avg = (double) s.getMean();
      max = (double) s.getMax();
      sum = s.getMean() * m.getCount();
      std_dev = s.getStdDev();
    }
  }

  private static Boolean toBool(ImmutableMap<String, String> atts, String key) {
    return Description.TRUE_VALUE.equals(atts.get(key)) ? true : null;
  }

  @SuppressWarnings("unchecked")
  private static Map<String, Object> makeBuckets(
      Field<?>[] fields,
      Map<?, Metric> metrics,
      ImmutableMap<String, String> atts) {
    if (fields.length == 1) {
      Function<Object, String> fmt =
          (Function<Object, String>) fields[0].formatter();
      Map<String, Object> out = new TreeMap<>();
      for (Map.Entry<?, Metric> e : metrics.entrySet()) {
        out.put(
            fmt.apply(e.getKey()),
            new MetricJson(e.getValue(), atts, true));
      }
      return out;
    }

    Map<String, Object> out = new TreeMap<>();
    for (Map.Entry<?, Metric> e : metrics.entrySet()) {
      ImmutableList<Object> keys = (ImmutableList<Object>) e.getKey();
      Map<String, Object> dst = out;

      for (int i = 0; i < fields.length - 1; i++) {
        Function<Object, String> fmt =
            (Function<Object, String>) fields[i].formatter();
        String key = fmt.apply(keys.get(i));
        Map<String, Object> t = (Map<String, Object>) dst.get(key);
        if (t == null) {
          t = new TreeMap<>();
          dst.put(key, t);
        }
        dst = t;
      }

      Function<Object, String> fmt =
          (Function<Object, String>) fields[fields.length - 1].formatter();
      dst.put(
          fmt.apply(keys.get(fields.length - 1)),
          new MetricJson(e.getValue(), atts, true));
    }
    return out;
  }

  static class FieldJson {
    String name;
    String type;
    String description;

    FieldJson(Field<?> field) {
      this.name = field.getName();
      this.description = field.getDescription();
      this.type = Enum.class.isAssignableFrom(field.getType())
          ? field.getType().getSimpleName()
          : null;
    }
  }
}
