require 'base64'
require_relative 'oauth_client'

module Twurl
  class AppOnlyOAuthClient < Twurl::OAuthClient

    AUTHORIZATION_FAILED_MESSAGE = "Authorization failed. Check that your consumer key and secret are correct."

    attr_reader :consumer_key, :consumer_secret, :bearer_token

    def initialize(options = {})
      @consumer_key    = options['consumer_key']
      @consumer_secret = options['consumer_secret']
      @bearer_token    = options['bearer_token']
    end

    def save
      self.class.rcfile.bearer_token(consumer_key, bearer_token)
    end

    def exchange_credentials_for_access_token
      response = fetch_oauth2_token
      if response.nil? || response[:access_token].nil?
        raise Exception, AUTHORIZATION_FAILED_MESSAGE
      end
      @bearer_token = response[:access_token]
    end

    def perform_request_from_options(options, &block)
      request = build_request_from_options(options)
      request['user-agent'] = user_agent
      request['authorization'] = "Bearer #{bearer_token}"

      http_client.request(request, &block)
    end

    def needs_to_authorize?
      bearer_token.nil?
    end

    def request_data
      {'grant_type' => 'client_credentials'}
    end

    def http_client
      uri = URI.parse(Twurl.options.base_url)
      http = if Twurl.options.proxy
        proxy_uri = URI.parse(Twurl.options.proxy)
        Net::HTTP.new(uri.host, uri.port, proxy_uri.host, proxy_uri.port)
      else
        Net::HTTP.new(uri.host, uri.port)
      end
      set_http_client_options(http)
    end

    def set_http_client_options(http)
      http.set_debug_output(Twurl.options.debug_output_io) if Twurl.options.trace
      http.read_timeout = http.open_timeout = Twurl.options.timeout || 60
      http.open_timeout = Twurl.options.connection_timeout if Twurl.options.connection_timeout
      http.max_retries = 0
      http.use_ssl     = true
      http.verify_mode = OpenSSL::SSL::VERIFY_NONE
      http
    end

    def fetch_oauth2_token
      request = Net::HTTP::Post.new('/oauth2/token')
      request.body = URI.encode_www_form(request_data)
      request['user-agent'] = user_agent
      request['authorization'] = "Basic #{Base64.strict_encode64("#{consumer_key}:#{consumer_secret}")}"
      response = http_client.request(request).body
      JSON.parse(response,:symbolize_names => true)
    end
  end
end