require 'active_support/core_ext/hash'
require 'footrest/client'
require 'paul_walker'

module Bearcat
  class Client < Footrest::Client
    require 'bearcat/api_array'

    Dir[File.join(__dir__, 'client', '*.rb')].each do |mod|
      mname = File.basename(mod, '.*').camelize
      mname = 'GraphQL' if mname == 'GraphQl'
      require mod
      include "Bearcat::Client::#{mname}".constantize
    end

    # Override Footrest request for ApiArray support
    def request(method, &block)
      enforce_rate_limits
      response = connection.send(method, &block)
      apply_rate_limits(response.headers['x-rate-limit-remaining'])
      ApiArray.process_response(response, self)
    end

    def enforce_rate_limits
      return unless limit_remaining.present?
      return unless limit_remaining < Bearcat.rate_limit_min

      tts = ((Bearcat.rate_limit_min - limit_remaining) / 5).ceil
      tts = Bearcat.min_sleep_seconds if tts < Bearcat.min_sleep_seconds
      tts = Bearcat.max_sleep_seconds if tts > Bearcat.max_sleep_seconds


      message = "Canvas API rate limit minimum #{Bearcat.rate_limit_min} reached. "\
        "Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\
        "Limit Remaining: #{limit_remaining}"
      Bearcat.logger.debug(message)

      sleep(tts)
    end

    def apply_rate_limits(limit)
      return if limit.nil?
      self.limit_remaining = limit.to_i
    end

    def using_master_rate_limit?
      config[:master_rate_limit].present? || Bearcat.master_rate_limit.present?
    end

    def limit_remaining
      if using_master_rate_limit?
        Bearcat.master_mutex.synchronize do
          limit = PaulWalker::RateLimit.get(config[:token], config[:token])
          if limit.nil?
            PaulWalker::RateLimit.add(config[:token], config[:token], 0, Bearcat::rate_limit_min)
            limit = { current: 0 }.with_indifferent_access
          end
          Bearcat.logger.debug limit['current'].to_s
          limit['current']
        end
      else
        Bearcat.rate_limits[config[:token]]
      end
    end

    def limit_remaining=(value)
      if using_master_rate_limit?
        Bearcat.master_mutex.synchronize do
          PaulWalker::RateLimit.add(config[:token], config[:token], value, Bearcat::rate_limit_min)
        end
      else
        Bearcat.rate_limits[config[:token]] = value
      end
    end
  end
end