use gonidium::repl::{ReplConfig, ReplSession};

/// Basic sanity check: declaring inputs updates the header summary.
#[test]
fn repl_declares_inputs_and_shows_in_header() {
    let mut session = ReplSession::new(ReplConfig::default());

    let out1 = session.process_line("x: f32");
    assert!(
        out1.header.inputs_summary.contains("x: f32"),
        "inputs_summary should mention declared input x: f32, got: {}",
        out1.header.inputs_summary
    );

    let out2 = session.process_line("y: f64");
    assert!(
        out2.header.inputs_summary.contains("x: f32")
            && out2.header.inputs_summary.contains("y: f64"),
        "inputs_summary should contain both x: f32 and y: f64, got: {}",
        out2.header.inputs_summary
    );
}

/// Assignments should record locals and show them in the header summary.
#[test]
fn repl_assignment_updates_locals_in_header() {
    let mut session = ReplSession::new(ReplConfig::default());

    // Declare an input so the assignment type-checks.
    session.process_line("x: f32");

    let out = session.process_line("t1 = x + 1");
    assert!(
        out.header.locals_summary.contains("t1"),
        "locals_summary should mention t1, got: {}",
        out.header.locals_summary
    );
}

/// Bare expressions should produce at least one user-facing message line.
#[test]
fn repl_expression_produces_output_message() {
    let mut session = ReplSession::new(ReplConfig::default());

    let out = session.process_line("1 + 0");
    assert!(
        !out.messages.is_empty(),
        "expression line should produce at least one output message"
    );
    assert!(
        out.messages.iter().any(|m| m.contains(": ")
            && (m.ends_with("f64")
                || m.ends_with("i64")
                || m.ends_with("i8")
                || m.ends_with("f32"))),
        "expression output should include dtype annotation (expr: dtype), got: {:?}",
        out.messages
    );
}

#[test]
fn repl_invalid_dtype_emits_diag_and_keeps_inputs_unchanged() {
    let mut session = ReplSession::new(ReplConfig::default());

    let out = session.process_line("x: not_a_dtype");
    assert!(
        out.messages.iter().any(|m| m.contains("P002")),
        "invalid dtype should emit P002, got: {:?}",
        out.messages
    );
    assert!(
        out.header.inputs_summary == "inputs: (none)",
        "invalid dtype must not mutate inputs, got: {}",
        out.header.inputs_summary
    );
}

#[test]
fn repl_promotion_diag_updates_last_diag_summary() {
    let mut session = ReplSession::new(ReplConfig::default());
    session.process_line("x: f32");

    let out = session.process_line("x + 1");
    assert!(
        out.messages.iter().any(|m| m.contains("L301")),
        "expected implicit-promotion diag L301, got: {:?}",
        out.messages
    );
    assert!(
        out.header.last_diag_summary.contains("L301"),
        "last_diag_summary should track latest significant diag, got: {}",
        out.header.last_diag_summary
    );
}
