require 'nagios-herald/helpers/base'
# Search for previous occurrences of a given Nagios alert and report.
#
# Can search for host alerts (i.e. DOWN state) and service alerts for a
# single host (i.e. 'Disk Space').
#
# Options:
#  :duration - time (in days) to search [DEFAULT: 7 days]
#  :hostname - Etsy Nagios-like hostname (i.e. web0200.ny4) [REQUIRED]
#  :service_name - service name to search (i.e. 'Disk Space') [OPTIONAL]
#
#  If the :service_name argument is not present, this performs a search
#  for host alerts.

module NagiosHerald
  class Helper
    class AlertFrequency < Helper
      include NagiosHerald::Logging

      # Public: Initialize a new AlertFrequency object.
      #
      # hostname       - The name of the alerting host we want to query.
      # service        - Optional service name that may be alerting.
      # options        - Options to tune the query.
      #   :time_period - How far back to query. EXAMPLE: 1h (1 hour); 2d (2 days); 3w (3 weeks). DEFAULT: 7d
      #   :num_results - The maximum number of results we want returned. DEFAULT: 100
      #
      # Returns a new AlertFrequency object.
      def initialize(hostname, service = nil, options = {})
        @hostname = hostname
        @service  = service
        @time_period = options[:time_period] ? options[:time_period] : "7d"
        @num_results = options[:num_results] ? options[:num_results] : 100
        # @key_fields are used later to generate a unique key so we can aggregate notifications
        # into single events for realistic event counts.
        @key_fields = ["nagios_hostname", "nagios_service", "nagios_state", "nagios_epoch"]
      end

      # Public: Generate the query.
      #
      #
      # Returns the generated query.
      def generate_query()
        # query for service alerts or host alerts, depending on which args were selected
        query = "type:nagios_log nagios_hostname:#{@hostname}"
        if @service.nil?
            query += " nagios_type:\"HOST NOTIFICATION\" nagios_state:\"DOWN\""
        else
            query += " nagios_type:\"SERVICE NOTIFICATION\" nagios_service:\"#{@service}\" (nagios_state:\"WARNING\" OR nagios_state:\"CRITICAL\" OR nagios_state:\"UNKNOWN\")"
        end
      end
      #
      # Public: Aggregate the Nagios notifications
      # Nagios logs an entry for each entity that got alerted; a single alert can
      # result in many log entries so we need to account for this by creating a
      # unique key to ensure we don't count duplicate log lines.
      # Chances are we *won't* see a duplicate except in cases where an alert fires
      # on the cusp of a minute (I've seen up to 4-second skew in timestamp for
      # alert results; this _can_ happen).
      #
      # results - Hash containing the Elasticsearch results.
      #
      # Returns the count of events seen for this alert.
      def aggregate_events(results)
        notifications = results['hits']['hits']
        events = {}
        notifications.each do |notification|
            # For each unique combination of notification attributes, create a key to track it as a single event.
            event_key = @key_fields.map{|f| notification['_source'][f]}.join('-')
            events[event_key] = 1
        end

        return events.length
      end

      # Public: Queries Elasticsearch to determine how frequently an alert has fired in a given period.
      #
      # query - A query string generated by generate_query().
      #
      # Returns a hash containing results from the search.
      def get_alert_frequency(query)
        # Call elasticsearch_query.rb here
        options = {:time_period => @time_period, :num_results => @num_results}
        es = NagiosHerald::Helper::ElasticsearchQuery.new(options)
        results = es.query_from_string(query)

        events_count = aggregate_events(results)
      end

    end
  end
end
