#!/usr/bin/env python3

#
# Get a paid voucher and tell the Tahoe-LAFS client node to redeem it for some
# ZKAPs from an issuer.  Exit with success when the Tahoe-LAFS client node
# reports that the voucher has been redeemed.
#

from sys import argv
from requests import post, get, put
from json import dumps
from time import sleep

def main():
    if len(argv) != 5:
        raise SystemExit(
            "usage: %s <client api root> <client api token path> <issuer api root> <voucher>",
        )
    clientAPIRoot, clientAPITokenPath, issuerAPIRoot, voucher = argv[1:]
    if not clientAPIRoot.endswith("/"):
        clientAPIRoot += "/"
    if not issuerAPIRoot.endswith("/"):
        issuerAPIRoot += "/"

    zkapauthz = clientAPIRoot + "storage-plugins/privatestorageio-zkapauthz-v1"

    with open(clientAPITokenPath) as p:
        clientAPIToken = p.read().strip()

    # Submit a charge to the issuer (which is also the PaymentServer).
    charge_response = post(
        issuerAPIRoot + "v1/stripe/charge",
        dumps(charge_json(voucher)),
        headers={
            "content-type": "application/json",
        },
    )
    charge_response.raise_for_status()

    # Tell the client to redeem the voucher.
    response = put(
        zkapauthz + "/voucher",
        dumps({"voucher": voucher}),
        headers={
            "content-type": "application/json",
            "authorization": "tahoe-lafs " + clientAPIToken,
        }

    )
    if response.status_code // 100 != 2:
        print("Unexpected response: {}".format(response.content))
        response.raise_for_status()

    # Poll the vouchers list for a while to see it get redeemed.
    def find_redeemed_voucher():
        response = get(
            zkapauthz + "/voucher/" + voucher,
            headers={
                "authorization": "tahoe-lafs " + clientAPIToken,
            },
        )
        response.raise_for_status()
        actual = response.json()
        print("Actual response: {}".format(actual))
        try:
            check = (
                actual["version"],
                actual["number"],
                actual["state"]["name"],
            )
        except Exception as e:
            print("Check failed: {}".format(e))
            return False
        else:
            print("Checking {}".format(check))
            return check == (1, voucher, "redeemed")

    retry(
        "find redeemed voucher",
        find_redeemed_voucher,
    )


def retry(description, f):
    for i in range(60):
        print("trying to {}...".format(description))
        if f():
            print("{} succeeded".format(description))
            return
        sleep(1.0)
    raise ValueError("failed to {} after many tries".format(description))


def charge_json(voucher):
    return {
        "token": "tok_abcdef",
        "voucher": voucher,
        "amount": "650",
        "currency": "USD",
    }

if __name__ == '__main__':
    main()