//! Integration tests for ext4-mkfs.

use ext4_mkfs::{mkfs, FsType, IoBlockDevice, MkfsConfig};
use std::io::Cursor;

/// Helper to create a memory-backed block device of given size.
fn create_memory_device(size: usize) -> IoBlockDevice<Cursor<Vec<u8>>> {
    let data = vec![0u8; size];
    IoBlockDevice::new(Cursor::new(data), 512, size as u64)
}

#[test]
fn test_mkfs_ext4_minimal() {
    // 2MB - minimum viable size for ext4
    let device = create_memory_device(2 * 1024 * 1024);
    let config = MkfsConfig::new().fs_type(FsType::Ext4).block_size(1024);

    let result = mkfs(device, config);
    assert!(result.is_ok(), "mkfs should succeed: {:?}", result);
}

#[test]
fn test_mkfs_ext4_with_label() {
    let device = create_memory_device(2 * 1024 * 1024);
    let config = MkfsConfig::new()
        .fs_type(FsType::Ext4)
        .block_size(1024)
        .label("test_vol");

    let result = mkfs(device, config);
    assert!(result.is_ok(), "mkfs with label should succeed: {:?}", result);
}

#[test]
fn test_mkfs_ext4_with_uuid() {
    let device = create_memory_device(2 * 1024 * 1024);
    let uuid = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
    let config = MkfsConfig::new()
        .fs_type(FsType::Ext4)
        .block_size(1024)
        .uuid(uuid);

    let result = mkfs(device, config);
    assert!(result.is_ok(), "mkfs with UUID should succeed: {:?}", result);
}

#[test]
fn test_mkfs_ext2() {
    let device = create_memory_device(2 * 1024 * 1024);
    let config = MkfsConfig::new().fs_type(FsType::Ext2).block_size(1024);

    let result = mkfs(device, config);
    assert!(result.is_ok(), "mkfs ext2 should succeed: {:?}", result);
}

#[test]
fn test_mkfs_ext3() {
    let device = create_memory_device(2 * 1024 * 1024);
    let config = MkfsConfig::new().fs_type(FsType::Ext3).block_size(1024);

    let result = mkfs(device, config);
    assert!(result.is_ok(), "mkfs ext3 should succeed: {:?}", result);
}

#[test]
fn test_mkfs_different_block_sizes() {
    for block_size in [1024, 2048, 4096] {
        let device = create_memory_device(4 * 1024 * 1024);
        let config = MkfsConfig::new()
            .fs_type(FsType::Ext4)
            .block_size(block_size);

        let result = mkfs(device, config);
        assert!(
            result.is_ok(),
            "mkfs with block_size {} should succeed: {:?}",
            block_size,
            result
        );
    }
}

#[test]
fn test_mkfs_device_too_small() {
    // 512KB - too small
    let device = create_memory_device(512 * 1024);
    let config = MkfsConfig::new().fs_type(FsType::Ext4).block_size(1024);

    let result = mkfs(device, config);
    assert!(result.is_err(), "mkfs should fail for device too small");

    match result {
        Err(ext4_mkfs::Error::DeviceTooSmall { .. }) => {}
        other => panic!("Expected DeviceTooSmall error, got {:?}", other),
    }
}

#[test]
fn test_mkfs_invalid_block_size() {
    let device = create_memory_device(2 * 1024 * 1024);
    let config = MkfsConfig::new()
        .fs_type(FsType::Ext4)
        .block_size(512); // Invalid - must be 1024, 2048, or 4096

    let result = mkfs(device, config);
    assert!(result.is_err(), "mkfs should fail for invalid block size");

    match result {
        Err(ext4_mkfs::Error::InvalidConfig(_)) => {}
        other => panic!("Expected InvalidConfig error, got {:?}", other),
    }
}

#[test]
fn test_mkfs_larger_device() {
    // 10MB device
    let device = create_memory_device(10 * 1024 * 1024);
    let config = MkfsConfig::new()
        .fs_type(FsType::Ext4)
        .block_size(4096)
        .label("large_test");

    let result = mkfs(device, config);
    assert!(result.is_ok(), "mkfs on larger device should succeed: {:?}", result);
}

#[test]
fn test_mkfs_verifies_superblock_magic() {
    // Create and format a device
    let data = vec![0u8; 2 * 1024 * 1024];
    let cursor = Cursor::new(data);
    let device = IoBlockDevice::new(cursor, 512, 2 * 1024 * 1024);

    let config = MkfsConfig::new().fs_type(FsType::Ext4).block_size(1024);

    let result = mkfs(device, config);
    assert!(result.is_ok());
}

#[test]
fn test_config_builder_chain() {
    let config = MkfsConfig::new()
        .fs_type(FsType::Ext4)
        .block_size(4096)
        .label("my_volume")
        .uuid([0xAA; 16])
        .journal(false)
        .inode_size(256);

    assert_eq!(config.fs_type, FsType::Ext4);
    assert_eq!(config.block_size, 4096);
    assert_eq!(config.label, Some("my_volume".to_string()));
    assert_eq!(config.uuid, Some([0xAA; 16]));
    assert!(!config.journal);
    assert_eq!(config.inode_size, 256);
}

#[test]
fn test_config_default() {
    let config = MkfsConfig::default();

    assert_eq!(config.fs_type, FsType::Ext4);
    assert_eq!(config.block_size, 4096);
    assert_eq!(config.label, None);
    assert_eq!(config.uuid, None);
    assert!(!config.journal);
    assert_eq!(config.inode_size, 256);
}
