use mad_hatter::MadError;

// --- Test enum: mixed variants ---

#[derive(Debug, MadError)]
pub enum AppError {
    #[humanize("Resource '{id}' not found")]
    NotFound { id: String },

    #[humanize("Unauthorized access")]
    Unauthorized,

    #[humanize("Relay failed: {from} -> {to}")]
    RelayFailed { from: String, to: String },

    #[humanize("Database error: {detail}")]
    DbError { detail: String, code: i32 },

    #[humanize("Validation failed on '{field}': {reason}")]
    ValidationError { field: String, reason: String },

    #[humanize("Request timed out")]
    Timeout,
}

// --- Tests ---

#[test]
fn test_display_named_single_field() {
    let err = AppError::NotFound { id: "abc123".into() };
    assert_eq!(format!("{}", err), "Resource 'abc123' not found");
}

#[test]
fn test_display_unit_variant() {
    let err = AppError::Unauthorized;
    assert_eq!(format!("{}", err), "Unauthorized access");
}

#[test]
fn test_display_multi_field() {
    let err = AppError::RelayFailed {
        from: "node-1".into(),
        to: "node-2".into(),
    };
    assert_eq!(format!("{}", err), "Relay failed: node-1 -> node-2");
}

#[test]
fn test_display_partial_fields() {
    // DbError has `detail` and `code`, but template only uses `detail`
    let err = AppError::DbError {
        detail: "connection reset".into(),
        code: 500,
    };
    assert_eq!(format!("{}", err), "Database error: connection reset");
}

#[test]
fn test_display_two_field_validation() {
    let err = AppError::ValidationError {
        field: "email".into(),
        reason: "invalid format".into(),
    };
    assert_eq!(
        format!("{}", err),
        "Validation failed on 'email': invalid format"
    );
}

#[test]
fn test_display_unit_timeout() {
    let err = AppError::Timeout;
    assert_eq!(format!("{}", err), "Request timed out");
}

#[test]
fn test_humanize_returns_sealed() {
    let err = AppError::NotFound { id: "xyz".into() };
    let sealed = err.humanize();
    // We can't access value() from outside mad-hatter crate,
    // but we can verify it's the right type via Debug
    let debug = format!("{:?}", sealed);
    assert!(debug.contains("xyz"));
}

#[test]
fn test_humanize_unit_variant() {
    let err = AppError::Unauthorized;
    let sealed = err.humanize();
    let debug = format!("{:?}", sealed);
    assert!(debug.contains("Unauthorized"));
}

#[test]
fn test_humanize_multi_field() {
    let err = AppError::RelayFailed {
        from: "a".into(),
        to: "b".into(),
    };
    let sealed = err.humanize();
    let debug = format!("{:?}", sealed);
    assert!(debug.contains("a"));
    assert!(debug.contains("b"));
}

#[test]
fn test_error_trait_impl() {
    let err = AppError::NotFound { id: "test".into() };
    // Verify Error trait is implemented by using it as &dyn Error
    let _: &dyn std::error::Error = &err;
}

#[test]
fn test_error_source_is_none() {
    let err = AppError::NotFound { id: "test".into() };
    let err_ref: &dyn std::error::Error = &err;
    assert!(err_ref.source().is_none());
}

// --- Separate enum: single variant ---

#[derive(Debug, MadError)]
pub enum SimpleError {
    #[humanize("Unauthorized access")]
    OnlyVariant,
}

#[test]
fn test_single_variant_enum() {
    let err = SimpleError::OnlyVariant;
    assert_eq!(format!("{}", err), "Unauthorized access");
}

// --- Named fields with no placeholders (all fields ignored) ---

#[derive(Debug, MadError)]
pub enum IgnoreFieldsError {
    #[humanize("Something went wrong")]
    HasFieldsButIgnored { detail: String, code: i32 },
}

#[test]
fn test_named_fields_no_placeholders() {
    let err = IgnoreFieldsError::HasFieldsButIgnored {
        detail: "unused".into(),
        code: 42,
    };
    assert_eq!(format!("{}", err), "Something went wrong");
}

// --- Chinese template ---

#[derive(Debug, MadError)]
pub enum ChineseError {
    #[humanize("实例{id}找不到")]
    NotFound { id: String },

    #[humanize("中继失败：从{from}到{to}")]
    RelayFailed { from: String, to: String },

    #[humanize("未授权访问")]
    Unauthorized,
}

#[test]
fn test_chinese_single_placeholder() {
    let err = ChineseError::NotFound { id: "abc".into() };
    assert_eq!(format!("{}", err), "实例abc找不到");
}

#[test]
fn test_chinese_multi_placeholder() {
    let err = ChineseError::RelayFailed {
        from: "节点1".into(),
        to: "节点2".into(),
    };
    assert_eq!(format!("{}", err), "中继失败：从节点1到节点2");
}

#[test]
fn test_chinese_no_placeholder() {
    let err = ChineseError::Unauthorized;
    assert_eq!(format!("{}", err), "未授权访问");
}