use crate::app::AppState;
use std::path::{Path, PathBuf};

#[derive(Clone)]
pub struct StaticFilesManager {
    pub dir: PathBuf,
    pub index: Vec<String>,
}

impl StaticFilesManager {
    pub fn new(app_state: &AppState) -> Result<Self, String> {
        match Self::create_dir_if_missing(&app_state.config.storage_dir) {
            Ok(dir) => Ok(StaticFilesManager {
                index: Vec::new(),
                dir,
            }),
            Err(msg) => Err(msg),
        }
    }

    fn create_dir_if_missing(app_dir: &PathBuf) -> Result<PathBuf, String> {
        let static_dir = app_dir.join("static");

        if !static_dir.exists() {
            match std::fs::create_dir_all(&static_dir) {
                Ok(_) => {
                    if let Err(err) = Self::copy_default_files(&static_dir) {
                        return Err(format!("{}", err));
                    }
                }
                Err(err) => return Err(format!("{}", err)),
            }
        }

        Ok(static_dir)
    }

    fn copy_default_files(static_dir: &PathBuf) -> Result<(), String> {
        let local_default_static = std::env::current_dir().unwrap().join("default_static");
        let default_static = static_dir.join("default");
        match std::fs::create_dir_all(&default_static) {
            Err(err) => Err(format!("{}", err)),
            Ok(_) => {
                let mut cpy_options = fs_extra::dir::CopyOptions::new();
                cpy_options.content_only = true;
                match fs_extra::dir::copy(local_default_static, default_static, &cpy_options) {
                    Err(err) => Err(format!("{}", err)),
                    Ok(_) => Ok(()),
                }
            }
        }
    }

    fn rec_read_dir(&mut self, root: &Path, strip_from: &Path) {
        for entry in root.read_dir().unwrap() {
            if let Ok(entry) = entry {
                if entry.path().is_dir() {
                    self.rec_read_dir(&entry.path(), strip_from);
                } else {
                    self._push_path(&entry.path(), strip_from);
                }
            }
        }
    }

    fn _push_path(&mut self, path: &Path, strip_from: &Path) {
        let push_path = path.strip_prefix(strip_from).unwrap();
        self.index
            .push(format!("/{}", push_path.to_str().unwrap().to_owned()));
    }

    pub fn build_index(&mut self) {
        self.index = Vec::new();
        self.rec_read_dir(&self.dir.clone(), &self.dir.clone());
    }
}