require 'base64'
require 'openssl'
require 'time'
require 'digest'

module SimpleHmac
  module Helper
    def hmac_token(verb, content_type, content_md5, url, date, api_secret, options={})
      options = { separator: "\n", algorithm: 'sha256', include_verb: true }.merge(options)
      url_without_server = url.gsub(/https?:\/\/[^(,|\?|\/)]*/, '')
      data = [verb.upcase, content_type, content_md5, url_without_server, date]
      data.shift unless options[:include_verb]
      string_to_sign = data.join(options[:separator])
      sign_string(string_to_sign, api_secret, options[:algorithm])
    end

    def sign_string(string, secret, algorithm = 'sha256')
      Base64.strict_encode64(OpenSSL::HMAC.digest(algorithm, secret, string))
    end

    def authentication_headers(verb, content_type, payload, url, api_key, api_secret, options={})
      options         = { auth_prefix: 'WIZYPAY' }.merge(options)
      auth_prefix     = options.delete :auth_prefix
      date = Time.now.httpdate
      content_type ||= 'text/plain'
      content_md5 = digest_md5(verb, payload)
      hmac_token = hmac_token(verb, content_type, content_md5, url, date, api_secret, options)
      {
        'Date' => date,
        'Content-Type' => content_type,
        'Content-MD5' => content_md5,
        'Authorization' => "#{auth_prefix} #{api_key}:#{hmac_token}"
      }
    end

    def digest_md5(verb, payload)
      return '' unless [:post, :put, :patch].include?(verb.downcase.to_sym)
      if payload.nil?
        body = ''
      elsif payload.respond_to? :read
        body = payload.read
        payload.instance_variable_get(:@stream).seek(0)
      else
        body = payload
      end
      Digest::MD5.base64digest(body)
    end
  end
end
