use anyhow::Result;
use zerocopy::FromBytes;
use zerocopy::Immutable;
use zerocopy::IntoBytes;
use zerocopy::KnownLayout;
use crate::arena::Arena;
use crate::arena::BlockId;
use crate::blockgroup::BLOCK_SIZE;
use crate::builder::Builder;
use crate::inode::Inode;
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
pub(crate) struct SuperBlock {
    pub inodes_count: u32,
    pub blocks_count: u32,
    _r_blocks_count: u32,
    pub free_blocks_count: u32,
    pub free_inodes_count: u32,
    _first_data_block: u32,
    _log_block_size: u32,
    log_frag_size: u32,
    pub blocks_per_group: u32,
    frags_per_group: u32,
    pub inodes_per_group: u32,
    mtime: u32,
    wtime: u32,
    _mnt_count: u16,
    _max_mnt_count: u16,
    magic: u16,
    state: u16,
    errors: u16,
    _minor_rev_level: u16,
    _lastcheck: u32,
    _checkinterval: u32,
    _creator_os: u32,
    rev_level: u32,
    _def_resuid: u16,
    _def_resgid: u16,
    first_ino: u32,
    pub inode_size: u16,
    pub block_group_nr: u16,
    feature_compat: u32,
    feature_incompat: u32,
    _feature_ro_compat: u32,
    uuid: [u8; 16],
    }
impl SuperBlock {
    pub fn new<'a>(arena: &'a Arena<'a>, cfg: &Builder) -> Result<&'a mut SuperBlock> {
        const EXT2_MAGIC_NUMBER: u16 = 0xEF53;
        const COMPAT_EXT_ATTR: u32 = 0x8;
        let num_groups = cfg.size / (cfg.blocks_per_group * BLOCK_SIZE as u32);
        let blocks_per_group = cfg.blocks_per_group;
        let inodes_per_group = cfg.inodes_per_group;
        let log_block_size = 2; let now = std::time::SystemTime::now()
            .duration_since(std::time::UNIX_EPOCH)?
            .as_secs() as u32;
        let uuid = uuid::Uuid::new_v4().into_bytes();
        let inodes_count = inodes_per_group * num_groups;
        let blocks_count = blocks_per_group * num_groups;
        let first_ino = 11;
        let sb = arena.allocate::<SuperBlock>(BlockId::from(0), 1024)?;
        *sb = Self {
            inodes_count,
            blocks_count,
            free_blocks_count: 0, free_inodes_count: inodes_count, _log_block_size: log_block_size,
            log_frag_size: log_block_size,
            blocks_per_group,
            frags_per_group: blocks_per_group,
            inodes_per_group,
            mtime: now,
            wtime: now,
            magic: EXT2_MAGIC_NUMBER,
            state: 1,     errors: 1,    rev_level: 1, first_ino,
            inode_size: Inode::INODE_RECORD_SIZE as u16,
            block_group_nr: 1, feature_compat: COMPAT_EXT_ATTR,
            feature_incompat: 0x2, uuid,
            ..Default::default()
        };
        Ok(sb)
    }
    #[inline]
    pub fn num_groups(&self) -> u16 {
        (self.inodes_count / self.inodes_per_group) as u16
    }
}