#!/usr/bin/env python3
"""Binary Transfer Lane for MCP - client shim (free downloadable artifact).

Mints a call-bound transfer, uploads the agent-generated file out-of-band,
and returns ONLY the receipt reference for the tool call's arguments -
the bytes never cross the model or the protocol.

Usage as a library:
    from client_shim import client_transfer
    ref = client_transfer(base, api_key, server_id, tool, call_id, data, mime)
    # ref == {"receipt": {...}, "signature": "...", "download_token": "..."}
"""
import hashlib, json, urllib.error, urllib.request


def _req(base, method, path, body=None, headers=None, raw_body=None):
    data = raw_body if raw_body is not None else (json.dumps(body).encode() if body is not None else None)
    r = urllib.request.Request(base.rstrip("/") + path, data=data, method=method, headers=headers or {})
    try:
        with urllib.request.urlopen(r, timeout=120) as resp:
            b = resp.read()
            return resp.status, (json.loads(b or b"{}") if b and b[:1] in (b"{", b"[") else b)
    except urllib.error.HTTPError as e:
        b = e.read()
        try:
            return e.code, json.loads(b or b"{}")
        except Exception:
            return e.code, {}


def client_transfer(base, api_key, server_id, tool, call_id, data, mime="application/octet-stream"):
    sha = hashlib.sha256(data).hexdigest()
    st, mint = _req(base, "POST", "/transfers",
                    {"server_id": server_id, "tool": tool, "call_id": call_id,
                     "mime": mime, "size": len(data), "sha256": sha},
                    headers={"Authorization": "Bearer " + api_key, "Content-Type": "application/json"})
    if st == 402:
        raise RuntimeError("payment required: pay the x402 challenge and resend with X-PAYMENT")
    if st != 201:
        raise RuntimeError(f"mint failed: {st} {mint}")
    st, up = _req(base, "PUT", mint["upload_path"], raw_body=data,
                  headers={"X-Upload-Token": mint["upload_token"], "Content-Type": mime})
    if st != 200:
        raise RuntimeError(f"upload failed: {st} {up}")
    return {"receipt": up["receipt"], "signature": up["signature"],
            "download_token": up["download_token"]}
