# frozen_string_literal: true

require 'abaci/config'

require 'influxdb'

module Abaci

  # Helper class to access data from influx
  class Influx
    extend Base

    class << self

      # Returns an {InfluxDB::Client} configured to access our backend
      # @return [InfluxDB::Client]
      def client
        @client ||= InfluxDB::Client.new url: material('influx_url'), username: material('influx_username'), password: material('influx_password'), epoch: 'ms'
      end

      # Returns the pageviews currently stored in influx
      # @return [Hash<Integer, Integer>] millisecond epochs to pageview count.
      def pageviews
        return @pageviews if instance_variable_defined?(:@pageviews)
        response = {}

        client.query("select sum(count) as count from pageviews_by_build where time > now() - #{config(:last)} group by time(1m)") do |_name, _tags, points|
          points.reject { |point| point['count'].nil? }.each { |point| response[point['time']] = point['count'] }
        end

        @pageviews = response
      end

      # Returns the pageviews by build
      # @return [Hash<Integer, Hash<String, Integer>>] millisecond epocs to a hash of build id to pageview count.
      def pageviews_by_build
        return @pageviews_by_build if instance_variable_defined?(:@pageviews_by_build)
        response = {}

        client.query("select sum(count) as count from pageviews_by_build where time > now() - #{config(:last)} group by time(1m), build_id") do |_name, tags, points|
          build_id = tags['build_id']
          next if build_id.nil?

          points.reject { |point| point['count'].nil? }.each do |point|
            response[point['time']] ||= {}
            response[point['time']][build_id] = point['count']
          end
        end

        @pageviews_by_build = response
      end

      # Writes the current error rate values to Influx
      # @return [Boolean] returns true if the data was written to Influx successfully
      def write_error_rates
        points = Abaci.error_rates.collect do |timestamp, data|
          {
            series: 'pageview_error_rates',
            timestamp: timestamp,
            values: data
          }
        end

        if config(:dry_run)
          puts "This is a dry run! #{points.count} data points would have been written to influx."
          puts JSON.pretty_unparse(points).split("\n").collect { |line| "    #{line}" }.join("\n") if config(:debug)
          return false
        end

        response = client.write_points(points, 'ms')

        if response.code != '204'
          puts "Error: Writing to Influx did not succeed.  Received a #{response.code} response.  Body: #{response.body}"
          return false
        end

        true
      end

      # Writes the current error rate values to Influx
      # @return [Boolean] returns true if the data was written to Influx successfully
      def write_error_rates_by_build
        points = Abaci.error_rates_by_build.collect do |timestamp, time_slice_data|
          time_slice_data.collect do |build_id, data|
            {
              series: 'pageview_error_rates_by_build',
              timestamp: timestamp,
              tags: { build_id: build_id },
              values: data
            }
          end
        end.flatten

        if config(:dry_run)
          puts "This is a dry run! #{points.count} data points would have been written to influx."
          puts JSON.pretty_unparse(points).split("\n").collect { |line| "    #{line}" }.join("\n") if config(:debug)
          return false
        end

        response = client.write_points(points, 'ms')

        if response.code != '204'
          puts "Error: Writing to Influx did not succeed.  Received a #{response.code} response.  Body: #{response.body}"
          return false
        end

        true
      end
    end
  end
end
