# -*- coding: utf-8 -*-
"""
Copyright 2019 eBay Inc.
 
Licensed under the Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,

WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and
limitations under the License.
"""

import json
import logging
import urllib.error
import urllib.parse
import urllib.request
from datetime import datetime, timedelta

import requests

from ebay_feedsdk.oauthclient.credentialutil import Credentialutil
from ebay_feedsdk.oauthclient.model import util
from ebay_feedsdk.oauthclient.model.model import OauthToken

LOGFILE = 'eBay_Oauth_log.txt'
logging.basicConfig(level=logging.DEBUG, filename=LOGFILE,
                    format="%(asctime)s: %(levelname)s - %(funcName)s: %(message)s", filemode='w')


class Oauth2api(object):

    def generate_user_authorization_url(self, env_type, scopes, state=None):
        '''
            EnvType = Environment.SANDBOX or Environment.PRODUCTION
            scopes = list of strings
        '''

        credential = Credentialutil.get_credentials(env_type)

        scopes = ' '.join(scopes)
        param = {
            'client_id': credential.client_id,
            'redirect_uri': credential.ru_name,
            'response_type': 'code',
            'prompt': 'login',
            'scope': scopes
        }

        if state != None:
            param.update({'state': state})

        query = urllib.parse.urlencode(param)
        return env_type.web_endpoint + '?' + query

    def get_application_token(self, env_type, scopes):
        """
            makes call for application token and stores result in credential object
            returns credential object
        """

        logging.info("Trying to get a new application access token ... ")
        credential = Credentialutil.get_credentials(env_type)
        headers = util.generate_request_headers(credential)
        body = util.generate_application_request_body(credential, ' '.join(scopes))

        resp = requests.post(env_type.api_endpoint, data=body, headers=headers)
        content = json.loads(resp.content)
        token = OauthToken()

        if resp.status_code == requests.codes.ok:
            token.access_token = content['access_token']
            # set token expiration time 5 minutes before actual expire time
            token.token_expiry = datetime.utcnow() + timedelta(seconds=int(content['expires_in'])) - timedelta(
                minutes=5)

        else:
            token.error = str(resp.status_code) + ': ' + content['error_description']
            logging.error("Unable to retrieve token.  Status code: %s - %s", resp.status_code,
                          requests.status_codes._codes[resp.status_code])
            logging.error("Error: %s - %s", content['error'], content['error_description'])

        return token

    def exchange_code_for_access_token(self, env_type, code):
        logging.info("Trying to get a new user access token ... ")
        credential = Credentialutil.get_credentials(env_type)

        headers = util.generate_request_headers(credential)
        body = util.generate_oauth_request_body(credential, code)
        resp = requests.post(env_type.api_endpoint, data=body, headers=headers)

        content = json.loads(resp.content)
        token = OauthToken()

        if resp.status_code == requests.codes.ok:
            token.access_token = content['access_token']
            token.token_expiry = datetime.utcnow() + timedelta(seconds=int(content['expires_in'])) - timedelta(
                minutes=5)
            token.refresh_token = content['refresh_token']
            token.refresh_token_expiry = datetime.utcnow() + timedelta(
                seconds=int(content['refresh_token_expires_in'])) - timedelta(minutes=5)
        else:
            token.error = str(resp.status_code) + ': ' + content['error_description']
            logging.error("Unable to retrieve token.  Status code: %s - %s", resp.status_code,
                          requests.status_codes._codes[resp.status_code])
            logging.error("Error: %s - %s", content['error'], content['error_description'])
        return token

    def get_access_token(self, env_type, refresh_token, scopes):
        """
        refresh token call
        """

        logging.info("Trying to get a new user access token ... ")

        credential = Credentialutil.get_credentials(env_type)

        headers = util.generate_request_headers(credential)
        body = util.generate_refresh_request_body(' '.join(scopes), refresh_token)
        resp = requests.post(env_type.api_endpoint, data=body, headers=headers)
        content = json.loads(resp.content)
        token = OauthToken()
        token.token_response = content

        if resp.status_code == requests.codes.ok:
            token.access_token = content['access_token']
            token.token_expiry = datetime.utcnow() + timedelta(seconds=int(content['expires_in'])) - timedelta(
                minutes=5)
        else:
            token.error = str(resp.status_code) + ': ' + content['error_description']
            logging.error("Unable to retrieve token.  Status code: %s - %s", resp.status_code,
                          requests.status_codes._codes[resp.status_code])
            logging.error("Error: %s - %s", content['error'], content['error_description'])
        return token
