#![allow(unused)]
use cid::Cid;

use crate::{error::CarError, header::CarHeader, reader::CarReader, section::Section, Ipld};
use std::{
    collections::HashMap,
    io::{Read, Seek},
};

use super::read_section;

pub(crate) struct CarReaderV1<R> {
    inner: R,
    sections: HashMap<Cid, Section>,
    header: CarHeader,
}

impl<R> CarReaderV1<R>
where
    R: Read + Seek,
{
    pub(crate) fn new(mut inner: R) -> Result<Self, CarError> {
        let header = CarHeader::read_header(&mut inner)?;
        let mut sections = HashMap::new();
        while let Some(section) = read_section(&mut inner)? {
            sections.insert(section.cid(), section);
        }
        Ok(Self {
            inner,
            header,
            sections,
        })
    }
}

impl<R> CarReader for CarReaderV1<R>
where
    R: Read + Seek,
{
    #[inline(always)]
    fn header(&self) -> &CarHeader {
        &self.header
    }

    #[inline(always)]
    fn sections(&self) -> Vec<Section> {
        self.sections.values().map(Section::clone).collect()
    }

    #[inline]
    fn read_section_data(&mut self, cid: &Cid) -> Result<Vec<u8>, CarError> {
        let s = self
            .sections
            .get(cid)
            .ok_or(CarError::InvalidSection("cid not exist".into()))?;
        s.read_data(&mut self.inner)
    }

    #[inline]
    fn ipld(&mut self, cid: &Cid) -> Result<Ipld, CarError> {
        let s = self
            .sections
            .get_mut(cid)
            .ok_or(CarError::NotFound("cid not exist".into()))?;
        s.ipld(&mut self.inner)
    }
}

#[cfg(test)]
mod test {

    use super::*;
    use crate::unixfs::UnixFs;

    #[test]
    fn test_read() {
        let file = std::path::Path::new("test");
        let file = file.join("carv1-basic.car");
        let file = std::fs::File::open(file).unwrap();
        let mut reader = CarReaderV1::new(file).unwrap();
        let roots = reader.header().roots();
        assert_eq!(reader.sections().len(), 6);
        for r in roots.iter() {
            let s_ipld = reader.ipld(r).unwrap();
            let unix_fs: Result<UnixFs, CarError> = s_ipld.try_into();
            assert!(unix_fs.is_ok());
            unix_fs.map(|fs| {
                assert_eq!(fs.links.len(), 3);
            });
        }
        let rs = reader.search_file_cid("not-distributed.jpg");
        println!("{rs:?}");
    }
}
