//! Archive format identification by magic bytes and file extension.

use std::fmt;
use std::path::Path;

/// Known archive and compression formats.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize)]
pub enum ArchiveFormat {
    Zip,
    Tar,
    TarGz,
    TarBz2,
    TarXz,
    TarZst,
    TarLz4,
    SevenZip,
    Gz,
    Bz2,
    Xz,
    Lz4,
    Zstd,
    StuffIt,
    CompactPro,
    // New formats
    Ar,
    Deb,
    Cab,
    Rar,
    Brotli,
    Snappy,
    Lzma,
    Lzip,
    Bz3,
    Arc,
    Unknown,
}

impl fmt::Display for ArchiveFormat {
    // rust-doctor: acknowledged — exhaustive enum match over 26 variants
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Zip => write!(f, "ZIP"),
            Self::Tar => write!(f, "TAR"),
            Self::TarGz => write!(f, "TAR.GZ"),
            Self::TarBz2 => write!(f, "TAR.BZ2"),
            Self::TarXz => write!(f, "TAR.XZ"),
            Self::TarZst => write!(f, "TAR.ZSTD"),
            Self::TarLz4 => write!(f, "TAR.LZ4"),
            Self::SevenZip => write!(f, "7Z"),
            Self::Gz => write!(f, "GZIP"),
            Self::Bz2 => write!(f, "BZIP2"),
            Self::Xz => write!(f, "XZ"),
            Self::Lz4 => write!(f, "LZ4"),
            Self::Zstd => write!(f, "ZSTD"),
            Self::StuffIt => write!(f, "StuffIt"),
            Self::CompactPro => write!(f, "Compact Pro"),
            Self::Ar => write!(f, "AR"),
            Self::Deb => write!(f, "DEB"),
            Self::Cab => write!(f, "CAB"),
            Self::Rar => write!(f, "RAR"),
            Self::Brotli => write!(f, "Brotli"),
            Self::Snappy => write!(f, "Snappy"),
            Self::Lzma => write!(f, "LZMA"),
            Self::Lzip => write!(f, "LZIP"),
            Self::Bz3 => write!(f, "BZIP3"),
            Self::Arc => write!(f, "ARC"),
            Self::Unknown => write!(f, "Unknown"),
        }
    }
}

/// Magic byte signatures for format detection.
const ZIP_MAGIC: &[u8] = &[0x50, 0x4B, 0x03, 0x04];
const GZ_MAGIC: &[u8] = &[0x1F, 0x8B];
const BZ2_MAGIC: &[u8] = &[0x42, 0x5A, 0x68];
const XZ_MAGIC: &[u8] = &[0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00];
const SEVENZ_MAGIC: &[u8] = &[0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C];
const ZSTD_MAGIC: &[u8] = &[0x28, 0xB5, 0x2F, 0xFD];
const LZ4_FRAME_MAGIC: &[u8] = &[0x04, 0x22, 0x4D, 0x18];
const STUFFIT_MAGIC: &[u8] = b"SIT!";
const STUFFIT5_MAGIC: &[u8] = b"StuffIt";
const COMPACT_PRO_MAGIC: u8 = 0x01;
const RAR_MAGIC: &[u8] = &[0x52, 0x61, 0x72, 0x21, 0x1A, 0x07];
const CAB_MAGIC: &[u8] = &[0x4D, 0x53, 0x43, 0x46];
const AR_MAGIC: &[u8] = b"!<arch>";
const LZIP_MAGIC: &[u8] = b"LZIP";
const BZ3_MAGIC: &[u8] = b"BZ3v1";
const SNAPPY_FRAME_MAGIC: &[u8] = &[0xFF, 0x06, 0x00, 0x00, 0x73, 0x4E, 0x61, 0x50, 0x70, 0x59];

/// Detect archive format from raw bytes (magic number inspection).
// rust-doctor: acknowledged — sequential magic-byte checks for 20+ formats
#[must_use]
pub fn detect_format(data: &[u8]) -> ArchiveFormat {
    if data.len() < 4 {
        return ArchiveFormat::Unknown;
    }

    // Check magic bytes in order of specificity (longer signatures first)
    if data.len() >= 10 && data.starts_with(SNAPPY_FRAME_MAGIC) {
        return ArchiveFormat::Snappy;
    }
    if data.len() >= 5 && data.starts_with(BZ3_MAGIC) {
        return ArchiveFormat::Bz3;
    }
    if data.len() >= 8 && data.starts_with(AR_MAGIC) {
        // Check if it's a DEB (ar containing debian-binary)
        if data.len() > 68 && data.get(8..24) == Some(b"debian-binary   ".as_slice()) {
            return ArchiveFormat::Deb;
        }
        return ArchiveFormat::Ar;
    }
    if data.len() >= 7 && data.starts_with(RAR_MAGIC) {
        return ArchiveFormat::Rar;
    }
    if data.len() >= 6 && data.starts_with(SEVENZ_MAGIC) {
        return ArchiveFormat::SevenZip;
    }
    if data.len() >= 6 && data.starts_with(XZ_MAGIC) {
        return ArchiveFormat::Xz;
    }
    if data.starts_with(ZIP_MAGIC) {
        return ArchiveFormat::Zip;
    }
    if data.starts_with(CAB_MAGIC) {
        return ArchiveFormat::Cab;
    }
    if data.starts_with(ZSTD_MAGIC) {
        return ArchiveFormat::Zstd;
    }
    if data.starts_with(LZ4_FRAME_MAGIC) {
        return ArchiveFormat::Lz4;
    }
    if data.starts_with(LZIP_MAGIC) {
        return ArchiveFormat::Lzip;
    }
    if data.starts_with(GZ_MAGIC) {
        return ArchiveFormat::Gz;
    }
    if data.starts_with(BZ2_MAGIC) {
        return ArchiveFormat::Bz2;
    }
    if data.starts_with(STUFFIT_MAGIC) || (data.len() >= 7 && data.starts_with(STUFFIT5_MAGIC)) {
        return ArchiveFormat::StuffIt;
    }
    if data.first().copied() == Some(COMPACT_PRO_MAGIC) && data.get(1).copied() == Some(0x01) {
        return ArchiveFormat::CompactPro;
    }
    // LZMA: starts with 0x5D 0x00 (properties byte + dictionary size)
    if data.first().copied() == Some(0x5D) && data.get(1).copied() == Some(0x00) {
        return ArchiveFormat::Lzma;
    }
    // ARC: starts with 0x1A followed by a valid method byte (1-9)
    if data.first().copied() == Some(0x1A)
        && data.get(1).copied().is_some_and(|b| (1..=9).contains(&b))
    {
        return ArchiveFormat::Arc;
    }
    // TAR detection: check for "ustar" at offset 257
    if data.get(257..262) == Some(b"ustar".as_slice()) {
        return ArchiveFormat::Tar;
    }

    ArchiveFormat::Unknown
}

/// Detect archive format from file extension, refining magic-byte detection.
// rust-doctor: acknowledged — exhaustive extension matching for 20+ formats
#[must_use]
#[allow(clippy::case_sensitive_file_extension_comparisons)]
pub fn detect_format_from_path(path: &Path, data: &[u8]) -> ArchiveFormat {
    let magic = detect_format(data);

    // If magic detection was conclusive for non-compound formats, use it
    if !matches!(
        magic,
        ArchiveFormat::Gz
            | ArchiveFormat::Bz2
            | ArchiveFormat::Xz
            | ArchiveFormat::Zstd
            | ArchiveFormat::Lz4
            | ArchiveFormat::Unknown
    ) {
        return magic;
    }

    // Use extension to disambiguate compound formats (e.g., tar.gz vs plain gz)
    let name = path
        .file_name()
        .and_then(|n| n.to_str())
        .unwrap_or("")
        .to_ascii_lowercase();

    if name.ends_with(".tar.gz") || name.ends_with(".tgz") {
        return ArchiveFormat::TarGz;
    }
    if name.ends_with(".tar.bz2") || name.ends_with(".tbz2") {
        return ArchiveFormat::TarBz2;
    }
    if name.ends_with(".tar.xz") || name.ends_with(".txz") {
        return ArchiveFormat::TarXz;
    }
    if name.ends_with(".tar.zst") || name.ends_with(".tzst") {
        return ArchiveFormat::TarZst;
    }
    if name.ends_with(".tar.lz4") {
        return ArchiveFormat::TarLz4;
    }
    if name.ends_with(".tar") {
        return ArchiveFormat::Tar;
    }
    if name.ends_with(".sit") || name.ends_with(".sitx") || name.ends_with(".sea") {
        return ArchiveFormat::StuffIt;
    }
    if name.ends_with(".cpt") {
        return ArchiveFormat::CompactPro;
    }
    if name.ends_with(".7z") {
        return ArchiveFormat::SevenZip;
    }
    if name.ends_with(".deb") || name.ends_with(".udeb") {
        return ArchiveFormat::Deb;
    }
    if name.ends_with(".cab") {
        return ArchiveFormat::Cab;
    }
    if name.ends_with(".rar") || name.ends_with(".cbr") {
        return ArchiveFormat::Rar;
    }
    if name.ends_with(".br") {
        return ArchiveFormat::Brotli;
    }
    if name.ends_with(".sz") || name.ends_with(".snappy") {
        return ArchiveFormat::Snappy;
    }
    if name.ends_with(".lzma") {
        return ArchiveFormat::Lzma;
    }
    if name.ends_with(".bz3") {
        return ArchiveFormat::Bz3;
    }
    if name.ends_with(".lz") {
        return ArchiveFormat::Lzip;
    }
    if name.ends_with(".arc") {
        return ArchiveFormat::Arc;
    }
    if name.ends_with(".a") {
        return ArchiveFormat::Ar;
    }

    // Fall back to magic detection
    magic
}

/// Information about a detected format.
#[derive(Debug, serde::Serialize)]
pub struct FormatInfo {
    pub format: ArchiveFormat,
    pub description: String,
    pub mime_type: String,
    pub is_archive: bool,
    pub is_compressed: bool,
}

/// Get detailed information about a format.
// rust-doctor: acknowledged — exhaustive enum match over 26 variants
#[must_use]
#[allow(clippy::too_many_lines)]
pub fn format_info(format: ArchiveFormat) -> FormatInfo {
    match format {
        ArchiveFormat::Zip => FormatInfo {
            format,
            description: "ZIP archive (PKZIP compatible)".into(),
            mime_type: "application/zip".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Tar => FormatInfo {
            format,
            description: "POSIX TAR archive (uncompressed)".into(),
            mime_type: "application/x-tar".into(),
            is_archive: true,
            is_compressed: false,
        },
        ArchiveFormat::TarGz => FormatInfo {
            format,
            description: "TAR archive compressed with gzip".into(),
            mime_type: "application/gzip".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::TarBz2 => FormatInfo {
            format,
            description: "TAR archive compressed with bzip2".into(),
            mime_type: "application/x-bzip2".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::TarXz => FormatInfo {
            format,
            description: "TAR archive compressed with XZ/LZMA2".into(),
            mime_type: "application/x-xz".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::TarZst => FormatInfo {
            format,
            description: "TAR archive compressed with Zstandard".into(),
            mime_type: "application/zstd".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::TarLz4 => FormatInfo {
            format,
            description: "TAR archive compressed with LZ4".into(),
            mime_type: "application/x-lz4".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::SevenZip => FormatInfo {
            format,
            description: "7-Zip archive (LZMA/LZMA2)".into(),
            mime_type: "application/x-7z-compressed".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Gz => FormatInfo {
            format,
            description: "Gzip compressed file (RFC 1952)".into(),
            mime_type: "application/gzip".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Bz2 => FormatInfo {
            format,
            description: "Bzip2 compressed file".into(),
            mime_type: "application/x-bzip2".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Xz => FormatInfo {
            format,
            description: "XZ compressed file (LZMA2)".into(),
            mime_type: "application/x-xz".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Lz4 => FormatInfo {
            format,
            description: "LZ4 compressed file (frame format)".into(),
            mime_type: "application/x-lz4".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Zstd => FormatInfo {
            format,
            description: "Zstandard compressed file".into(),
            mime_type: "application/zstd".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::StuffIt => FormatInfo {
            format,
            description: "StuffIt archive (classic Mac OS)".into(),
            mime_type: "application/x-stuffit".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::CompactPro => FormatInfo {
            format,
            description: "Compact Pro archive (classic Mac OS)".into(),
            mime_type: "application/x-compact-pro".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Ar => FormatInfo {
            format,
            description: "Unix AR archive".into(),
            mime_type: "application/x-archive".into(),
            is_archive: true,
            is_compressed: false,
        },
        ArchiveFormat::Deb => FormatInfo {
            format,
            description: "Debian package (ar + tar)".into(),
            mime_type: "application/vnd.debian.binary-package".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Cab => FormatInfo {
            format,
            description: "Windows Cabinet archive".into(),
            mime_type: "application/vnd.ms-cab-compressed".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Rar => FormatInfo {
            format,
            description: "RAR archive (v4/v5)".into(),
            mime_type: "application/vnd.rar".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Brotli => FormatInfo {
            format,
            description: "Brotli compressed file".into(),
            mime_type: "application/x-brotli".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Snappy => FormatInfo {
            format,
            description: "Snappy compressed file (frame format)".into(),
            mime_type: "application/x-snappy-framed".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Lzma => FormatInfo {
            format,
            description: "LZMA compressed file (standalone)".into(),
            mime_type: "application/x-lzma".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Bz3 => FormatInfo {
            format,
            description: "BZip3 compressed file".into(),
            mime_type: "application/x-bzip3".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Lzip => FormatInfo {
            format,
            description: "Lzip compressed file (LZMA)".into(),
            mime_type: "application/x-lzip".into(),
            is_archive: false,
            is_compressed: true,
        },
        ArchiveFormat::Arc => FormatInfo {
            format,
            description: "ARC archive (SEA/PKWare)".into(),
            mime_type: "application/x-arc".into(),
            is_archive: true,
            is_compressed: true,
        },
        ArchiveFormat::Unknown => FormatInfo {
            format,
            description: "Unknown format".into(),
            mime_type: "application/octet-stream".into(),
            is_archive: false,
            is_compressed: false,
        },
    }
}

#[cfg(test)]
#[allow(clippy::missing_panics_doc)]
mod tests {
    use super::*;

    #[test]
    fn test_detect_zip() {
        let data = [0x50, 0x4B, 0x03, 0x04, 0x00, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Zip);
    }

    #[test]
    fn test_detect_gzip() {
        let data = [0x1F, 0x8B, 0x08, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Gz);
    }

    #[test]
    fn test_detect_xz() {
        let data = [0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Xz);
    }

    #[test]
    fn test_detect_lz4_frame() {
        let data = [0x04, 0x22, 0x4D, 0x18, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Lz4);
    }

    #[test]
    fn test_detect_zstd() {
        let data = [0x28, 0xB5, 0x2F, 0xFD, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Zstd);
    }

    #[test]
    fn test_detect_bz2() {
        let data = [0x42, 0x5A, 0x68, 0x39, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Bz2);
    }

    #[test]
    fn test_detect_7z() {
        let data = [0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::SevenZip);
    }

    #[test]
    fn test_detect_stuffit() {
        let data = b"SIT!\x00\x00\x00\x00";
        assert_eq!(detect_format(data), ArchiveFormat::StuffIt);
    }

    #[test]
    fn test_detect_compact_pro() {
        let data = [0x01, 0x01, 0x00, 0x00, 0x00, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::CompactPro);
    }

    #[test]
    fn test_detect_unknown() {
        let data = [0xFF, 0xFE, 0x00, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Unknown);
    }

    #[test]
    fn test_detect_too_short() {
        let data = [0x50, 0x4B];
        assert_eq!(detect_format(&data), ArchiveFormat::Unknown);
    }

    #[test]
    fn test_detect_empty_data() {
        assert_eq!(detect_format(&[]), ArchiveFormat::Unknown);
    }

    #[test]
    fn test_detect_single_byte() {
        assert_eq!(detect_format(&[0xFF]), ArchiveFormat::Unknown);
    }

    #[test]
    fn test_detect_three_bytes() {
        assert_eq!(detect_format(&[0x50, 0x4B, 0x03]), ArchiveFormat::Unknown);
    }

    #[test]
    fn test_detect_stuffit5() {
        let data = b"StuffIt\x05\x00\x00\x00\x00\x00\x00\x00";
        assert_eq!(detect_format(data), ArchiveFormat::StuffIt);
    }

    #[test]
    fn test_detect_rar_v5() {
        let data = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x01, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Rar);
    }

    #[test]
    fn test_detect_rar_v4() {
        let data = [0x52, 0x61, 0x72, 0x21, 0x1A, 0x07, 0x00, 0xCF];
        assert_eq!(detect_format(&data), ArchiveFormat::Rar);
    }

    #[test]
    fn test_detect_cab() {
        let data = [0x4D, 0x53, 0x43, 0x46, 0x00, 0x00, 0x00, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Cab);
    }

    #[test]
    fn test_detect_bz3() {
        let data = b"BZ3v1\x00\x00\x00";
        assert_eq!(detect_format(data), ArchiveFormat::Bz3);
    }

    #[test]
    fn test_extension_bz3() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("file.bz3");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Bz3);
    }

    #[test]
    fn test_detect_ar() {
        let data = b"!<arch>\n";
        assert_eq!(detect_format(data), ArchiveFormat::Ar);
    }

    #[test]
    fn test_detect_lzma() {
        let data = [0x5D, 0x00, 0x00, 0x80, 0x00];
        assert_eq!(detect_format(&data), ArchiveFormat::Lzma);
    }

    #[test]
    fn test_detect_lzip() {
        let data = b"LZIP\x01\x33\x00\x26";
        assert_eq!(detect_format(data), ArchiveFormat::Lzip);
    }

    #[test]
    fn test_detect_arc() {
        let data = [0x1A, 0x08, 0x43, 0x4F, 0x4D, 0x50];
        assert_eq!(detect_format(&data), ArchiveFormat::Arc);
    }

    #[test]
    fn test_detect_snappy_frame() {
        let data = [
            0xFF, 0x06, 0x00, 0x00, 0x73, 0x4E, 0x61, 0x50, 0x70, 0x59, 0x00,
        ];
        assert_eq!(detect_format(&data), ArchiveFormat::Snappy);
    }

    #[test]
    fn test_extension_tar_gz() {
        let data = [0x1F, 0x8B, 0x08, 0x00, 0x00];
        let path = Path::new("test.tar.gz");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::TarGz);
    }

    #[test]
    fn test_extension_tgz() {
        let data = [0x1F, 0x8B, 0x08, 0x00, 0x00];
        let path = Path::new("test.tgz");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::TarGz);
    }

    #[test]
    fn test_extension_tar_bz2() {
        let data = [0x42, 0x5A, 0x68, 0x39, 0x00];
        let path = Path::new("test.tar.bz2");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::TarBz2);
    }

    #[test]
    fn test_extension_tar_xz() {
        let data = [0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00, 0x00];
        let path = Path::new("test.tar.xz");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::TarXz);
    }

    #[test]
    fn test_extension_tar_zst() {
        let data = [0x28, 0xB5, 0x2F, 0xFD, 0x00];
        let path = Path::new("test.tar.zst");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::TarZst);
    }

    #[test]
    fn test_extension_tar_lz4() {
        let data = [0x04, 0x22, 0x4D, 0x18, 0x00];
        let path = Path::new("test.tar.lz4");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::TarLz4);
    }

    #[test]
    fn test_extension_sit() {
        let data = b"SIT!\x00\x00\x00\x00";
        let path = Path::new("test.sit");
        assert_eq!(detect_format_from_path(path, data), ArchiveFormat::StuffIt);
    }

    #[test]
    fn test_extension_7z() {
        let data = [0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C, 0x00];
        let path = Path::new("test.7z");
        assert_eq!(
            detect_format_from_path(path, &data),
            ArchiveFormat::SevenZip
        );
    }

    #[test]
    fn test_extension_rar() {
        // Unknown magic but .rar extension
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("test.rar");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Rar);
    }

    #[test]
    fn test_extension_cbr() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("test.cbr");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Rar);
    }

    #[test]
    fn test_extension_deb() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("package.deb");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Deb);
    }

    #[test]
    fn test_extension_cab() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("setup.cab");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Cab);
    }

    #[test]
    fn test_extension_brotli() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("file.br");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Brotli);
    }

    #[test]
    fn test_extension_lzma() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("file.lzma");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Lzma);
    }

    #[test]
    fn test_extension_lz() {
        let data = [0x00, 0x00, 0x00, 0x00];
        let path = Path::new("file.lz");
        assert_eq!(detect_format_from_path(path, &data), ArchiveFormat::Lzip);
    }

    #[test]
    fn test_format_info_all_variants() {
        let formats = [
            ArchiveFormat::Zip,
            ArchiveFormat::Tar,
            ArchiveFormat::TarGz,
            ArchiveFormat::TarBz2,
            ArchiveFormat::TarXz,
            ArchiveFormat::TarZst,
            ArchiveFormat::TarLz4,
            ArchiveFormat::SevenZip,
            ArchiveFormat::Gz,
            ArchiveFormat::Bz2,
            ArchiveFormat::Xz,
            ArchiveFormat::Lz4,
            ArchiveFormat::Zstd,
            ArchiveFormat::StuffIt,
            ArchiveFormat::CompactPro,
            ArchiveFormat::Ar,
            ArchiveFormat::Deb,
            ArchiveFormat::Cab,
            ArchiveFormat::Rar,
            ArchiveFormat::Brotli,
            ArchiveFormat::Snappy,
            ArchiveFormat::Lzma,
            ArchiveFormat::Lzip,
            ArchiveFormat::Bz3,
            ArchiveFormat::Arc,
            ArchiveFormat::Unknown,
        ];
        for fmt in &formats {
            let info = format_info(*fmt);
            assert!(!info.description.is_empty());
            assert!(!info.mime_type.is_empty());
        }
    }

    #[test]
    fn test_display_all_variants() {
        let formats = [
            ArchiveFormat::Zip,
            ArchiveFormat::Tar,
            ArchiveFormat::TarGz,
            ArchiveFormat::TarBz2,
            ArchiveFormat::TarXz,
            ArchiveFormat::TarZst,
            ArchiveFormat::TarLz4,
            ArchiveFormat::SevenZip,
            ArchiveFormat::Gz,
            ArchiveFormat::Bz2,
            ArchiveFormat::Xz,
            ArchiveFormat::Lz4,
            ArchiveFormat::Zstd,
            ArchiveFormat::StuffIt,
            ArchiveFormat::CompactPro,
            ArchiveFormat::Ar,
            ArchiveFormat::Deb,
            ArchiveFormat::Cab,
            ArchiveFormat::Rar,
            ArchiveFormat::Brotli,
            ArchiveFormat::Snappy,
            ArchiveFormat::Lzma,
            ArchiveFormat::Lzip,
            ArchiveFormat::Bz3,
            ArchiveFormat::Arc,
            ArchiveFormat::Unknown,
        ];
        for fmt in &formats {
            let s = fmt.to_string();
            assert!(!s.is_empty());
        }
    }
}
