use rasm_core::codegen::err::{CodegenError, CodegenErrorKind};
use rasm_core::isa::MnemonicKind;

#[test]
fn display_wrong_operand_count() {
    let e = CodegenError::new(CodegenErrorKind::WrongOperandCount {
        mnemonic: MnemonicKind::Mov,
        expected: 2,
        got: 1,
    });
    assert_eq!(e.to_string(), "Mov expects 2 operand(s), got 1");
    assert_eq!(e.kind.to_string(), "Mov expects 2 operand(s), got 1");
}

#[test]
fn display_wrong_operand_count_add() {
    let e = CodegenError::new(CodegenErrorKind::WrongOperandCount {
        mnemonic: MnemonicKind::Add,
        expected: 2,
        got: 3,
    });
    assert_eq!(e.to_string(), "Add expects 2 operand(s), got 3");
}

#[test]
fn display_unsupported_operand_combination() {
    let e = CodegenError::new(CodegenErrorKind::UnsupportedOperandCombination);
    assert_eq!(e.to_string(), "unsupported operand combination");
}

#[test]
fn display_undefined_label() {
    let e = CodegenError::new(CodegenErrorKind::UndefinedLabel("foo".to_string()));
    assert_eq!(e.to_string(), "undefined label: 'foo'");
}

#[test]
fn display_undefined_label_empty() {
    let e = CodegenError::new(CodegenErrorKind::UndefinedLabel(String::new()));
    assert_eq!(e.to_string(), "undefined label: ''");
}

#[test]
fn display_undefined_label_with_underscores() {
    let e = CodegenError::new(CodegenErrorKind::UndefinedLabel("my_label".to_string()));
    assert_eq!(e.to_string(), "undefined label: 'my_label'");
}

#[test]
fn display_relocation_overflow_positive() {
    let e = CodegenError::new(CodegenErrorKind::RelocationOverflow {
        label: "target".to_string(),
        offset: 0x7FFFFFFF + 1,
    });
    assert!(e.to_string().contains("relocation overflow"));
    assert!(e.to_string().contains("target"));
}

#[test]
fn display_relocation_overflow_negative() {
    let e = CodegenError::new(CodegenErrorKind::RelocationOverflow {
        label: "backward".to_string(),
        offset: -(i32::MIN as i64) - 1,
    });
    assert!(e.to_string().contains("relocation overflow"));
    assert!(e.to_string().contains("backward"));
}

#[test]
fn debug_codegen_error() {
    let e = CodegenError::new(CodegenErrorKind::UnsupportedOperandCombination);
    let debug = format!("{e:?}");
    assert!(debug.contains("CodegenError"));
}

#[test]
fn codegen_error_kind_debug() {
    let kind = CodegenErrorKind::UndefinedLabel("x".into());
    let debug = format!("{kind:?}");
    assert!(debug.contains("UndefinedLabel"));
}

#[test]
fn codegen_error_display_all_kinds() {
    // Ensure all variants are covered by Display
    let kinds = [
        CodegenErrorKind::WrongOperandCount {
            mnemonic: MnemonicKind::Ret,
            expected: 0,
            got: 1,
        }
        .to_string(),
        CodegenErrorKind::UnsupportedOperandCombination.to_string(),
        CodegenErrorKind::UndefinedLabel("test".into()).to_string(),
        CodegenErrorKind::RelocationOverflow {
            label: "x".into(),
            offset: 9999999999,
        }
        .to_string(),
    ];
    for s in &kinds {
        assert!(!s.is_empty(), "Display produced empty string");
    }
}
