use betex::types::{
    AccountId, FillPrice, FillQuantity, MarketId, Money, OddsX10000, OrderId, Quantity,
};

#[test]
fn money_add_overflow_panics_in_debug() {
    let res = std::panic::catch_unwind(|| {
        let _ = Money(i64::MAX) + Money(1);
    });
    assert!(res.is_err(), "overflowing Money add should panic in debug");
}

#[test]
fn money_sub_overflow_panics_in_debug() {
    let res = std::panic::catch_unwind(|| {
        let _ = Money(i64::MIN) - Money(1);
    });
    assert!(res.is_err(), "overflowing Money sub should panic in debug");
}

#[test]
fn odds_from_decimal_rejects_non_finite_and_negative() {
    assert!(OddsX10000::from_decimal(f64::NAN).is_none());
    assert!(OddsX10000::from_decimal(f64::INFINITY).is_none());
    assert!(OddsX10000::from_decimal(-1.0).is_none());
}

#[test]
fn odds_display_preserves_4dp() {
    assert_eq!(format!("{}", OddsX10000(10_150)), "1.0150");
}

#[test]
fn display_impls_exist_for_types() {
    let line = format!(
        "{} {} {} {} {} {} {}",
        MarketId(1),
        OrderId(2),
        AccountId::from(3),
        Money(4),
        Quantity(5),
        FillPrice::Odds(OddsX10000(20_000)),
        FillQuantity::Stake(Money(6))
    );
    assert!(!line.is_empty());
}

#[test]
fn correlation_id_and_idempotency_key_round_trip_string() {
    use betex::types::{CorrelationId, IdempotencyKey};

    let cid = CorrelationId("abc-123".to_string());
    assert_eq!(cid.as_str(), "abc-123");
    assert_eq!(format!("{cid}"), "abc-123");

    let ik = IdempotencyKey("key-456".to_string());
    assert_eq!(ik.as_str(), "key-456");
    assert_eq!(format!("{ik}"), "key-456");
}

#[test]
fn account_id_round_trips_as_string() {
    let account_id = AccountId::from("acct-xyz");
    assert_eq!(account_id.as_str(), "acct-xyz");
    assert_eq!(format!("{account_id}"), "acct-xyz");

    let json = serde_json::to_string(&account_id).expect("serialize account id");
    assert_eq!(json, "\"acct-xyz\"");

    let decoded: AccountId = serde_json::from_str(&json).expect("deserialize account id");
    assert_eq!(decoded, account_id);
}

#[test]
fn account_id_can_be_created_from_uuid() {
    let uuid = uuid::Uuid::nil();
    let account_id = AccountId::from(uuid);
    assert_eq!(account_id.as_str(), uuid.to_string());

    let by_ref = AccountId::from(&uuid);
    assert_eq!(by_ref, account_id);
}
