define([
  'angular',
  'lodash',
  'kbn',
  './queryCtrl',
],
function (angular, _, kbn) {
  'use strict';

  var module = angular.module('grafana.services');

  module.factory('KairosDBDatasource', function($q, $http, templateSrv) {

    function KairosDBDatasource(datasource) {
      this.type = 'kairosdb';
      this.editorSrc = 'app/features/kairosdb/partials/query.editor.html';
      this.url = datasource.url;
      this.name = datasource.name;
      this.supportMetrics = true;
    }

    // Called once per panel (graph)
    KairosDBDatasource.prototype.query = function(options) {
      var start = convertToTSDBTime(options.range.from);
      var end = convertToTSDBTime(options.range.to);
      var queries = _.compact(_.map(options.targets, convertTargetToQuery));

      // No valid targets, return the empty result to save a round trip.
      if (_.isEmpty(queries)) {
        var d = $q.defer();
        d.resolve({ data: [] });
        return d.promise;
      }

      var groupByTags = {};
      _.each(queries, function(query) {
        _.each(query.metric.group_by, function(group) {
          _.each(group.tags, function(tag) {
            groupByTags[tag] = true;
          });
        });
      });

      return this.performTimeSeriesQuery(queries, start, end)
        .then(_.bind(function(response) {
          var result = [];
          _.each(response.data, function(metricData, index) {
            _.each(metricData, function(md) {
              _.each(md.results, function(r) {
                result.push(transformMetricData(r, groupByTags, {}));
              });
            });
          });
          return { data: result };
        }, options));
    };

    KairosDBDatasource.prototype.performTimeSeriesQuery = function(queries, start, end) {
      var reqBody = {
        "metrics": _.pluck(queries, 'metric'),
        "cache_time": 0,
        "start_absolute": start,
        "end_absolute": end
      };

      var options = {
        method: 'POST',
        url: this.url + '/rest/kairosDBPost',
        data: reqBody
      };

      return $http(options);
    };

    KairosDBDatasource.prototype.performSuggestMetrics = function() {
      var options = {
        method: 'GET',
        url: this.url + '/rest/kairosDBmetrics'
      };
      return $http(options).then(function(result) {
        return result.data.results;
      });
    };

    KairosDBDatasource.prototype.performSuggestTags = function(target, key) {
      var options = {
        method: 'POST',
        url: this.url + '/rest/kairosDBtags',
        data: {
          cache_time: 0,
          metrics: [{
            name: target.metric,
            tags: {}
          }],
          start_absolute: 0
        }
      };
      return $http(options).then(function(result) {
        var keys = [];
        _.each(result.data.queries, function(query) {
          _.each(query.results, function(result) {
            if (key) {
              keys = keys.concat(result.tags[key]);
            }
              keys = keys.concat(_.keys(result.tags));
          });
        });
        return keys;
      });
    }

    function transformMetricData(md, groupByTags, options) {
      var dps = [],
          tagData = [],
          metricLabel = null;

      if (!_.isEmpty(md.tags)) {
        _.each(_.pairs(md.tags), function(tag) {
          if (_.has(groupByTags, tag[0])) {
            tagData.push(tag[0] + "=" + tag[1]);
          }
        });
      }

      metricLabel = createMetricLabel(md.name, tagData, options);

      _.each(md.values, function (v) {
        dps.push([v[1], v[0]]);
      });

      return { target: metricLabel, datapoints: dps };
    }

    function createMetricLabel(metric, tagData, options) {
      if (!_.isUndefined(options) && options.alias) {
        return options.alias;
      }

      if (!_.isEmpty(tagData)) {
        metric += "{" + tagData.join(", ") + "}";
      }

      return metric;
    }

    function convertTargetToQuery(target) {
      if (!target.metric) {
        return null;
      }

      var aggregator = {
        name: "avg",
        align_sampling: true,
        sampling: {
          value: 5,
          unit: "Minutes"
        }
      };

      var query = {
        metric: {
          name: templateSrv.replace(target.metric),
          aggregators: [aggregator]
        }
      };

      if (target.aggregator) {
        aggregator.name = templateSrv.replace(target.aggregator);
      }

      if (target.sampling && target.sampling.unit && target.sampling.value) {
        aggregator.sampling = {
          "unit": templateSrv.replace(target.sampling.unit),
          "value": templateSrv.replace(target.sampling.value)
        };
      }

      if (target.groups && target.groups.length) {
        query.metric.group_by = [{
          name: "tag",
          tags: target.groups
        }];
      }

      if (target.tags) {
        query.metric.tags = {};
        _.each(target.tags, function(tag) {
          if (query.metric.tags[tag.key]) {
            query.metric.tags[tag.key].push(templateSrv.replace(tag.value));
          } else {
            query.metric.tags[tag.key] = [templateSrv.replace(tag.value)];
          }
        });
      }

      return query;
    }

    return KairosDBDatasource;
  });

  function convertToTSDBTime(date) {
    if (date === 'now') {
      return null;
    }

    date = kbn.parseDate(date);

    return date.getTime();
  }
});
