## $Id$
##
## Copyright (C) 2022 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
import json
import requests
import uuid
from zope.component import getUtility, queryUtility
from kofacustom.nigeria.paypal.interfaces import IPaypalConfig


PAYPAL_REST_URLS = {
        'sandbox': 'https://api-m.sandbox.paypal.com',
        'live':    'https://api-m.paypal.com'}


def get_auth_token():
    """Get an authentication token from paypal

    Requests to paypal must provide an authorization token, which can be
    retrieved by sending REST credentials (`client_id` and `client_secret`) as
    provided in your Paypal developer account.

    During livespan of tokens, this call will not create new ones.
    """
    config = getUtility(IPaypalConfig)
    url = "%s/v1/oauth2/token" % PAYPAL_REST_URLS[config['mode']]
    auth = requests.auth.HTTPBasicAuth(
            config['client_id'], config['client_secret'])
    headers = {"content-type": "application/x-www-form-urlencoded"}
    params = [("grant_type", "client_credentials"), ]
    response = requests.post(url, auth=auth, headers=headers, params=params)
    response.raise_for_status()
    result = response.json()
    return result["access_token"]


def create_order(
        purchase_units, return_url, cancel_url,
        request_id=None, notify_url=None):
    token = get_auth_token()
    if request_id is None:
        request_id = str(uuid.uuid4())
    headers = {
        "content-type": "application/json",
        "authorization": "Bearer %s" % token,
        "paypal-request-id": request_id
    }

    json_data = {
            "intent": "CAPTURE",
            "payment_source": {
                "paypal": {
                    "experience_context": {
                        "landing_page": "NO_PREFERENCE",
                        "user_action": "CONTINUE",
                        "brand_name": "WAeUP",
                        "shipping_preference": "NO_SHIPPING",
                        "cancel_url": cancel_url,
                        "return_url": return_url}
                    }
                },
            "purchase_units": []
        }
    units = [x.json() for x in purchase_units]
    for n, unit in enumerate(units):
        unit["reference_id"] = n
        json_data["purchase_units"].append(unit)
    if notify_url:
        json_data["payment_source"]["paypal"][
                "experience_context"]["notify_url"] = notify_url
    config = getUtility(IPaypalConfig)
    url = "%s/v2/checkout/orders" % PAYPAL_REST_URLS[config['mode']]
    response = requests.post(url,
            headers=headers, json=json_data)
    try:
        response.raise_for_status()
    except requests.HTTPError as err:
        data = err.response.json()
        return None, None, request_id, data
    data = response.json()
    order_id = data['id']  # order token
    payment_link = [x for x in data['links']
            if x["rel"] == "payer-action"][0]["href"]
    return order_id, payment_link, request_id, data


def capture_order(order_id, request_id=None):
    config = getUtility(IPaypalConfig)
    token = get_auth_token()
    headers = {
        "content-type": "application/json",
        "authorization": "Bearer %s" % token,
        "paypal-request-id": request_id
    }
    if request_id is not None:
        headers["paypal-request-id"] = request_id
    url = "%s/v2/checkout/orders/%s/capture" % (
        PAYPAL_REST_URLS[config['mode']], order_id)
    response = requests.post(url, headers=headers)
    response.raise_for_status()
    data = response.json()
    return data
