Documentation
use itertools::Itertools;
use tokio::io::{AsyncReadExt, AsyncWriteExt};

use crate::error::ContextWrapper;

#[derive(Clone)]
pub struct Cache {
    path: String,
    extension: String,
}

impl Cache {
    pub fn new(path: String, extension: String) -> Self {
        std::fs::create_dir_all(&path).ok();
        Self { path, extension }
    }
    pub async fn cached(&self) -> anyhow::Result<Vec<u64>> {
        let mut entries = tokio::fs::read_dir(&self.path).await.anyhow()?;
        let mut file_names: Vec<u64> = Vec::new();

        while let Ok(Some(entry)) = entries.next_entry().await {
            let path = entry.path();
            if path.is_file() {
                if let Some(name) = path.file_name().and_then(|s| s.to_str()) {
                    let asd = name.split('.').collect_vec();
                    file_names.push(asd[0].parse().anyhow()?);
                }
            }
        }

        file_names.sort();

        Ok(file_names)
    }

    pub async fn remove_cache(&self, file: u64) -> anyhow::Result<()> {
        let file = format!("{file}.{}", self.extension);
        let path = std::path::Path::new(&self.path).join(file);
        tokio::fs::remove_file(path).await.anyhow()
    }

    pub async fn write_cache<T: serde::Serialize>(&self, file: u64, data: T) -> anyhow::Result<()> {
        let file = format!("{file}.{}", self.extension);
        let path = std::path::Path::new(&self.path).join(file);
        let data = postcard::to_allocvec(&data).anyhow()?;

        let mut file = tokio::fs::OpenOptions::new()
            .create(true)
            .write(true)
            .truncate(true)
            .open(path)
            .await
            .anyhow()?;

        file.write_all(&data).await.anyhow()?;
        file.flush().await?;

        Ok(())
    }
    pub async fn read_cache<T: for<'a> serde::Deserialize<'a>>(
        &self,
        file: u64,
    ) -> anyhow::Result<T> {
        let file = format!("{file}.{}", self.extension);
        let path = std::path::Path::new(&self.path).join(file);
        let mut buffer = vec![];
        tokio::fs::OpenOptions::new()
            .read(true)
            .open(path)
            .await
            .anyhow()?
            .read_to_end(&mut buffer)
            .await
            .anyhow()?;
        postcard::from_bytes(&buffer).anyhow()
    }
}