use std::path::{Path, PathBuf};

use super::{UpEndConnection, UpEndDatabase};
use crate::util::{hash::Hash, jobs::JobContainer};

pub mod fs;

#[derive(Debug, Clone)]
pub enum StoreError {
    Unknown(String),
}

impl std::fmt::Display for StoreError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "STORE ERROR: {}",
            match self {
                StoreError::Unknown(err) => err,
            }
        )
    }
}

impl std::error::Error for StoreError {}

type Result<T> = std::result::Result<T, StoreError>;

pub struct Blob {
    file_path: PathBuf,
}

impl Blob {
    pub fn from_filepath<P: AsRef<Path>>(path: P) -> Blob {
        Blob {
            file_path: PathBuf::from(path.as_ref()),
        }
    }

    pub fn get_file_path(&self) -> &Path {
        self.file_path.as_path()
    }
}

#[derive(Debug)]
pub enum UpdatePathOutcome {
    Added(PathBuf),
    Unchanged(PathBuf),
    Skipped(PathBuf),
    Removed(PathBuf),
    Failed(PathBuf, StoreError),
}

pub trait UpStore {
    fn retrieve(&self, hash: &Hash) -> Result<Vec<Blob>>;
    fn retrieve_all(&self) -> Result<Vec<Blob>>;
    fn store(
        &self,
        connection: UpEndConnection,
        blob: Blob,
        name_hint: Option<String>,
    ) -> Result<Hash>;
    fn update(
        &self,
        database: &UpEndDatabase,
        job_container: JobContainer,
        initial: bool,
    ) -> Result<Vec<UpdatePathOutcome>>;
    fn stats(&self) -> Result<serde_json::Value>;
}
