define([
  'angular',
  'lodash',
  'config'
],
function (angular, _, config) {
  'use strict';

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

  module.controller('MetricKeysCtrl', function($scope, $http, $q) {
    var elasticSearchUrlForMetricIndex = config.elasticsearch + '/' + config.grafana_metrics_index + '/';
    var httpOptions = {};
    if (config.elasticsearchBasicAuth) {
      httpOptions.withCredentials = true;
      httpOptions.headers = {
        "Authorization": "Basic " + config.elasticsearchBasicAuth
      };
    }
    $scope.init = function () {
      $scope.metricPath = "prod.apps.api.boobarella.*";
      $scope.metricCounter = 0;
    };

    $scope.createIndex = function () {
      $scope.errorText = null;
      $scope.infoText = null;

      deleteIndex()
        .then(createIndex)
        .then(function () {
          $scope.infoText = "Index created!";
        })
        .then(null, function (err) {
          $scope.errorText = angular.toJson(err);
        });
    };

    $scope.loadMetricsFromPath = function() {
      $scope.errorText = null;
      $scope.infoText = null;
      $scope.metricCounter = 0;

      return loadMetricsRecursive($scope.metricPath)
        .then(function() {
          $scope.infoText = "Indexing completed!";
        }, function(err) {
          $scope.errorText = "Error: " + err;
        });
    };

    $scope.loadAll = function() {
      $scope.infoText = "Fetching all metrics from graphite...";

      getFromEachGraphite('/metrics/index.json', saveMetricsArray)
        .then(function() {
          $scope.infoText = "Indexing complete!";
        }).then(null, function(err) {
          $scope.errorText = err;
        });
    };

    function getFromEachGraphite(request, data_callback, error_callback) {
      return $q.all(_.map(config.datasources, function(datasource) {
        if (datasource.type = 'graphite') {
          return $http.get(datasource.url + request)
            .then(data_callback, error_callback);
        }
      }));
    }

    function saveMetricsArray(data, currentIndex) {
      if (!data && !data.data && data.data.length === 0) {
        return $q.reject('No metrics from graphite');
      }

      if (data.data.length === currentIndex) {
        return $q.when('done');
      }

      currentIndex = currentIndex || 0;

      return saveMetricKey(data.data[currentIndex])
        .then(function() {
          return saveMetricsArray(data, currentIndex + 1);
        });
    }

    function deleteIndex()
    {
      var deferred = $q.defer();
      $http.delete(elasticSearchUrlForMetricIndex, httpOptions)
        .success(function() {
          deferred.resolve('ok');
        })
        .error(function(data, status) {
          if (status === 404) {
            deferred.resolve('ok');
          }
          else {
            deferred.reject('elastic search returned unexpected error');
          }
        });

      return deferred.promise;
    }

    function createIndex()
    {
      return $http.put(elasticSearchUrlForMetricIndex, {
        settings: {
          analysis: {
            analyzer: {
              metric_path_ngram : { tokenizer : "my_ngram_tokenizer" }
            },
            tokenizer: {
              my_ngram_tokenizer : {
                type : "nGram",
                min_gram : "3",
                max_gram : "8",
                token_chars: ["letter", "digit", "punctuation", "symbol"]
              }
            }
          }
        },
        mappings: {
          metricKey: {
            properties: {
              metricPath: {
                type: "multi_field",
                fields: {
                  "metricPath": { type: "string", index: "analyzed", index_analyzer: "standard" },
                  "metricPath_ng": { type: "string", index: "analyzed", index_analyzer: "metric_path_ngram" }
                }
              }
            }
          }
        }
      }, httpOptions);
    }

    function receiveMetric(result) {
      var data = result.data;
      if (!data || data.length === 0) {
        console.log('no data');
        return;
      }

      var funcs = _.map(data, function(metric) {
        if (metric.expandable) {
          return loadMetricsRecursive(metric.id + ".*");
        }
        if (metric.leaf) {
          return saveMetricKey(metric.id);
        }
      });

      return $q.all(funcs);
    }

    function saveMetricKey(metricId) {

      // Create request with id as title. Rethink this.
      var request = $scope.ejs.Document(config.grafana_metrics_index, 'metricKey', metricId).source({
        metricPath: metricId
      });

      return request.doIndex(
        function() {
          $scope.infoText = "Indexing " + metricId;
          $scope.metricCounter = $scope.metricCounter + 1;
        },
        function() {
          $scope.errorText = "failed to save metric " + metricId;
        }
      );
    }

    function loadMetricsRecursive(metricPath)
    {
      return getFromEachGraphite('/metrics/find/?query=' + metricPath, receiveMetric);
    }

  });

});
