use crate::{VfsDevice, VfsEntry, VfsError};
use std::path::{Path, PathBuf};

/// Host filesystem pass-through device.
pub struct HostPathDevice {
    name: String,
    root: PathBuf,
}

impl HostPathDevice {
    pub fn new(name: impl Into<String>, root: impl AsRef<Path>) -> Self {
        Self {
            name: name.into(),
            root: root.as_ref().to_path_buf(),
        }
    }
}

impl VfsDevice for HostPathDevice {
    fn name(&self) -> &str {
        &self.name
    }

    fn list_root(&self) -> Result<Vec<VfsEntry>, VfsError> {
        let mut entries = Vec::new();
        for entry in std::fs::read_dir(&self.root)? {
            let entry = entry?;
            let metadata = entry.metadata()?;
            entries.push(VfsEntry {
                name: entry.file_name().to_string_lossy().into_owned(),
                is_directory: metadata.is_dir(),
                size: metadata.len(),
                offset: 0,
                // Host FS carries no Xbox attribute byte; synthesise the
                // DIRECTORY/NORMAL split like canary's HostPathDevice.
                attributes: if metadata.is_dir() { 0x10 } else { 0x80 },
            });
        }
        Ok(entries)
    }

    fn read_file(&self, path: &str) -> Result<Vec<u8>, VfsError> {
        let full_path = self.root.join(path);
        std::fs::read(&full_path).map_err(VfsError::from)
    }

    fn stat(&self, path: &str) -> Result<VfsEntry, VfsError> {
        let full_path = self.root.join(path);
        let metadata = std::fs::metadata(&full_path)?;
        Ok(VfsEntry {
            name: path.to_string(),
            is_directory: metadata.is_dir(),
            size: metadata.len(),
            offset: 0,
            attributes: if metadata.is_dir() { 0x10 } else { 0x80 },
        })
    }
}
