use crate::bit_vector::*;
use crate::blob_device::*;
use crate::block_device::*;
use crate::errors::*;
use crate::structs::*;
use crate::utils::*;

pub struct BlobFS<'a> {
    pub bd: BlobDevice<'a>,
    pub superblock: Superblock,
    pub blockmap: BitVector<'a>,
}

// Public impl

impl<'a> BlobFS<'a> {
    pub fn new(bd: &'a mut dyn BlockDevice, blockmap_bits: &'a mut [u32]) -> Self {
        let result = BlobFS {
            bd: BlobDevice::new(bd),
            superblock: Superblock::default(),
            blockmap: BitVector::new(blockmap_bits),
        };

        return result;
    }

    pub fn format(&mut self) -> Result<(), BFSErr> {
        // Format the device.
        self.bd.format()?;

        return Ok(());
    }

    pub fn mount(&mut self) -> Result<(), BFSErr> {
        // Read the superblock from the device.
        self.bd.read_superblock(&mut self.superblock)?;

        // Read the allocation bitmap from the device
        self.bd.read_blockmap(&mut self.blockmap)?;

        return Ok(());
    }

    pub fn sanity_check(&self) -> Result<(), BFSErr> {
        return Ok(());
    }

    pub fn get_blob_size(&self, hash: u64) -> Result<usize, BFSErr> {
        let result = self.find_inode(hash)?;
        let inode = result.1;
        return Ok(inode.blob_size as usize);
    }

    pub fn get_blob(&self, hash: u64, blob_out: &mut [u8]) -> Result<(), BFSErr> {
        let result = self.find_inode(hash)?;
        let inode = result.1;
        dcheck!(
            inode.blob_size as usize <= blob_out.len(),
            BFSErr::OutOfBounds
        );

        let dst = &mut blob_out[..inode.blob_size as usize];
        self.bd.read_blob(inode.inline_extent, dst)?;

        return Ok(());
    }

    pub fn put_blob(&mut self, hash: u64, blob_in: &[u8]) -> Result<(), BFSErr> {
        if self.find_inode(hash).is_ok() {
            return Err(BFSErr::Duplicate);
        }

        let blob_block_count = self.bd.blob_size_in_blocks(blob_in);

        // Find a place to put the blob.
        let extent = self.find_extent(blob_block_count)?;

        // Copy the blob to the block device.
        self.bd.write_blob(extent, blob_in)?;

        // Set the corresponding bits in our local bitmap
        self.blockmap
            .clear_range(extent.offset(), extent.offset() + extent.size as usize)?;
        // FIXME flush bitmap to disk?

        // Create the inode for the new blob
        let inode = Inode {
            header: NodeHeader {
                flags: NodeHeader::FLAG_INODE,
                version: 0x0,
                next_node: 0xFFFFFFFF, // FIXME
            },
            hash0: hash, // FIXME just using 64-bit hash
            hash1: hash,
            hash2: hash,
            hash3: hash,
            blob_size: blob_in.len() as u64,
            block_count: blob_block_count as u32,
            extent_count: 1,
            padding: 0xFFFF,
            inline_extent: extent,
        };

        // Put the inode in the inode table
        let inode_idx = self.find_free_inode()?;
        self.bd.write_inode(inode_idx, &inode)?;

        return Ok(());
    }

    pub fn delete_blob(&mut self, hash: u64) -> Result<(), BFSErr> {
        let result = self.find_inode(hash)?;
        let inode_idx = result.0;
        let extent = result.1.inline_extent;

        self.bd.invalidate_inode(inode_idx)?;
        self.blockmap
            .set_range(extent.offset(), extent.offset() + extent.size as usize)?;
        self.bd.delete_blob(extent)?;
        self.bd.delete_blob(extent)?;
        return Ok(());
    }
}

// Private impl

impl<'a> BlobFS<'a> {
    fn find_inode(&self, hash: u64) -> Result<(usize, Inode), BFSErr> {
        for i in 0..self.superblock.inode_count as usize {
            let mut inode = Inode::default();
            self.bd.read_inode(i, &mut inode)?;
            if inode.header.flags == NodeHeader::FLAG_INODE && inode.hash0 == hash {
                return Ok((i, inode));
            }
        }
        return Err(BFSErr::NotFound);
    }

    // FIXME quick and dirty scan entire inode table for empty slot

    fn find_free_inode(&self) -> Result<usize, BFSErr> {
        for i in 0..self.superblock.inode_count as usize {
            let mut header = NodeHeader::default();
            self.bd.read_node_header(i, &mut header)?;
            if header.flags == u16::MAX {
                return Ok(i);
            }
        }
        assert!(false);
        return Err(BFSErr::NotFound);
    }

    #[allow(dead_code)]
    fn count_inodes(&self) -> Result<usize, BFSErr> {
        let mut count = 0;
        for i in 0..self.superblock.inode_count as usize {
            let mut header = NodeHeader::default();
            self.bd.read_node_header(i, &mut header)?;
            if header.flags == NodeHeader::FLAG_INODE {
                count = count + 1;
            }
        }
        return Ok(count);
    }

    fn find_extent(&self, blob_block_count: u16) -> Result<Extent, BFSErr> {
        let block_count = self.bd.bd.geom().block_count;
        let offset = self
            .blockmap
            .find_span(0, block_count, blob_block_count as usize)?;

        return Ok(Extent {
            size: blob_block_count as u16,
            //offset_hi: (offset >> 32) as u16,
            offset_hi: 0 as u16,
            offset_lo: offset as u32,
        });
    }
}

// Unit tests

#[test]
fn test_basic() {
    use crate::test_device::*;
    const BLOCK_SIZE: usize = 8192;
    const BLOCK_COUNT: usize = 32;

    let geom = BlockDeviceGeometry {
        block_size: BLOCK_SIZE,
        block_count: BLOCK_COUNT,
    };
    let mut buf: [u8; BLOCK_SIZE * BLOCK_COUNT] = [0; BLOCK_SIZE * BLOCK_COUNT];
    let mut dirty_bits = [0; BLOCK_SIZE * BLOCK_COUNT / 32];
    let bd: &mut dyn BlockDevice = &mut TestDevice::new(geom, buf.as_mut_ptr(), &mut dirty_bits);

    let mut blockmap_bits: [u32; BLOCK_COUNT / 32] = [0xFFFFFFFF; BLOCK_COUNT / 32];

    let mut fs = BlobFS::new(bd, blockmap_bits.as_mut());

    assert_ok!(fs.format());
    assert_ok!(fs.mount());
    assert_ok!(fs.sanity_check());

    // Block map should start with 4 reserved blocks for metadata
    assert_eq!(
        fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(),
        BLOCK_COUNT - 4
    );

    // Store a small blob in the filesystem
    let blob_hash: u64 = 0xDEADBEEFF00DCAFE;
    let blob_text = "This is the contents of a blob";
    let blob_contents = blob_text.as_bytes();
    assert_ok!(fs.put_blob(blob_hash, blob_contents));

    // Block map should have lost one free block
    assert_eq!(
        fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(),
        BLOCK_COUNT - 5
    );

    // Storing it a second time should fail.
    assert_err!(fs.put_blob(blob_hash, blob_contents));

    // Read it back out
    let blob_len = fs.get_blob_size(blob_hash).unwrap();
    let mut blob_contents: Vec<u8> = vec![0; blob_len];
    assert_ok!(fs.get_blob(blob_hash, &mut blob_contents));

    // Contents should match.
    let new_blob_text = core::str::from_utf8(&blob_contents).unwrap();
    assert_eq!(blob_text, new_blob_text);

    // Delete it and lookups should fail
    assert_ok!(fs.delete_blob(blob_hash));
    assert_err!(fs.get_blob_size(blob_hash));

    // Deleting it a second time should also fail.
    assert_err!(fs.delete_blob(blob_hash));

    // Block map should have gained one free block
    assert_eq!(
        fs.blockmap.count_range(0, BLOCK_COUNT).unwrap(),
        BLOCK_COUNT - 4
    );

    // Reading a non-existent blob should cause an error
    let bad_hash: u64 = 0xAAAAAAAAAAAAAAAA;
    assert_err!(fs.get_blob_size(bad_hash));
    let mut blob_contents: [u8; 256] = [0; 256];
    assert_err!(fs.get_blob(bad_hash, &mut blob_contents));
}
