"""Download, verify and inspect a pinned MicroDuck policy. No robot control.

Python 3.10+: python quickstart.py --policy walk --output ./microduck-policy
Optional interface inspection: pip install onnxruntime
The synthetic zero observation is a shape/finite-output check, not a rollout.
"""
import argparse
import hashlib
import json
from pathlib import Path
from urllib.request import urlopen

ORIGIN = "https://reachjalil-nottyduck.hf.space"
MAX_POLICY_BYTES = 4 * 1024 * 1024


def download(url, limit):
    with urlopen(url, timeout=60) as response:
        data = response.read(limit + 1)
    if len(data) > limit:
        raise ValueError("Download exceeds the inspection budget")
    return data


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--policy", default="walk", help="ID from /policy-catalog.json")
    parser.add_argument("--output", type=Path, default=Path("microduck-policy"))
    args = parser.parse_args()
    catalog = json.loads(download(ORIGIN + "/policy-catalog.json", 128 * 1024))
    manifest = json.loads(download(ORIGIN + "/asset-manifest.json", 128 * 1024))
    policy = next((p for p in catalog["policies"] if p["id"] == args.policy), None)
    if policy is None:
        parser.error("Choose one of: " + ", ".join(p["id"] for p in catalog["policies"]))
    item = next(p for p in manifest["files"] if p["path"] == policy["path"])
    if policy["sha256"] != item["sha256"] or catalog["release"] != manifest["prefix"]:
        raise ValueError("Catalog and manifest disagree")
    raw = download(ORIGIN + "/" + item["path"], MAX_POLICY_BYTES)
    if len(raw) != item["bytes"] or hashlib.sha256(raw).hexdigest() != item["sha256"]:
        raise ValueError("Policy failed checksum or size verification")
    args.output.mkdir(parents=True, exist_ok=True)
    target = args.output / Path(item["path"]).name
    target.write_bytes(raw)
    record = {"release": manifest["prefix"], "runtimeAssetVersion": manifest["runtimeAssetVersion"], "abi": catalog["abi"], "policy": policy}
    (args.output / "policy-record.json").write_text(json.dumps(record, indent=2) + "\n")
    print(f"Verified {policy['label']}: {len(raw):,} bytes")
    print(f"SHA-256 {item['sha256']}")
    print(f"Matching model: {policy['morphology']}")
    print(f"Commands: {policy['commandEncoding']}")
    print(f"Source: {policy['source']['url']}")
    print(f"License: {policy['license']}")
    try:
        import numpy as np
        import onnxruntime as ort
    except ImportError:
        print("Saved policy and source record. Install onnxruntime to inspect its interface.")
        return
    session = ort.InferenceSession(str(target), providers=["CPUExecutionProvider"])
    inputs, outputs = session.get_inputs(), session.get_outputs()
    if len(inputs) != 1 or inputs[0].name != "obs" or inputs[0].type != "tensor(float)" or inputs[0].shape != [1, 61]:
        raise ValueError("Unexpected input interface; do not deploy")
    if len(outputs) != 1 or outputs[0].name != "actions" or outputs[0].shape != [1, 14]:
        raise ValueError("Unexpected output interface; do not deploy")
    result = session.run(["actions"], {"obs": np.zeros((1, 61), dtype=np.float32)})[0]
    if result.shape != (1, 14) or not np.isfinite(result).all():
        raise ValueError("Synthetic interface check returned invalid actions")
    print("Interface verified: obs [1,61] -> actions [1,14], finite synthetic output.")
    print("This is not a simulator rollout, task-success score or hardware validation.")
    print("Use the native MJLab workflow for training, export and deployment rehearsal.")


if __name__ == "__main__":
    main()
