pub mod device;
pub mod disc_image;

use thiserror::Error;

#[derive(Debug, Error)]
pub enum VfsError {
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    #[error("Invalid format: {0}")]
    InvalidFormat(String),

    #[error("File not found: {0}")]
    NotFound(String),
}

/// A virtual filesystem entry (file or directory).
#[derive(Debug, Clone)]
pub struct VfsEntry {
    pub name: String,
    pub is_directory: bool,
    pub size: u64,
    pub offset: u64,
    /// Xbox `FILE_ATTRIBUTE_*` bitmask for this entry, sourced from the
    /// backing device's real on-disc metadata rather than inferred from
    /// the path shape. For GDFX disc images this is the on-disc attribute
    /// byte at dirent offset +12 OR'd with `FILE_ATTRIBUTE_READONLY`
    /// (matches xenia-canary `disc_image_device.cc:154`:
    /// `entry->attributes_ = attributes | kFileAttributeReadOnly`).
    ///
    /// Bit layout (canary `vfs/entry.h:66-76`): READONLY=0x01, HIDDEN=0x02,
    /// SYSTEM=0x04, DIRECTORY=0x10, ARCHIVE=0x20, NORMAL=0x80.
    pub attributes: u32,
}

/// Trait for VFS device implementations (XISO, STFS, host path, etc.)
pub trait VfsDevice: Send + Sync {
    fn name(&self) -> &str;
    fn list_root(&self) -> Result<Vec<VfsEntry>, VfsError>;
    fn read_file(&self, path: &str) -> Result<Vec<u8>, VfsError>;
    fn stat(&self, path: &str) -> Result<VfsEntry, VfsError>;
}
