//! `wai_video_meter` — the native sink-metering path for `wai.video.int_motion`,
//! the integer inter-frame video codec.
//!
//! Brackets the CPU energy a sink spends decoding an integer video codestream
//! to frames, with no elevated privileges: it samples the processor power the
//! non-privileged reader `macmon` reports, brackets a tight decode burst against
//! an idle baseline, and reports the **marginal** CPU energy attributable to the
//! decode. 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 its figure
//! is sealed `ModelBased`, never `OnChipCounter` (energy-measurement §3.1;
//! `wai::energy_burst::PowerSource`).
//!
//!   wai_video_meter <payload.wiv1 | bitstream.json> [receipt_out.json [report_out.json]]
//!                   [--no-report] [--previous-report <report.json>]
//!
//! The codestream is the `WIV1` payload `wai.video.int_motion` carries
//! (`extensions/integer-payloads.md` §3), and the receipt identifies it. Given a
//! tool's JSON bitstream instead, the meter converts it to `WIV1` first
//! (`int_payload::wiv1_from_json`) and meters and seals the converted payload.
//!
//! Video was the last cargo class with no meter: haptics, 4D splats, scores and
//! film are metered by `wai_meter`, worlds/feeds/avatars by `wai_world_meter`,
//! quantum circuits by `wai_quantum_meter`. It also has the strongest claim of
//! any of them, because its decode is not merely deterministic by construction
//! but **proven byte-identical on four architectures** by the cross-arch
//! matrix. So of everything the emitted receipt says, only the measurement —
//! `joules_micro` and the record of how it was obtained — rests on trusting this
//! machine; the result and the work can be re-derived from the codestream by
//! anyone, anywhere.
//!
//! Beside a measured figure it writes a measurement report
//! (energy-measurement §6): a `measurement` claim, signed with the receipt's key,
//! carrying the bracket's values, the build and the power reader. It goes beside
//! the receipt (`<receipt>.report.json`), to the path given, or to standard output
//! when no receipt path is given; `--no-report` turns it off, and says so.
//!
//! This is a bracket with stated bounds, exactly as the sibling meters: the
//! reported CPU power is SoC-wide, so the meter reports the DELTA over an
//! otherwise-idle machine (busy − idle mean power × window ÷ the decodes the
//! window paid for; see `wai::energy_burst`). Run it on a quiet box for a clean
//! number; it never fabricates one. Without `macmon`, or when the reported power
//! did not move (§3.1), or the §4 ratio cannot support a figure, it emits an
//! UNMETERED receipt — `joules_micro` carries the unmetered
//! marker `0`, never a figure of zero joules — and that receipt reports no rate
//! at all: an absent measurement must never be readable as "this decode was
//! free".

use ed25519_dalek::SigningKey;
use wai::energy_burst::{measure_with_macmon, power_reader};
use wai::energy_figure::meter_report;
use wai::energy_class::CounterFiltering;
use wai::video_receipt::{decode_wiv1, work_pixel_ops, Provenance, VideoReceipt};

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_video_meter <payload.wiv1 | bitstream.json> [receipt_out.json [report_out.json]] [--no-report] [--previous-report <report.json>]");
        std::process::exit(2);
    };

    let bytes = std::fs::read(path).expect("read the codestream");
    // The payload is WIV1; a JSON bitstream is the tools' form, converted first.
    let payload = if bytes.starts_with(b"WIV1") {
        bytes
    } else {
        let bs: serde_json::Value = serde_json::from_slice(&bytes).expect("neither a WIV1 payload nor a JSON bitstream");
        let p = wai::int_payload::wiv1_from_json(&bs, None).expect("the JSON bitstream converts to WIV1");
        eprintln!("{path} is a JSON bitstream: metering and sealing the WIV1 payload converted from it");
        p
    };
    // A decode that does not even run is not meterable.
    let clip = decode_wiv1(&payload).expect("codestream decodes");
    let (n, h, w) = (clip.frames.len() as u64, clip.h as u64, clip.w as u64);
    let work = work_pixel_ops(n, h, w);

    eprintln!(
        "metering {path} ({n} frames {h}x{w} RGB, work {work} subpixel-ops), \
         no sudo — the processor power macmon reports (ModelBased)"
    );

    // The §3 protocol (energy_burst): an idle bracket, then a decode burst on
    // several threads released together from a start barrier, with a busy
    // bracket over it. Many threads lift the marginal draw above the box's idle
    // fluctuation; the figure is the window's marginal energy over the work
    // the window paid for — the completions plus the half-finished decodes at
    // the close (C + N/2), since the window opened from rest.
    //
    // `Some((uj, class))` only when a figure was genuinely obtained. A
    // bracket that rounds to zero, or that §3.1 or the §4 ratio cannot support,
    // is a failure to measure, and it is reported as one.
    let mut values = None;
    let measured: Option<(u64, Provenance)> =
        match measure_with_macmon("decode", &payload, |p| {
            let _ = decode_wiv1(p);
        }) {
            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_video_meter — CPU energy bracket (the power macmon reports, no sudo): a figure only if the gate below seals it ==");
                print!("{}", b.report("decode"));
                match b.per_unit_uj() {
                    Some(per) => {
                        println!("→ per decode        : {per:.1} µJ   ({n} frames {h}x{w}, work {work})");
                        if work > 0 {
                            println!("→ per kilo-subpixel : {:.4} µJ", per * 1000.0 / work as f64);
                        }
                    }
                    None => println!("→ per decode        : no completion in the window"),
                }
                b.warn_if_unpublishable();
                // The samples are a power the reader reports, not a counter
                // read here, so the bracket seals `ModelBased` — never
                // `OnChipCounter`, whose liveness test (§3.1) was never run on
                // the counter behind the report. The filtering state applies
                // only to a counter's figure.
                match b.figure(CounterFiltering::Unknown) {
                    Some((uj, class)) => {
                        println!("joules_micro (receipt, {}): {uj}", class.label());
                        Some((uj, class))
                    }
                    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");
                        None
                    }
                }
            }
        };

    // The receipt carrying the measured (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(&[0x76u8; 32]); // 'v' for video-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-video-meter";
        let (uj, class) = match &measured {
            Some((uj, class)) => (*uj, Some(class.clone())),
            // With no reader present there is no measurement at all, and the
            // receipt says so by carrying no class rather than downgrading to a
            // label it also did not earn.
            None => (0, None),
        };
        let receipt = VideoReceipt::seal_decode_wiv1(&signer, signer_id, &payload, uj, class, None)
            .expect("seal receipt");
        assert!(receipt.verify(), "emitted receipt must verify");
        assert!(
            receipt.verify_reconstruction_wiv1(&payload),
            "emitted receipt must re-decode to the same frames"
        );
        let tag = measured.as_ref().map_or("UNMETERED", |(_, class)| class.label());
        if let Some(out) = args.get(2) {
            std::fs::write(out, receipt.to_json()).expect("write receipt");
            println!("receipt           : {out}  (verified, joules_micro {tag}, work {work})");
        }
        meter_report::write(
            &report_args,
            &receipt,
            None,
            values,
            power_reader(),
            &signer,
            signer_id,
            args.get(2).map(String::as_str),
            args.get(3).map(String::as_str),
        );
    }
}
