# -*- coding: utf-8 -*-
from __future__ import unicode_literals

import logging

from oauthlib.common import extract_params
from oauthlib.oauth1 import Client, SIGNATURE_HMAC, SIGNATURE_TYPE_AUTH_HEADER
from oauthlib.oauth1 import SIGNATURE_TYPE_BODY
from requests.compat import is_py3
from requests.utils import to_native_string
from requests.auth import AuthBase

CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
CONTENT_TYPE_MULTI_PART = 'multipart/form-data'

if is_py3:
  unicode = str

log = logging.getLogger(__name__)


# OBS!: Correct signing of requests are conditional on invoking OAuth1
# as the last step of preparing a request, or at least having the
# content-type set properly.
class OAuth1(AuthBase):
  """Signs the request using OAuth 1 (RFC5849)"""

  client_class = Client

  def __init__(self,
               client_key,
               client_secret=None,
               resource_owner_key=None,
               resource_owner_secret=None,
               callback_uri=None,
               signature_method=SIGNATURE_HMAC,
               signature_type=SIGNATURE_TYPE_AUTH_HEADER,
               rsa_key=None,
               verifier=None,
               decoding='utf-8',
               client_class=None,
               force_include_body=False,
               **kwargs):

    try:
      signature_type = signature_type.upper()
    except AttributeError:
      pass

    client_class = client_class or self.client_class

    self.force_include_body = force_include_body

    self.client = client_class(
        client_key,
        client_secret,
        resource_owner_key,
        resource_owner_secret,
        callback_uri,
        signature_method,
        signature_type,
        rsa_key,
        verifier,
        decoding=decoding,
        **kwargs)

  def __call__(self, r):
    """Add OAuth parameters to the request.

        Parameters may be included from the body if the content-type is
        urlencoded, if no content type is set a guess is made.
        """
    # Overwriting url is safe here as request will not modify it past
    # this point.
    log.debug('Signing request %s using client %s', r, self.client)

    content_type = r.headers.get('Content-Type', '')
    if (not content_type and extract_params(r.body) or
        self.client.signature_type == SIGNATURE_TYPE_BODY):
      content_type = CONTENT_TYPE_FORM_URLENCODED
    if not isinstance(content_type, unicode):
      content_type = content_type.decode('utf-8')

    is_form_encoded = (CONTENT_TYPE_FORM_URLENCODED in content_type)

    log.debug('Including body in call to sign: %s', is_form_encoded or
              self.force_include_body)

    if is_form_encoded:
      r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED
      r.url, headers, r.body = self.client.sign(
          unicode(r.url), unicode(r.method), r.body or '', r.headers)
    elif self.force_include_body:
      # To allow custom clients to work on non form encoded bodies.
      r.url, headers, r.body = self.client.sign(
          unicode(r.url), unicode(r.method), r.body or '', r.headers)
    else:
      # Omit body data in the signing of non form-encoded requests
      r.url, headers, _ = self.client.sign(
          unicode(r.url), unicode(r.method), None, r.headers)

    r.prepare_headers(headers)
    r.url = to_native_string(r.url)
    log.debug('Updated url: %s', r.url)
    log.debug('Updated headers: %s', headers)
    log.debug('Updated body: %r', r.body)
    return r
