use super::*;

fn test_node_id(n: u8) -> NodeId {
    NodeId::from_bytes([n; 16])
}

#[test]
fn test_range_descriptor_contains_key() {
    let desc = RangeDescriptor::new(
        0,
        Some(b"aaa".to_vec()),
        Some(b"zzz".to_vec()),
        vec![test_node_id(1)],
    );

    assert!(desc.contains_key(b"aaa")); // Inclusive start
    assert!(desc.contains_key(b"mmm"));
    assert!(!desc.contains_key(b"zzz")); // Exclusive end
    assert!(!desc.contains_key(b"000")); // Before start
}

#[test]
fn test_range_descriptor_full_range() {
    let desc = RangeDescriptor::new_full_range(0, vec![test_node_id(1)]);

    assert!(desc.contains_key(b""));
    assert!(desc.contains_key(b"anything"));
    assert!(desc.contains_key(&[255u8; 100]));
}

#[test]
fn test_range_descriptor_leader_followers() {
    let replicas = vec![test_node_id(1), test_node_id(2), test_node_id(3)];
    let desc = RangeDescriptor::new_full_range(0, replicas);

    assert_eq!(desc.leader(), Some(test_node_id(1)));
    assert_eq!(desc.followers().len(), 2);
    assert_eq!(desc.followers()[0], test_node_id(2));
    assert_eq!(desc.followers()[1], test_node_id(3));
}

#[test]
fn test_range_descriptor_adjacency() {
    let desc1 = RangeDescriptor::new(0, None, Some(b"mmm".to_vec()), vec![test_node_id(1)]);

    let desc2 = RangeDescriptor::new(1, Some(b"mmm".to_vec()), None, vec![test_node_id(2)]);

    assert!(desc1.is_adjacent_to(&desc2));
    assert!(desc2.is_adjacent_to(&desc1));

    let desc3 = RangeDescriptor::new(2, Some(b"nnn".to_vec()), None, vec![test_node_id(3)]);

    assert!(!desc1.is_adjacent_to(&desc3));
}

#[test]
fn test_meta_range_initial_shards() {
    let nodes = vec![test_node_id(1), test_node_id(2), test_node_id(3)];
    let meta = MetaRange::with_initial_shards(6, &nodes, 2);

    assert_eq!(meta.num_shards(), 6);

    // Each shard should have 2 replicas (replication_factor)
    for desc in meta.descriptors.values() {
        assert_eq!(desc.replicas.len(), 2);
    }

    // Check round-robin distribution
    let shard0 = meta.get(0).unwrap();
    assert_eq!(shard0.leader(), Some(test_node_id(1)));

    let shard1 = meta.get(1).unwrap();
    assert_eq!(shard1.leader(), Some(test_node_id(2)));

    let shard2 = meta.get(2).unwrap();
    assert_eq!(shard2.leader(), Some(test_node_id(3)));
}

#[test]
fn test_meta_range_shards_for_node() {
    let nodes = vec![test_node_id(1), test_node_id(2), test_node_id(3)];
    let meta = MetaRange::with_initial_shards(6, &nodes, 2);

    let shards = meta.shards_for_node(test_node_id(1));
    // Node 1 should be replica for multiple shards due to round-robin
    assert!(!shards.is_empty());
}

#[test]
fn test_meta_range_merge() {
    let nodes = vec![test_node_id(1), test_node_id(2)];
    let mut meta1 = MetaRange::with_initial_shards(2, &nodes, 2);
    let mut meta2 = meta1.clone();

    // Update meta2's shard 0 to have higher generation
    if let Some(desc) = meta2.get_mut(0) {
        desc.size_bytes = 1000;
        desc.generation = 10;
    }
    meta2.version = 5;

    // Merge meta2 into meta1
    meta1.merge(&meta2);

    // meta1 should have the newer descriptor
    assert_eq!(meta1.get(0).unwrap().generation, 10);
    assert_eq!(meta1.get(0).unwrap().size_bytes, 1000);
    assert_eq!(meta1.version, 5);
}

#[test]
fn test_shard_role() {
    let replicas = vec![test_node_id(1), test_node_id(2), test_node_id(3)];
    let desc = RangeDescriptor::new_full_range(0, replicas);

    assert_eq!(desc.role_for_node(test_node_id(1)), ShardRole::Leader);
    assert_eq!(desc.role_for_node(test_node_id(2)), ShardRole::Follower);
    assert_eq!(desc.role_for_node(test_node_id(3)), ShardRole::Follower);
    assert_eq!(desc.role_for_node(test_node_id(4)), ShardRole::None);
}
