//! Runnable World-family demo: **`compare`** the session-breakout `Composite`
//! blueprint across two structural axes (C11/C20 experiment matrix),
//! on REAL data, with NO re-authoring:
//!
//! 1. **Instrument** — GER40 vs FRA40 (both `pip_size = 1.0`, index points), the
//!    SAME blueprint bootstrapped at the same `{entry=3, exit=5}` point over each
//!    symbol. The pip honesty is by construction (both quote in index points; the
//!    pip is sourced per cell from the recorded geometry sidecar — #22
//!    shipped).
//! 2. **Bar period** — a 15m blueprint vs a 30m blueprint. The bar period is a
//!    STRUCTURAL axis (C34): `ger40_breakout_blueprint` is instantiated TWICE,
//!    at 15 and at 30, each a *different strategy* (the period is bound at
//!    construction, locking Resample and Session equal — it is NOT a sweep param).
//!
//! A "comparison" here is a plain Rust loop over the matrix (C20): one blueprint
//! per matrix cell, each bootstrapped + run + summarized, the reports tabulated.
//!
//! Run:
//! ```text
//! cargo run -p aura-ingest --example ger40_breakout_compare
//! ```
//! Prints both comparison tables. Skips a row cleanly where a symbol is absent.

use std::sync::Arc;

use aura_core::{Cell, Scalar, Timestamp};
use aura_engine::{summarize, RunMetrics};
use chrono_tz::Europe::Berlin;

use aura_ingest::{default_data_server, open_ohlc, DataServer, DEFAULT_DATA_PATH};

#[path = "shared/breakout_real.rs"]
mod breakout_real;
use breakout_real::*;

// The baseline tuning point both axes hold fixed (so only the structural axis
// varies): entry bar 3, exit bar 5 — the shipped baseline.
const ENTRY_BAR: i64 = 3;
const EXIT_BAR: i64 = 5;

// GER40 and FRA40 both quote in index points, so pip_size = 1.0 for both — the
// only reason a cross-instrument pip comparison is honest here. The pip is sourced
// per cell from the recorded geometry sidecar (#22 shipped), not a
// literal carried here. (symbol, human note)
const INSTRUMENTS: &[(&str, &str)] = &[("GER40", "index point"), ("FRA40", "index point")];

/// Bootstrap the blueprint (at `bar_period`) at `{entry=3, exit=5}`, run it over
/// `[from, to]` (epoch-ns) of real `symbol` OHLC, and summarize — or `None` if the
/// symbol has no file overlapping the window. The `pip_size` is sourced per cell
/// from the recorded geometry sidecar (always 1.0 here; both
/// indices) and rides on the blueprint's baked SimBroker. Returns the report plus
/// the entry count (0→1 transitions of held).
fn run_cell(
    server: &Arc<DataServer>,
    symbol: &str,
    bar_period: i64,
    from: Timestamp,
    to: Timestamp,
) -> Option<(RunMetrics, u32)> {
    let pip_size = pip_size_of(symbol);
    let (bp, taps) =
        ger40_breakout_blueprint(pip_size, bar_period, SESSION_HOUR, SESSION_MINUTE, Berlin);
    let point: Vec<Cell> = bp
        .param_space()
        .iter()
        .map(|ps| match ps.name.as_str() {
            "entry_bar.target" => Scalar::i64(ENTRY_BAR).cell(),
            "exit_bar.target" => Scalar::i64(EXIT_BAR).cell(),
            other => panic!("unexpected param slot {other}"),
        })
        .collect();
    let mut h = bp.bootstrap_with_cells(&point).expect("point kind-checked");

    let srcs = open_ohlc(server, symbol, from, to)?;
    h.run(srcs);
    drop(h);

    let equity: Vec<(Timestamp, f64)> = taps
        .equity
        .try_iter()
        .map(|(t, r)| (t, as_f64(&r[0])))
        .collect();
    let held: Vec<(Timestamp, f64)> = taps
        .held
        .try_iter()
        .map(|(t, r)| (t, as_f64(&r[0])))
        .collect();

    // Count entries (0 -> 1 transitions of held).
    let mut entries = 0u32;
    let mut prev = 0.0_f64;
    for (_, v) in &held {
        if *v == 1.0 && prev == 0.0 {
            entries += 1;
        }
        prev = *v;
    }
    Some((summarize(&equity, &held), entries))
}

fn main() {
    let server = default_data_server();
    if !server.has_symbol(SYMBOL) {
        println!("skip: no local data at {DEFAULT_DATA_PATH} (symbol {SYMBOL} absent).");
        return;
    }

    // Full year 2024 (the same UTC span, via the shared Timestamp helper).
    let (from, _) = utc_month_window(2024, 1);
    let (_, to) = utc_month_window(2024, 12);

    println!("=== GER40 session-breakout — World `compare` (structural matrix) ===");
    println!("window=2024 (UTC, full year), fixed tuning point entry={ENTRY_BAR}, exit={EXIT_BAR}\n");

    // --- Axis 1: instrument (GER40 vs FRA40), 15m blueprint. -----------------
    println!("--- axis 1: instrument (same 15m blueprint, GER40 vs FRA40) ---");
    println!(
        "{:<8} {:<14} {:>9} {:>11} {:>10} {:>7}",
        "symbol", "pip-meaning", "sessions", "total_pips", "max_dd", "flips"
    );
    println!("{}", "-".repeat(62));
    for &(symbol, note) in INSTRUMENTS {
        if !server.has_symbol(symbol) {
            println!("{symbol:<8} (no local data — skip)");
            continue;
        }
        match run_cell(&server, symbol, BAR_MINUTES, from, to) {
            Some((m, entries)) => println!(
                "{symbol:<8} {note:<14} {entries:>9} {:>11.1} {:>10.1} {:>7}",
                m.total_pips, m.max_drawdown, m.bias_sign_flips
            ),
            None => println!("{symbol:<8} (no overlapping OHLC files — skip)"),
        }
    }
    println!();

    // --- Axis 2: bar period (15m vs 30m blueprint), GER40. -------------------
    // The STRUCTURAL axis: ger40_breakout_blueprint instantiated at 15 AND at 30
    // — two *different strategies* (the period binds Resample AND Session equal at
    // construction; it is not a sweep param). C34 / C11.
    println!("--- axis 2: bar period (GER40, 15m blueprint vs 30m blueprint) ---");
    println!(
        "{:<10} {:>9} {:>11} {:>10} {:>7}",
        "bar-period", "sessions", "total_pips", "max_dd", "flips"
    );
    println!("{}", "-".repeat(52));
    for &period in &[15_i64, 30] {
        match run_cell(&server, SYMBOL, period, from, to) {
            Some((m, entries)) => println!(
                "{:<10} {entries:>9} {:>11.1} {:>10.1} {:>7}",
                format!("{period}m"),
                m.total_pips,
                m.max_drawdown,
                m.bias_sign_flips,
            ),
            None => println!("{period}m (no data — skip)"),
        }
    }

    println!("\nOK: one blueprint, two structural axes (instrument + bar period) compared");
    println!("    with no re-authoring — the bar period is a construction arg (15m and 30m");
    println!("    are different strategies, C34), the instrument a plain matrix loop (C20).");
}

fn as_f64(s: &Scalar) -> f64 {
    match s {
        Scalar::F64(v) => *v,
        other => panic!("expected f64, got {other:?}"),
    }
}
