use std::{path::PathBuf, sync::Arc};

use async_trait::async_trait;
use dagger_sdk::Container;

use crate::{dagger_middleware::DaggerMiddleware, leptos_service::LeptosService};

use super::RustService;

pub struct Assets {
    client: dagger_sdk::Query,
    assets: Vec<(PathBuf, PathBuf)>,
}

impl Assets {
    pub fn new(client: dagger_sdk::Query) -> Self {
        Self {
            client,
            assets: Vec::default(),
        }
    }

    fn with_folders(mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> Self {
        let mut folders = folders.into_iter().collect::<Vec<(PathBuf, PathBuf)>>();
        self.assets.append(&mut folders);

        self
    }
}

#[async_trait]
impl DaggerMiddleware for Assets {
    async fn handle(&self, container: Container) -> eyre::Result<Container> {
        let container =
            self.assets
                .iter()
                .fold(container, |container, (src_asset_path, dest_asset_path)| {
                    let src_path = src_asset_path.display().to_string();
                    let dest_path = dest_asset_path.display().to_string();
                    let path = self.client.host().directory(src_path);
                    container.with_directory(dest_path, path)
                });

        Ok(container)
    }
}

pub trait AssetsExt {
    fn with_assets(&mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> &mut Self {
        self
    }
}

impl AssetsExt for RustService {
    fn with_assets(&mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> &mut Self {
        self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
            Assets::new(self.client.clone()).with_folders(folders),
        )))
    }
}

impl AssetsExt for LeptosService {
    fn with_assets(&mut self, folders: impl IntoIterator<Item = (PathBuf, PathBuf)>) -> &mut Self {
        self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
            Assets::new(self.client.clone()).with_folders(folders),
        )))
    }
}
