use gonidium::diag::DiagCode;
use gonidium::ir::DType;
use gonidium::{lower, parse_dsl};

#[test]
fn default_int_literal_is_i64() {
    let func = parse_dsl("||\n0").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::I8);

    let func = parse_dsl("||\n256").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::I16);
}

#[test]
fn default_negative_int_literal_is_i64() {
    let func = parse_dsl("||\n-1").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::I8);
}

#[test]
fn annotated_int_literal_dtype() {
    let func = parse_dsl("||\n-8@i8").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::I8);
}

#[test]
fn annotated_int_literal_out_of_range() {
    let func = parse_dsl("||\n256@u8").expect("parse");
    let err = lower(&func).expect_err("lower should fail");
    assert_eq!(err.code, DiagCode::LowerIntOutOfRange);
    assert!(err.message.contains("256"));
    assert!(err.message.contains("u8"));
}

#[test]
fn float_literal_precision_warning() {
    let func = parse_dsl("||\n1.222@f16").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::F16);
    let has_precision_warning = r
        .diags
        .iter()
        .any(|d| d.code == DiagCode::LowerFloatPrecisionLoss && d.message.contains("f16"));
    assert!(
        has_precision_warning,
        "expected precision loss warning for 1.222@f16"
    );
}

#[test]
fn default_float_and_complex() {
    let func = parse_dsl("||\n1.0").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::F16);

    let func = parse_dsl("||\n1.0j").expect("parse");
    let r = lower(&func).expect("lower");
    assert_eq!(r.dag.dtypes[r.dag.outputs[0].0], DType::C64);
}
