module JSON::JWK::Set::Fetcher

def self.cache

def self.cache
  @@cache
end

def self.cache=(cache)

def self.cache=(cache)
  @@cache = cache
end

def self.debug(&block)

def self.debug(&block)
  original = self.debugging?
  debug!
  yield
ensure
  self.debugging = original
end

def self.debug!

def self.debug!
  self.debugging = true
end

def self.debugging=(boolean)

def self.debugging=(boolean)
  @@debugging = boolean
end

def self.debugging?

def self.debugging?
  @@debugging
end

def self.fetch(jwks_uri, kid:, auto_detect: true, **options)

def self.fetch(jwks_uri, kid:, auto_detect: true, **options)
  cache_key = [
    'json:jwk:set',
    OpenSSL::Digest::MD5.hexdigest(jwks_uri),
    kid
  ].collect(&:to_s).join(':')
  parsed_jwks = JSON.parse(
    cache.fetch(cache_key, options) do
      http_client.get(jwks_uri).body
    end
  )
  unless parsed_jwks.is_a?(Hash) && parsed_jwks['keys'].is_a?(Array)
    cache.delete(cache_key, options)
    raise UnexpectedFormat
  end
  jwks = Set.new(parsed_jwks)
  cache.delete(cache_key, options) if jwks[kid].blank?
  if auto_detect
    jwks[kid] or raise KidNotFound
  else
    jwks
  end
end

def self.http_client

def self.http_client
  Faraday.new(headers: {user_agent: "JSON::JWK::Set::Fetcher #{VERSION}"}) do |faraday|
    faraday.response :raise_error
    faraday.response :follow_redirects
    faraday.response :logger, JSON::JWK::Set::Fetcher.logger if debugging?
    faraday.adapter Faraday.default_adapter
    http_config.try(:call, faraday)
  end
end

def self.http_config(&block)

def self.http_config(&block)
  @@http_config ||= block
end

def self.logger

def self.logger
  @@logger
end

def self.logger=(logger)

def self.logger=(logger)
  @@logger = logger
end