//! `wai_quantum_meter` — the native sink-metering path for a
//! `wai.quantum.circuit2` or `wai.quantum.circuit` reconstruction's energy
//! (extensions/quantum-sim § Receipt). The circuit is read from its `WQC2` or
//! `WQC1` container and keeps that container's gateset, so the receipt's
//! circuit hash binds the capability the file was written under.
//!
//! Brackets the CPU energy a classical sink spends reconstructing a WQC
//! circuit's statevector, with no elevated privileges: it samples the processor
//! power the non-privileged reader `macmon` reports, brackets a tight
//! reconstruction burst against an idle baseline, and reports the **marginal**
//! CPU energy attributable to the simulation. That power is one the reader
//! reports from a channel it selects, not a counter this meter reads (on macOS
//! 27 the processor channels of IOReport's `Energy Model` group stop updating
//! for an unprivileged reader), so the figure is `ModelBased`, never
//! `OnChipCounter` (energy-measurement §3.1; `wai::energy_burst::PowerSource`).
//!
//!   wai_quantum_meter <circuit.wqc> [receipt_out.json [report_out.json]]
//!                     [--no-report] [--previous-report <report.json>]
//!
//! Output: bracketed microjoules per reconstruction, the figure that fills a
//! receipt's `joules_micro` with its class. With a second argument the meter
//! emits a signed [`QuantumReceipt`](wai::quantum_receipt::QuantumReceipt)
//! carrying that figure, self-verified — a portable receipt whose *result* and
//! *work* anyone can re-check by re-simulation, and whose *energy* the signer
//! attests.
//!
//! This is a bracket with stated bounds, exactly as `wai_world_meter`: the
//! reported CPU power is SoC-wide, so the meter reports the DELTA over an
//! otherwise-idle machine (busy − idle mean power × window ÷ the
//! reconstructions the window paid for; see `wai::energy_burst`). Run it on a
//! quiet box for a clean number; it never fabricates one. A usable figure is
//! sealed with its acquisition class — `ModelBased`, as a
//! `quantum_energy::Labelled` receipt; without `macmon`, or when the reported
//! power did not move (§3.1), or the §4 ratio cannot support a figure, the
//! receipt is sealed UNMETERED:
//! `joules_micro` carries the unmetered marker `0`, unlabelled, never a figure
//! of zero joules. Beside a measured figure it writes a measurement report
//! (energy-measurement §6), a `measurement` claim signed with the receipt's key —
//! beside the receipt (`<receipt>.report.json`), at the path given, or to
//! standard output; `--no-report` turns it off, and says so. Because a
//! quantum computation carries no speedup here, this energy — and the
//! exponential `work_amp_updates = n_ops·2^n` beside it — is precisely what the
//! receipt makes auditable. No quantum hardware is involved.

use wai::energy_burst::{measure_with_macmon, power_reader};
use wai::energy_figure::meter_report;
use wai::energy_class::{to_quantum_class, CounterFiltering, EnergyProvenance};
use wai::quantum::from_wqc;
use wai::quantum_energy::{Labelled, MaybeLabelled};
use wai::quantum_receipt::{work_amp_updates, QuantumReceipt};
use wai_quantum::ed25519_dalek::SigningKey;

fn main() {
    let report_args = meter_report::parse_args_or_exit(&std::env::args().collect::<Vec<_>>());
    let args = &report_args.positional;
    let Some(path) = args.get(1) else {
        eprintln!("usage: wai_quantum_meter <circuit.wqc> [receipt_out.json [report_out.json]] [--no-report] [--previous-report <report.json>]");
        std::process::exit(2);
    };

    let bytes = std::fs::read(path).expect("read wqc");
    let (circuit, measure) = from_wqc(&bytes).expect("parse wqc");
    // A reconstruction that does not even run is not meterable.
    circuit.simulate().expect("circuit reconstructs");
    let n = circuit.n_qubits;
    let n_ops = circuit.ops.len() as u32;
    let work = work_amp_updates(n, n_ops);

    eprintln!(
        "metering {path} ({}, {n} qubits, {n_ops} ops, work {work} amp-updates), \
         no sudo — the processor power macmon reports (ModelBased)",
        circuit.gateset.capability()
    );

    // The §3 protocol (energy_burst): an idle bracket, then reconstructions on
    // several threads released together from a start barrier, counted per
    // reconstruction — never per batch — with a busy bracket over them.
    let mut values = None;
    let measured: Option<(u64, EnergyProvenance)> = match measure_with_macmon("reconstruction", &circuit, |c| {
        let _ = c.simulate();
    }) {
        None => {
            eprintln!(
                "macmon unavailable or too few samples; emitting an UNMETERED receipt \
                 (joules_micro carries the unmetered marker 0). Install `brew install macmon` (a non-sudo \
                 power reader) for a ModelBased figure."
            );
            None
        }
        Some(b) => {
            values = b.values();
            println!("== wai_quantum_meter — CPU energy bracket (the power macmon reports, no sudo): a figure only if the gate below seals it ==");
            print!("{}", b.report("reconstruction"));
            if let Some(per) = b.per_unit_uj() {
                println!("→ per reconstruction: {per:.3} µJ   ({n} qubits, work {work})");
            }
            b.warn_if_unpublishable();
            // A reported power seals `ModelBased`, never `OnChipCounter` (§3.1).
            let m = b.figure(CounterFiltering::Unknown);
            match &m {
                Some((uj, class)) => println!("joules_micro (receipt, {}): {uj}", class.label()),
                None => {
                    eprintln!(
                        "no usable figure obtained ({:.1}x noise: {}); emitting an \
                         UNMETERED receipt rather than sealing a number the measurement does \
                         not support.",
                        b.ratio(),
                        b.unsealed_reason().unwrap_or("refused")
                    );
                    println!("joules_micro (receipt, UNMETERED): 0, the unmetered marker: the bracket above is no figure this receipt carries");
                }
            }
            m
        }
    };
    let joules_micro = measured.as_ref().map_or(0, |(uj, _)| *uj);

    // The receipt carrying the bracketed (or unmetered) energy, written when a
    // path is given; its report is written whether or not it is.
    {
        // A native sink signs with its own identity key; this metering tool
        // uses a fixed, clearly-labeled demo signer.
        let signer = SigningKey::from_bytes(&[0x71u8; 32]); // 'q' for quantum-meter
        // A demo signer whose seed is published: a label, never origin-bound (jwp-receipts §7.1, §7.8).
        let signer_id = "did:example:wai-quantum-meter";
        let receipt = QuantumReceipt::seal(
            &signer,
            signer_id,
            &circuit,
            measure,
            joules_micro,
            None,
        )
        .expect("seal receipt");
        let (sealed, tag) = match &measured {
            Some((_, class)) => {
                let label = class.label();
                let class = to_quantum_class(class).expect("a class the meter seals has a quantum counterpart");
                let l = Labelled::seal(receipt, class, &signer).expect("a usable figure is a valid label");
                assert!(l.verify(), "emitted receipt must verify");
                assert!(l.verify_reconstruction(&circuit), "emitted receipt must re-simulate to the same statevector");
                (MaybeLabelled::Labelled(l), label)
            }
            None => {
                assert!(receipt.verify(), "emitted receipt must verify");
                assert!(
                    receipt.verify_reconstruction(&circuit),
                    "emitted receipt must re-simulate to the same statevector"
                );
                (MaybeLabelled::Unlabelled(receipt), "UNMETERED")
            }
        };
        if let Some(out) = args.get(2) {
            std::fs::write(out, sealed.to_json()).expect("write receipt");
            println!("receipt           : {out}  (verified, joules_micro {tag}, work {work})");
        }
        meter_report::write(
            &report_args,
            &sealed,
            None,
            values,
            power_reader(),
            &signer,
            signer_id,
            args.get(2).map(String::as_str),
            args.get(3).map(String::as_str),
        );
    }
}
