//! Gated behaviour-preservation proof for the consolidated OHLC opener (#80/#92):
//! the library `open_ohlc` over an epoch-ns `Timestamp` window produces a recorded
//! `(held, equity)` series BIT-IDENTICAL to opening the four `M1FieldSource`s by
//! hand over the equivalent Unix-ms window via the untouched ms-path `open`. Same
//! instants, same bars, same numbers — the migration changes the surface, not the
//! behaviour.
//!
//! Mirrors the other gated GER40 tests: skips with a note where the local
//! Pepperstone archive is absent, so `cargo test --workspace` stays green
//! anywhere; exercises the real path where the files exist.

use std::sync::Arc;

use aura_engine::{Harness, Source};
use chrono::TimeZone;
use data_server::{DataServer, DEFAULT_DATA_PATH};

use aura_ingest::{open_ohlc, M1Field, M1FieldSource};

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

/// Run a fresh harness over `sources` and drain the recorded `(held, equity)`
/// series (the same fold the determinism tests use).
fn series_from(mut h: Harness, taps: &Taps, sources: Vec<Box<dyn Source>>) -> Vec<(f64, f64)> {
    h.run(sources);
    drop(h);
    let trace = drain_trace(taps);
    trace.iter().map(|b| (b.held, b.equity)).collect()
}

/// Property: the Timestamp `open_ohlc` path and the hand-rolled ms-path `open`
/// (×4, in O/H/L/C order) over the equivalent window yield bit-identical recorded
/// series — behaviour-preserving consolidation (AC5).
#[test]
fn open_ohlc_timestamp_path_matches_ms_path_open() {
    let server = Arc::new(DataServer::new(DEFAULT_DATA_PATH));
    if !server.has_symbol(SYMBOL) {
        eprintln!("skip: no local data at {DEFAULT_DATA_PATH} (symbol {SYMBOL} absent)");
        return;
    }

    // September 2024 (inclusive UTC), the window the other gated tests pin.
    let from_ms = chrono::Utc.with_ymd_and_hms(2024, 9, 1, 0, 0, 0).unwrap().timestamp_millis();
    let to_ms = chrono::Utc.with_ymd_and_hms(2024, 9, 30, 23, 59, 59).unwrap().timestamp_millis();
    let from_ts = aura_ingest::unix_ms_to_epoch_ns(from_ms);
    let to_ts = aura_ingest::unix_ms_to_epoch_ns(to_ms);

    // Path A: the consolidated Timestamp opener.
    let (h_a, taps_a) = build_harness();
    let sources_a = open_ohlc(&server, SYMBOL, from_ts, to_ts).expect("window overlaps GER40 data");
    let series_a = series_from(h_a, &taps_a, sources_a);
    assert!(!series_a.is_empty(), "window resolved to zero bars");

    // Path B: the untouched ms-path open, four fields by hand in O/H/L/C order.
    let fields = [M1Field::Open, M1Field::High, M1Field::Low, M1Field::Close];
    let mut sources_b: Vec<Box<dyn Source>> = Vec::with_capacity(4);
    for &f in &fields {
        let s = M1FieldSource::open(&server, SYMBOL, Some(from_ms), Some(to_ms), f)
            .expect("window overlaps GER40 data");
        sources_b.push(Box::new(s));
    }
    let (h_b, taps_b) = build_harness();
    let series_b = series_from(h_b, &taps_b, sources_b);

    assert_eq!(
        series_a, series_b,
        "open_ohlc (Timestamp) must reproduce the ms-path open bit-identically (behaviour-preserving, #80/#92)",
    );
}
