use std::{fmt, io, os::fd::RawFd, path::Path};

use bitflags::bitflags;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileModeUpdate {
    Set(FileMode),
    Modify { set: FileMode, clear: FileMode },
}

bitflags! {
    #[derive(Clone, Copy, PartialEq, Eq)]
    pub struct FileMode: u32 {
        const OTHER_EXEC = 1 << 0;
        const OTHER_WRITE = 1 << 1;
        const OTHER_READ = 1 << 2;
        const GROUP_EXEC = 1 << 3;
        const GROUP_WRITE = 1 << 4;
        const GROUP_READ = 1 << 5;
        const USER_EXEC = 1 << 6;
        const USER_WRITE = 1 << 7;
        const USER_READ = 1 << 8;
    }
}

impl FileMode {
    const MASK: u32 = 0o777;
}

impl From<u32> for FileMode {
    fn from(value: u32) -> Self {
        Self::from_bits_retain(value & Self::MASK)
    }
}

pub use crate::sys::fs::update_file_mode;

pub fn set_file_mode<P: AsRef<Path>>(at: Option<RawFd>, path: P, mode: FileMode) -> io::Result<()> {
    update_file_mode(at, path, FileModeUpdate::Set(mode))
}

impl fmt::Debug for FileMode {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:#03o}", self.bits())
    }
}
