"""Synthetic SReverse workflow. All keys and credentials are public test values."""
import base64, hashlib, hmac, json, os, secrets, time, urllib.error, urllib.request
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

BASE = os.environ.get("SREVERSE_DEMO_BASE", "http://127.0.0.1:8787")
SIGNING_KEY = b"sreverse-public-demo-signing-key"
ENCRYPTION_KEY = bytes(range(32))

def post(path, value, headers=None):
    body = json.dumps(value, separators=(",", ":")).encode()
    request = urllib.request.Request(BASE + path, data=body, method="POST", headers={"Content-Type": "application/json", **(headers or {})})
    try:
        with urllib.request.urlopen(request) as response:
            return response.status, json.load(response)
    except urllib.error.HTTPError as error:
        return error.code, json.load(error)

login_status, login = post("/v1/login", {"username": "demo", "password": "demo"})
assert login_status == 200
refresh_status, refresh = post("/v1/refresh", {"refresh_token": login["refresh_token"]})
assert refresh_status == 200 and refresh["refresh_token"] == "refresh-2"

iv = secrets.token_bytes(12)
ciphertext = AESGCM(ENCRYPTION_KEY).encrypt(iv, json.dumps({"reference": "ABC123"}, separators=(",", ":")).encode(), None)
envelope = {"iv": base64.b64encode(iv).decode(), "ciphertext": base64.b64encode(ciphertext).decode()}
body = json.dumps(envelope, separators=(",", ":"))
timestamp = str(int(time.time()))
nonce = secrets.token_hex(16)
message = f"POST\n/v1/lookup\n{timestamp}\n{nonce}\n{body}".encode()
signature = hmac.new(SIGNING_KEY, message, hashlib.sha256).hexdigest()
headers = {"Authorization": f"Bearer {refresh['access_token']}", "X-Timestamp": timestamp, "X-Nonce": nonce, "X-Signature": signature}
lookup_status, lookup = post("/v1/lookup", envelope, headers)
assert lookup_status == 200 and lookup["reference"] == "ABC123"
bad_status, bad = post("/v1/lookup", envelope, {**headers, "X-Signature": "bad"})
assert bad_status == 403 and bad["error"] == "invalid_signature"
print(json.dumps({"login": login_status, "rotated_refresh_token": refresh["refresh_token"], "lookup": lookup, "rejected_bad_signature": bad_status}, indent=2))
