use std::borrow::Cow;
use std::sync::Arc;
use actix_files::Files;
use actix_web::dev::HttpServiceFactory;
use path_tree::PathTree;
use tracing::warn;
use crate::spa_service::SpaService;
use crate::utils::{find_and_parse_build_manifest, serve_index};
#[derive(Debug, Clone)]
pub struct Spa {
    index_file: Cow<'static, str>,
    static_resources_mount: Cow<'static, str>,
    static_resources_location: Cow<'static, str>,
}
impl Spa {
    pub fn new() -> Self {
        Self::default()
    }
    pub fn index_file(mut self, index_file: impl Into<String>) -> Self {
        self.index_file = Cow::Owned(index_file.into());
        self
    }
    pub fn static_resources_mount(mut self, static_resources_mount: impl Into<String>) -> Self {
        self.static_resources_mount = Cow::Owned(static_resources_mount.into());
        self
    }
    pub fn static_resources_location(mut self, static_resources_location: impl Into<String>) -> Self {
        self.static_resources_location = Cow::Owned(static_resources_location.into());
        self
    }
    pub fn finish(self) -> impl HttpServiceFactory {
        let index_file = Arc::new(self.index_file.into_owned());
        let static_resources_location = Arc::new(self.static_resources_location.into_owned());
        let static_resources_mount = self.static_resources_mount.into_owned();
        let path_tree = match find_and_parse_build_manifest(&static_resources_location) {
            Ok(tree) => Arc::new(tree),
            Err(e) => {
                warn!("Failed to parse build manifest: {}. Using default path tree.", e);
                Arc::new(PathTree::default())
            }
        };
        let files = Files::new(&static_resources_mount, static_resources_location.as_str())
            .index_file("extremely-unlikely-to-exist-!@$%^&*.txt")
            .default_handler({
                let index_file = Arc::clone(&index_file);
                let static_resources_location = Arc::clone(&static_resources_location);
                let path_tree = Arc::clone(&path_tree);
                move |req| {
                    let index_file = Arc::clone(&index_file);
                    let static_resources_location = Arc::clone(&static_resources_location);
                    let path_tree = Arc::clone(&path_tree);
                    async move {
                        serve_index(req, &index_file, &static_resources_location, &path_tree)
                            .await
                            .map_err(actix_web::Error::from)
                    }
                }
            });
        SpaService {
            index_file,
            static_resources_location,
            files,
            path_tree,
        }
    }
}
impl Default for Spa {
    fn default() -> Self {
        Self {
            index_file: Cow::Borrowed("./index.html"),
            static_resources_mount: Cow::Borrowed("/"),
            static_resources_location: Cow::Borrowed("./"),
        }
    }
}
pub fn spa() -> Spa {
    Spa::default()
}