require './core/utils/summary_writer_utils'

include SummaryWriterUtils

module StatUtils
  # This module is intended to include shared methods in relation to statistics/metrics
  require 'statsd-ruby'

  def initialize_statsd
    @domain = 'statsd.internal.justin.tv'
    @statsd = Statsd.new @domain, 8125
    @metric = 'smoca'
  end

  def gauge(name, amount)
    # Automatically appends smoca. to the front of a metric, since this is within the Smoca project
    return nil if ENV['TRACKING'] != 'true' # Only increment if TRACKING == 'true'
    initialize_statsd # This needs to be called to get the @ class variables

    @statsd.gauge("#{@metric}.#{name}", amount)
  end

  def increment(name)
    # Automatically appends smoca. to the front of a metric, since this is within the Smoca project
    return nil if ENV['TRACKING'] != 'true' # Only increment if TRACKING == 'true'
    initialize_statsd
    @statsd.increment("#{@metric}.#{name}")
  end

  def measure_login_ratio(statscounter)
    return false if statscounter.nil?

    # Takes the StatsCounter Object
    if ENV['PARALLEL'] == 'true'
      write_login_success(statscounter.success)
      write_login_failure(statscounter.fail)
    else
      puts "\nLogin Success Count: #{statscounter.success}\n"\
    "Login Fail Count: #{statscounter.fail}\n"\
    "Percentage of Success: #{statscounter.success_percent}%"
      # Printing out success percent instead of failure because in the logs it looks better if 100%
      # But in terms of statsd graphs, it's only important to notice failure rates increase
      # Easily changeable to fail_percentage if needed (or simply removing the print statement)

      gauge('debug.login_failure.count', statscounter.fail_percent) # Send login fail stats if tracking enabled
    end
  end

  module Tracking
    def summary_log_events(exit_code)
      return false if ENV['TRACKING'] != 'true'

      measure_test_duration(exit_code)
    end

    # @param process Type String - The process number which RSpec is running on (via RSpec Parallel)
    # @param notification - object type SummaryNotification
    def measure_process_duration(process, notification)
      return false if process == nil
      process = 1 if process == '' # parallel_tests gem puts Process 1 as Blank, so set it as 1 for reporting.

      if notification.failure_count == 0
        result = 'success'
      else
        result = 'failure'
      end

      gauge("duration.processes.#{process}.#{result}", notification.duration / 60)
    end

    # Used for monitoring exceptions. Takes in an example exception - if it's a known trackable exception, increment it in Statsd
    # @param exception The exception an example came across
    def track_exception(exception)

      # A hash containing known exceptions to log and its error message to send to statsd as
      known_exceptions =
        {
          Selenium::WebDriver::Error::ScriptTimeoutError => 'script_timeout_error', # A script did not complete before its timeout expired.
          Selenium::WebDriver::Error::UnknownError       => 'unknown_webdriver_error'
        }

      exceptions_to_log = [] # Store all of the exceptions that need to be logged to statsd

      if exception.class == RSpec::Core::MultipleExceptionError
        # Multiple Exceptions Found. Loop through each and log if known.
        exception.all_exceptions.each do |e|
          exceptions_to_log << e.class if known_exceptions.has_key?(e.class)
        end
      else
        # Only one exception found. log if known.
        exceptions_to_log << exception.class if known_exceptions.has_key?(exception.class)
      end

      # Increment the unique exceptions.
      exceptions_to_log.uniq.each do |logged_e|
        increment("warnings.#{known_exceptions[logged_e]}")
      end
    end

    private
    def measure_test_duration(exit_code)
      if exit_code == 0
        result = 'success'
      else
        result = 'failure'
      end

      gauge("#{result}.duration", (get_test_duration().max / 60)) # Measures the duration and also distinguishes a success/fail result
    end
  end

  class StatsCounter
    attr_accessor :fail, :success
    attr_reader :success_percent, :fail_percent

    def initialize
      @success = 0
      @fail = 0
      @success_percent = 0
      @fail_percent = 0
    end

    def increment_success
      @success += 1.0
      calculate_percents() # Each increment, recalculate the percents
    end

    def increment_fail
      @fail += 1.0
      calculate_percents() # Each increment, recalculate the percents
    end

    def calculate_percents # Alias to calculating both percents
      @fail_percent = ((@fail / (@fail + @success)) * 100).round(2) if (@fail + @success) != 0
      @success_percent = ((@success / (@fail + @success)) * 100).round(2) if (@fail + @success) != 0
    end
  end
end
