use armour_core::{KeyScheme, KeyType};

#[test]
fn typed_u32_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::U32]);
    let bytes = s.from_str("12345").unwrap();
    assert_eq!(bytes, 12345u32.to_be_bytes().to_vec());
    assert_eq!(s.to_string_repr(&bytes).unwrap(), "12345");
}

#[test]
fn typed_composite_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::U8, KeyType::U32, KeyType::U64]);
    let input = "1-42-1000000";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn typed_fuid_hex_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::Fuid]);
    let input = "abcdef0123456789";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn typed_array_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::Array(4)]);
    let input = "deadbeef";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn bytes_roundtrip() {
    let s = KeyScheme::Bytes;
    let input = "0102030405";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn length_mismatch_error() {
    let s = KeyScheme::Typed(&[KeyType::U32]);
    let too_short = vec![0u8; 3];
    assert!(s.to_string_repr(&too_short).is_err());
}

#[test]
fn typed_fuid_u32_composite_regression() {
    let s = KeyScheme::Typed(&[KeyType::Fuid, KeyType::U32]);
    let mut bytes = vec![0u8; 12];
    bytes[..8].copy_from_slice(&[0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89]);
    bytes[8..].copy_from_slice(&42u32.to_be_bytes());
    let repr = s.to_string_repr(&bytes).unwrap();
    assert_eq!(s.from_str(&repr).unwrap(), bytes);
}

#[test]
fn typed_accepts_single_component() {
    let s = KeyScheme::Typed(&[KeyType::U32]);
    assert_eq!(s.from_str("42").unwrap(), 42u32.to_be_bytes().to_vec());
}

#[test]
fn typed_all_key_types_roundtrip() {
    const SCHEMA: &[KeyType] = &[
        KeyType::U8,
        KeyType::U32,
        KeyType::U64,
        KeyType::Timestamp,
        KeyType::Fuid,
        KeyType::Array(4),
    ];
    let s = KeyScheme::Typed(SCHEMA);
    let mut bytes = Vec::new();
    bytes.push(7);
    bytes.extend_from_slice(&12345u32.to_be_bytes());
    bytes.extend_from_slice(&9876543210u64.to_be_bytes());
    bytes.extend_from_slice(&[0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
    bytes.extend_from_slice(&[0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11]);
    bytes.extend_from_slice(&[0xde, 0xad, 0xbe, 0xef]);

    let repr = s.to_string_repr(&bytes).unwrap();
    assert_eq!(s.from_str(&repr).unwrap(), bytes);
}

#[test]
fn composite_fuid_then_u32_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::U8, KeyType::Fuid, KeyType::U32]);
    let input = "1-abcdef0123456789-42";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(bytes.len(), 1 + 8 + 4);
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn composite_timestamp_then_u64_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::Timestamp, KeyType::U64]);
    let input = "00112233aabbccdd-999";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(bytes.len(), 8 + 8);
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn composite_array_then_u8_roundtrip() {
    let s = KeyScheme::Typed(&[KeyType::Array(4), KeyType::U8]);
    let input = "deadbeef-7";
    let bytes = s.from_str(input).unwrap();
    assert_eq!(bytes.len(), 4 + 1);
    assert_eq!(s.to_string_repr(&bytes).unwrap(), input);
}

#[test]
fn extra_components_rejected() {
    let s = KeyScheme::Typed(&[KeyType::U64]);
    assert!(
        s.from_str("1-999").is_err(),
        "trailing component should fail"
    );
}

#[test]
fn empty_component_rejected() {
    let s = KeyScheme::Typed(&[KeyType::U8, KeyType::U32]);
    assert!(s.from_str("1--42").is_err(), "empty component should fail");
}

#[test]
fn missing_component_rejected() {
    let s = KeyScheme::Typed(&[KeyType::U8, KeyType::U32]);
    assert!(s.from_str("1").is_err(), "missing component should fail");
}

#[test]
fn trailing_decimal_component_rejected() {
    let s = KeyScheme::Typed(&[KeyType::U8, KeyType::U32]);
    assert!(
        s.from_str("1-2-3").is_err(),
        "trailing decimal component should hit arity guard"
    );
}
