"""Server-side reseller adapter. Default demo uses synthetic orders only."""
import argparse
import hashlib
import json
import os
import time
from urllib.error import HTTPError, URLError
from urllib.parse import urlparse
from urllib.request import Request, urlopen


class ResellerClient:
    def __init__(self, origin, api_key):
        parsed = urlparse(origin)
        if parsed.scheme != "https" or not parsed.hostname or parsed.username or parsed.query or parsed.fragment:
            raise ValueError("Use your store's HTTPS origin")
        if not api_key:
            raise ValueError("API key is required")
        self.base = origin.rstrip("/") + "/reseller/v1"
        self.key = api_key

    def request(self, method, path, body=None, identity=None):
        encoded = None if body is None else json.dumps(body, separators=(",", ":"), sort_keys=True).encode()
        for attempt in range(5):
            headers = {"Authorization": "Bearer " + self.key, "Content-Type": "application/json"}
            if identity:
                headers["Idempotency-Key"] = identity
            request = Request(self.base + path, data=encoded, headers=headers, method=method)
            try:
                with urlopen(request, timeout=20) as response:
                    return json.loads(response.read(2_000_000))
            except HTTPError as error:
                if error.code not in (429, 503) or attempt == 4:
                    # Never log request headers, raw delivery bodies, or API keys.
                    raise RuntimeError(f"API HTTP {error.code}; request ID {error.headers.get('X-Request-ID', '-')}") from None
                delay = min(60, max(1, int(error.headers.get("Retry-After", "2"))))
            except (URLError, TimeoutError):
                if attempt == 4:
                    raise RuntimeError("Transport outcome unknown: retain the same order reference and retry key") from None
                delay = min(8, 2 ** attempt)
            time.sleep(delay)

    def create_order(self, product_id, quantity, client_order_id, max_total_minor, *, sandbox=True):
        if not client_order_id or max_total_minor < 1:
            raise ValueError("A durable customer order reference and maximum total are required")
        identity = "tt-client-" + hashlib.sha256(client_order_id.encode()).hexdigest()
        prefix = "/sandbox" if sandbox else ""
        return self.request("POST", prefix + "/orders", {
            "product_id": product_id,
            "quantity": quantity,
            "client_order_id": client_order_id,
            "max_total_minor": max_total_minor,
        }, identity)

    def order(self, order_id, *, sandbox=True):
        prefix = "/sandbox" if sandbox else ""
        return self.request("GET", prefix + "/orders/" + str(order_id))

    def delivery(self, order_id, *, sandbox=True):
        prefix = "/sandbox" if sandbox else ""
        return self.request("GET", prefix + "/orders/" + str(order_id) + "/delivery")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--origin", required=True)
    parser.add_argument("--reference", required=True, help="Persist your customer order ID; never change it to retry")
    parser.add_argument("--product", type=int, default=1)
    parser.add_argument("--quantity", type=int, default=1)
    parser.add_argument("--max-total-minor", type=int, default=100)
    parser.add_argument("--live", action="store_true", help="Explicitly spend real funds using an approved purchase key")
    args = parser.parse_args()
    client = ResellerClient(args.origin, os.environ.get("TRUSTEDTOOLS_API_KEY"))
    order = client.create_order(args.product, args.quantity, args.reference, args.max_total_minor, sandbox=not args.live)
    print(json.dumps({key: order[key] for key in ("id", "state", "total_minor") if key in order}))
    # Integrate delivery() into your private fulfillment handler; do not print credentials to logs.
