# encoding: utf-8
require "logstash/outputs/base"
require "logstash/namespace"
require "application_insights"

include ApplicationInsights
include ApplicationInsights::Channel

class LogStash::Outputs::ApplicationInsights < LogStash::Outputs::Base
  config_name "applicationinsights"

  config :ikey, :validate => :string, :required => true
  config :ai_type, :validate => :string, :required => true
  config :dev_mode, :validate => :boolean, :required => false, :default => false
  config :ai_message_field, :validate => :string, :required => false, :default => nil
  config :ai_properties_field, :validate => :string, :required => false, :default => nil
  config :ai_severity_level_field, :validate => :string, :required => false, :default => nil
  config :ai_severity_level_mapping, :validate => :hash, :required => false, :default => nil
  config :ai_metrics_names, :validate => :array, :required => false, :default => nil
  config :ai_event_name, :validate => :string, :required => false, :default => nil
  
  public
  def register
     create_client
  end # def register

  public
  def multi_receive(events)
    events.each do |event|
      begin
        ai_properties = get_ai_properties(event)
        if @ai_type == "trace"
          ai_message = get_field(event, @ai_message_field)
          ai_severity = get_ai_severity(event)
          @client.track_trace(ai_message, ai_severity, { :properties => ai_properties })
        elsif @ai_type == "metric"
          if !@ai_metrics_names.nil? && @ai_metrics_names.any?
            @ai_metrics_names.each do |metric_name|
              metric_value = get_field(event, metric_name)
              if metric_value.nil?
                @logger.warn("#{@metric_name} specified in ai_metrics_names not found in event data.")
              else
                @client.track_metric(metric_name, metric_value.to_f, { :properties => ai_properties })
              end  # if
            end # do
          end # if ai_metric_fields
        elsif @ai_type == "event"
          @client.track_event(@ai_event_name, { :properties => ai_properties }) if !@ai_event_name.nil?
        end # if ai_type

        @client.flush if @dev_mode

      rescue => e
        @logger.error("Error occurred sending data to AI.", :exception => e)
      end # begin
    end # do 
  end # def multi_receive
  
  def close
    @client.flush
  end # def close

  def create_client
    telemetry_context = TelemetryContext.new
    async_queue = AsynchronousQueue.new(AsynchronousSender.new)
    telemetry_channel = TelemetryChannel.new(telemetry_context, async_queue)
    @client = TelemetryClient.new(@ikey, telemetry_channel)
  end # def create_client
  
  def get_field(event, field_name)
    return nil if field_name.nil?
    
    field = event.get(field_name) # Extracts specified field value as the AI Message.
    @logger.warn("#{field_name} not found in event data.") if field.nil?
    event.remove(field_name) unless field.nil?  # Removes the duplicated AI field.
    field
  end # def get_ai_message
  
  def get_ai_properties(event)
    ai_properties = event.to_hash.fetch(@ai_properties_field, nil)
    if !@ai_properties_field.nil? && ai_properties.nil?
      @logger.warn("#{@ai_properties_field} specified in ai_properties_field not found in event data. Will use all fields in event as AI properties.")
    end # if

    ai_properties || event.to_hash
  end # def get_ai_properties
  
  def get_ai_severity(event)
    return nil if @ai_severity_level_field.nil? 

    severity_value = event.get(@ai_severity_level_field)

    if !@ai_severity_level_mapping.nil? && @ai_severity_level_mapping.any?
      ai_severity_level = @ai_severity_level_mapping.fetch(severity_value, nil)
    else
      ai_severity_level = severity_value
    end # unless

    if ai_severity_level.nil?
      @logger.warn("Cannot map value '#{severity_value}' from '#{@ai_severity_level_field}' to AI severity level. Will use default value.")
    else
      event.remove(@ai_severity_level_field)  # Removes the duplicated severity field.
    end # if
    
    ai_severity_level
  end # def get_ai_severity

end # LogStash::Outputs::ApplicationInsights
