use mount_fstab::fstype::FsType;
use mount_fstab::options::Options;
use mount_fstab::spec::Spec;
use mount_fstab::types::{Entry, Fstab, MountPoint};

#[test]
fn display_single_entry() {
    let mut entry = Entry::new(
        Spec::Uuid("abc".into()),
        MountPoint::new("/").unwrap(),
        FsType::parse("ext4").unwrap(),
        Options::parse("defaults").unwrap(),
    );
    entry.freq = 0;
    entry.passno = 1;

    let fstab = Fstab {
        intro_comment: None,
        entries: vec![entry],
        trailing_comment: None,
    };

    let output = fstab.to_string();
    assert_eq!(output, "UUID=abc / ext4 defaults 0 1\n");
}

#[test]
fn display_with_comments() {
    let mut entry = Entry::new(
        Spec::Uuid("abc".into()),
        MountPoint::new("/").unwrap(),
        FsType::parse("ext4").unwrap(),
        Options::parse("defaults").unwrap(),
    );
    entry.freq = 0;
    entry.passno = 1;
    entry.comment = Some("# Root filesystem\n".to_owned());

    let fstab = Fstab {
        intro_comment: Some("# My fstab\n".to_owned()),
        entries: vec![entry],
        trailing_comment: Some("# End\n".to_owned()),
    };

    let output = fstab.to_string();
    assert!(output.starts_with("# My fstab\n"));
    assert!(output.contains("# Root filesystem\n"));
    assert!(output.ends_with("# End\n"));
}

#[test]
fn display_entry_with_escaped_space() {
    let entry = Entry::new(
        Spec::Label("My Drive".into()),
        MountPoint::new("/mnt/data").unwrap(),
        FsType::parse("ext4").unwrap(),
        Options::parse("defaults").unwrap(),
    );

    let fstab = Fstab {
        intro_comment: None,
        entries: vec![entry],
        trailing_comment: None,
    };

    let output = fstab.to_string();
    assert!(output.contains(r"LABEL=My\040Drive"));
}

#[test]
fn display_entry_with_escaped_backslash() {
    let entry = Entry::new(
        Spec::Keyword(r"foo\bar".into()),
        MountPoint::new("/mnt").unwrap(),
        FsType::parse("ext4").unwrap(),
        Options::parse("defaults").unwrap(),
    );

    let fstab = Fstab {
        intro_comment: None,
        entries: vec![entry],
        trailing_comment: None,
    };

    let output = fstab.to_string();
    assert!(output.contains(r"foo\\bar"));
}

#[test]
fn display_multiple_entries_preserves_order() {
    let mut e1 = Entry::new(
        Spec::Uuid("root".into()),
        MountPoint::new("/").unwrap(),
        FsType::parse("ext4").unwrap(),
        Options::parse("defaults").unwrap(),
    );
    e1.passno = 1;
    let e2 = Entry::new(
        Spec::Uuid("boot".into()),
        MountPoint::new("/boot").unwrap(),
        FsType::parse("ext4").unwrap(),
        Options::parse("defaults").unwrap(),
    );

    let fstab = Fstab {
        intro_comment: None,
        entries: vec![e1, e2],
        trailing_comment: None,
    };

    let output = fstab.to_string();
    let lines: Vec<&str> = output.lines().collect();
    assert_eq!(lines.len(), 2);
    assert!(lines[0].contains(" / "));
    assert!(lines[1].contains(" /boot "));
}

#[test]
fn parse_display_roundtrip() {
    let input = "\
# /etc/fstab: static file system information

UUID=root / ext4 defaults 0 1
UUID=boot /boot ext4 defaults 0 2
";
    let fstab = Fstab::parse_str(input).unwrap();
    let output = fstab.to_string();
    let re_parsed = Fstab::parse_str(&output).unwrap();

    assert_eq!(fstab.entries.len(), re_parsed.entries.len());
    for (a, b) in fstab.entries.iter().zip(re_parsed.entries.iter()) {
        assert_eq!(a.spec, b.spec);
        assert_eq!(a.file, b.file);
        assert_eq!(a.vfstype, b.vfstype);
        assert_eq!(a.options, b.options);
        assert_eq!(a.freq, b.freq);
        assert_eq!(a.passno, b.passno);
    }
}
