//! Conformance corpus for the quantum-ops extension (`quantum-ops-conformance/`).
//!
//! `wai.quantum.calibration` + `wai.quantum.job` receipts are portable JSON, signed
//! Ed25519 over a BLAKE3 Merkle root. Interop = a third party parses the JSON and
//! reproduces the checks: recompute the Merkle root, enforce the grant's joule
//! ceiling, verify the signature, confirm each content hash against the raw
//! artifact bytes, and (for a job) confirm the calibration cross-link. Each vector
//! is a `vectors/<name>.json` receipt + the `artifacts/` bytes it content-addresses;
//! `expected_hashes.json` pins every `receipt_hash`. Deterministic: pinned demo
//! signing keys + fixed content, so `gen` reproduces byte-identical vectors.
//!
//!   wai_quantum_ops_vectors gen <dir>  |  verify <dir>

use std::path::Path;

use wai_quantum::ed25519_dalek::SigningKey;
use wai::quantum_ops::{content_hash, CalibrationReceipt, Evidence, GrantRef, JobReceipt};

fn key(seed: u8) -> SigningKey {
    SigningKey::from_bytes(&[seed; 32])
}
fn hex(b: &[u8]) -> String {
    b.iter().map(|x| format!("{x:02x}")).collect()
}

// Deterministic artifact bytes the receipts content-address (placeholders for the
// vendor HDF5/QASM a real producer would hash; the corpus ships them so a verifier
// can reproduce the content-addressing).
const CFG_Q3: &[u8] = b"pulse-config q3 v7";
const RB_Q3: &[u8] = b"<HDF5 randomized-benchmarking dataset for q3>";
const CFG_CZ: &[u8] = b"pulse-config cz(q3,q4) v3";
const RB_CZ: &[u8] = b"<HDF5 interleaved-RB dataset for cz(q3,q4)>";
const CIRCUIT: &[u8] = b"OPENQASM 3.0; qubit[2] q; h q[0]; cx q[0], q[1];";
const RESULT: &[u8] = br#"{"counts":{"00":512,"11":488}}"#;

const LAB: &str = "did:key:demo-lab";
const DEVICE: &str = "example:lab3-device";

fn cal_q3() -> CalibrationReceipt {
    let ev = vec![Evidence {
        kind: "randomized_benchmarking".into(),
        blob_hash: content_hash(RB_Q3),
        summary: "1q RB fidelity 0.9992".into(),
    }];
    let grant = GrantRef {
        grant_hash: content_hash(b"grant:calibrate:lab3"),
        capability: "quantum.calibrate".into(),
        joule_ceiling_micro: 5_000_000,
        funds_ceiling: None,
    };
    CalibrationReceipt::seal(
        &key(0x11), LAB, DEVICE, "q3", content_hash(CFG_Q3), ev, 4_200_000, grant, None,
    )
}

fn cal_cz(parent: [u8; 32]) -> CalibrationReceipt {
    let ev = vec![Evidence {
        kind: "interleaved_rb".into(),
        blob_hash: content_hash(RB_CZ),
        summary: "cz gate fidelity 0.9871".into(),
    }];
    let grant = GrantRef {
        grant_hash: content_hash(b"grant:calibrate:lab3"),
        capability: "quantum.calibrate".into(),
        joule_ceiling_micro: 8_000_000,
        funds_ceiling: None,
    };
    CalibrationReceipt::seal(
        &key(0x11), LAB, DEVICE, "cz(q3,q4)", content_hash(CFG_CZ), ev, 6_800_000, grant,
        Some(parent),
    )
}

fn job_bell(cal_ref: [u8; 32]) -> JobReceipt {
    let grant = GrantRef {
        grant_hash: content_hash(b"grant:job:lab3"),
        capability: "quantum.job.run".into(),
        joule_ceiling_micro: 1_000_000,
        funds_ceiling: Some(50),
    };
    JobReceipt::seal(
        &key(0x22), LAB, "example:qpu-a", content_hash(CIRCUIT), content_hash(RESULT),
        Some(cal_ref), 1000, 250, grant, None,
    )
}

fn main() {
    let a: Vec<String> = std::env::args().collect();
    match (a.get(1).map(String::as_str), a.get(2)) {
        (Some("gen"), Some(d)) => generate(Path::new(d)),
        (Some("verify"), Some(d)) => verify(Path::new(d)),
        _ => {
            eprintln!("usage: wai_quantum_ops_vectors <gen|verify> <corpus-dir>");
            std::process::exit(2);
        }
    }
}

fn generate(dir: &Path) {
    let vd = dir.join("vectors");
    let ad = dir.join("artifacts");
    std::fs::create_dir_all(&vd).expect("mkdir vectors");
    std::fs::create_dir_all(&ad).expect("mkdir artifacts");

    // artifacts the receipts content-address
    for (name, bytes) in [
        ("cfg_q3.bin", CFG_Q3), ("rb_q3.bin", RB_Q3),
        ("cfg_cz.bin", CFG_CZ), ("rb_cz.bin", RB_CZ),
        ("circuit.qasm", CIRCUIT), ("result.json", RESULT),
    ] {
        std::fs::write(ad.join(name), bytes).expect("write artifact");
    }

    let cal_q3 = cal_q3();
    let cal_cz = cal_cz(cal_q3.receipt_hash());
    let job = job_bell(cal_q3.receipt_hash());

    for (name, json) in [
        ("cal_q3", cal_q3.to_json()),
        ("cal_cz", cal_cz.to_json()),
        ("job_bell", job.to_json()),
    ] {
        std::fs::write(vd.join(format!("{name}.json")), &json).expect("write vector");
    }

    let manifest = serde_json::json!({
        "extension": "wai.quantum.calibration + wai.quantum.job",
        "note": "Ed25519 over BLAKE3 Merkle; verify = merkle + joule-ceiling + signature (+ cross-link for the job).",
        "vectors": {
            "cal_q3": { "kind": "calibration", "receipt_hash": hex(&cal_q3.receipt_hash()), "verifies": true },
            "cal_cz": { "kind": "calibration", "receipt_hash": hex(&cal_cz.receipt_hash()),
                        "verifies": true, "parent": "cal_q3" },
            "job_bell": { "kind": "job", "receipt_hash": hex(&job.receipt_hash()),
                          "verifies": true, "calibration_ref": "cal_q3" },
        },
    });
    std::fs::write(
        dir.join("expected_hashes.json"),
        serde_json::to_string_pretty(&manifest).unwrap(),
    )
    .expect("write manifest");
    println!("generated quantum-ops corpus at {}", dir.display());
}

fn verify(dir: &Path) {
    let vd = dir.join("vectors");
    let read = |n: &str| std::fs::read_to_string(vd.join(n)).unwrap_or_else(|_| panic!("read {n}"));
    let manifest: serde_json::Value =
        serde_json::from_str(&std::fs::read_to_string(dir.join("expected_hashes.json")).expect("read manifest"))
            .expect("parse manifest");
    let want = |name: &str| {
        manifest["vectors"][name]["receipt_hash"].as_str().expect("expected hash").to_string()
    };

    let mut ok = true;
    let mut check = |name: &str, got: String, verifies: bool| {
        let expected = want(name);
        let pass = verifies && got == expected;
        println!("{} {name}  receipt_hash {}", if pass { "PASS" } else { "FAIL" }, &got[..16]);
        ok &= pass;
    };

    let cal_q3 = CalibrationReceipt::from_json(&read("cal_q3.json")).expect("parse cal_q3");
    check("cal_q3", hex(&cal_q3.receipt_hash()),
          cal_q3.verify() && cal_q3.evidence_matches(0, RB_Q3));

    let cal_cz = CalibrationReceipt::from_json(&read("cal_cz.json")).expect("parse cal_cz");
    check("cal_cz", hex(&cal_cz.receipt_hash()),
          cal_cz.verify()
              && cal_cz.evidence_matches(0, RB_CZ)
              && cal_cz.parent_receipt_hash == Some(cal_q3.receipt_hash()));

    let job = JobReceipt::from_json(&read("job_bell.json")).expect("parse job_bell");
    check("job_bell", hex(&job.receipt_hash()),
          job.verify()
              && job.result_matches(RESULT)
              && job.verify_against_calibration(&cal_q3)   // cross-link to the right state
              && !job.verify_against_calibration(&cal_cz)); // and NOT a different one

    if ok {
        println!("all vectors pass: signature + joule-ceiling + content-addressing + cross-link hold");
    } else {
        eprintln!("CORPUS FAILED");
        std::process::exit(1);
    }
}
