#!/usr/bin/env python3
"""BAPLIE Viewer Online API: minimal Python client (standard library only).

    export BVO_API_KEY=...        # your facility API key
    export BVO_PRIVATE_KEY=...    # your facility private key (never put it in a web page or app a user can open)
    python3 bvo_api.py my_baplie.edi
"""
import hashlib, json, os, sys, time, urllib.parse, urllib.request

BASE_URL = os.environ.get("BVO_BASE_URL", "https://api-gateway.baplieviewer.com/v4")
API_KEY = os.environ["BVO_API_KEY"]
PRIVATE_KEY = os.environ["BVO_PRIVATE_KEY"]


def make_hash(*values):
    """sha512 of the field values joined in the documented order, followed by the private key. Lowercase hex."""
    return hashlib.sha512(("".join(values) + PRIVATE_KEY).encode("utf-8")).hexdigest()


def call(path, fields):
    """POST form fields to an API call and return the reply body as text."""
    body = urllib.parse.urlencode(fields).encode("utf-8")
    request = urllib.request.Request(
        BASE_URL + "/" + path, data=body,
        headers={"x-api-key": API_KEY, "Content-Type": "application/x-www-form-urlencoded"})
    with urllib.request.urlopen(request, timeout=60) as response:
        return response.read().decode("utf-8")


def call_json(path, fields):
    reply = json.loads(call(path, fields))
    if reply.get("ack") != "success":
        raise RuntimeError("%s failed: %s" % (path, reply))
    return reply


if __name__ == "__main__":
    edi = open(sys.argv[1], encoding="utf-8").read()
    file_id = "demo%d" % int(time.time())

    # upload: hash = data + file_id + main_json + anomalies_json + private key
    up = call_json("upload", {
        "file_id": file_id, "data": edi, "main_json": "0", "anomalies_json": "0", "api_file_type": "BAPLIE",
        "hash": make_hash(edi, file_id, "0", "0")})
    file_upload_id = str(up["file_upload_id"])
    print("uploaded: file_upload_id", file_upload_id)

    # read the file back as JSON: hash = file_id + private key
    data = call_json("read/json", {"file_id": file_id, "hash": make_hash(file_id)})
    print("read/json ok, top level keys:", list(data)[:4])

    # 2D view: the reply is an HTML page that opens the viewer (see the integration guide).
    # user_id names the person using YOUR application. If this facility has no container list for that user the call answers error 502:
    # call view/restrictContainers once first (all_bays=1 lets the user see everything).
    html = call("view/2D", {"file_id": file_id, "user_id": "user-1", "hash": make_hash(file_id, "user-1")})
    print("view/2D returned", len(html), "bytes of HTML")

    # delete: hash = file_id + file_upload_id + private key
    call_json("delete/file", {"file_id": file_id, "file_upload_id": file_upload_id, "hash": make_hash(file_id, file_upload_id)})
    print("deleted")
