//! Headline RED-pin for issue #61 ("[series] Step 1 — primitive
//! Series over {Int, Float}"): the simple-moving-average (SMA) worked
//! example from `design/models/0007-kernel-extensions.md` §"Worked
//! example — `Series` for streaming analytics" must `ail build
//! --alloc=rc` to a native binary, run, and print the correct moving
//! averages.
//!
//! Property protected: the kernel-tier `Series` library extension
//! works end-to-end as an ordinary AILang consumer sees it — the bare
//! kernel-tier type `(con Series (con Float))`, construction via
//! `(new Series (con Float) 3)`, type-scoped ops `Series.push`,
//! `Series.at`, `Series.total_count`, the bounded ring-buffer
//! semantics (window size 3), financial-style indexing (index 0 =
//! newest), and count/total bookkeeping. This single fixture
//! transitively forces the whole Series surface to be correct: a
//! wrong ring-buffer, a wrong index orientation, or wrong total_count
//! bookkeeping would print different averages.
//!
//! The SMA fixture (`examples/series_sma.ail`) is the worked example
//! from model 0007 with two VERIFIED corrections applied:
//!   - `>=` (line 77 of 0007) replaced with the polymorphic Ord
//!     prelude helper `ge` — `>=` does not exist as a symbol; both
//!     operands here are `Int`.
//!   - a newline separator (`(do io/print_str "\n")`) appended to each
//!     emitted average — `print` emits no trailing newline, so without
//!     it the four averages concatenate into an unreadable, unassertable
//!     blob.
//! Everything else in the worked example is valid against today's tool.
//!
//! Why this is RED right now: the `series` kernel module does not exist
//! yet. `ail check examples/series_sma.ail` rejects with
//! `[bare-cross-module-type-ref]` — bare type `Series` not in scope,
//! candidate list empty — i.e. the feature is ABSENT, not a parse /
//! operator / scaffolding error. The GREEN side (authoring the kernel
//! `series` module + its 5 ops) is a later `implement` mini-mode
//! dispatch; this pin authors only the SMA *consumer*.
//!
//! This is a CLI-boundary E2E test because the acceptance spans the
//! check -> mono -> codegen -> link -> run pipeline and the symptom is
//! the printed moving averages of the produced binary.
//!
//! Expected stdout was derived by probing the live `%g`-style float
//! formatter INDEPENDENTLY of the (nonexistent) Series, so the
//! assertion encodes the intended averages formatted exactly as the
//! tool will format them once Series exists. Push stream
//! `1.0, 5.0, 3.0, 8.0, 6.0, 2.0`, window size 3, financial index
//! (0 = newest), `emit_if_full` emits once `total_count >= n`:
//!   - after push 3.0: (3+5+1)/3 =  9/3 -> "3.0"
//!   - after push 8.0: (8+3+5)/3 = 16/3 -> "5.33333"
//!   - after push 6.0: (6+8+3)/3 = 17/3 -> "5.66667"
//!   - after push 2.0: (2+6+8)/3 = 16/3 -> "5.33333"
//! Probe command (run this session):
//!   ./target/release/ail run /tmp/sma_probe.ail --alloc=rc
//!   where /tmp/sma_probe.ail printed each of 9.0/3, 16.0/3, 17.0/3,
//!   16.0/3 via `(app print (app / X (app int_to_float 3)))` separated
//!   by `(do io/print_str "\n")`. Captured bytes (od -c):
//!   `3.0\n5.33333\n5.66667\n5.33333\n`. After `.trim()`:
//!   `3.0\n5.33333\n5.66667\n5.33333`.

use std::path::{Path, PathBuf};
use std::process::Command;

fn repo_root() -> PathBuf {
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    Path::new(manifest_dir)
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .to_path_buf()
}

/// The SMA worked example from model 0007 (a pure consumer of the
/// kernel-tier `Series` type) must build under `--alloc=rc`, run, and
/// print the four correct moving averages, one per line. Green ⇒ the
/// `Series` ring buffer, financial indexing, and count bookkeeping all
/// work end-to-end.
#[test]
fn series_sma_worked_example_builds_runs_correct_output() {
    let fixture = repo_root().join("examples/series_sma.ail");
    let tmp = std::env::temp_dir().join(format!(
        "ailang_series_sma_{}",
        std::process::id()
    ));
    std::fs::create_dir_all(&tmp).unwrap();
    let out = tmp.join("bin");

    let build = Command::new(env!("CARGO_BIN_EXE_ail"))
        .args(["build", fixture.to_str().unwrap(), "--alloc=rc", "-o"])
        .arg(&out)
        .output()
        .expect("ail build failed to spawn");
    assert!(
        build.status.success(),
        "ail build --alloc=rc failed for the SMA worked example (the \
         kernel-tier `Series` library extension): stderr={}",
        String::from_utf8_lossy(&build.stderr)
    );

    let run = Command::new(&out).output().expect("execute binary");
    assert!(
        run.status.success(),
        "binary exited non-zero: {:?}",
        run.status
    );
    let stdout = String::from_utf8_lossy(&run.stdout);
    assert_eq!(
        stdout.trim(),
        "3.0\n5.33333\n5.66667\n5.33333",
        "expected the four simple-moving-averages of the stream \
         1.0,5.0,3.0,8.0,6.0,2.0 (window 3, financial index, emit once \
         total_count>=3), formatted by the live float formatter; got: {stdout:?}"
    );
}
