use std::sync::Arc;

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

use crate::dagger_middleware::DaggerMiddleware;

use super::RustService;

pub struct DaggerBin {
    client: dagger_sdk::Query,
    version: String,
}

impl DaggerBin {
    pub fn new(client: dagger_sdk::Query, version: impl Into<String>) -> Self {
        Self {
            client,
            version: version.into(),
        }
    }
}

#[async_trait]
impl DaggerMiddleware for DaggerBin {
    async fn handle(&self, container: Container) -> eyre::Result<Container> {
        let install_script = self.client.http("https://dl.dagger.io/dagger/install.sh");

        let dagger_bin = self
            .client
            .container()
            .from("alpine")
            .with_file_opts(
                "/mnt/install.sh",
                install_script,
                dagger_sdk::ContainerWithFileOpts {
                    owner: None,
                    permissions: Some(0o755),
                    expand: None,
                },
            )
            .with_env_variable("DAGGER_VERSION", &self.version)
            .with_exec(vec!["/mnt/install.sh"])
            .file("/bin/dagger");

        Ok(container
            .with_file_opts(
                "/usr/local/bin/dagger",
                dagger_bin,
                dagger_sdk::ContainerWithFileOpts {
                    owner: None,
                    permissions: Some(0o755),
                    expand: None,
                },
            )
            .with_exec(vec!["/usr/local/bin/dagger", "version"]))
    }
}

pub trait DaggerBinExt {
    fn with_dagger_bin(&mut self, dagger_version: impl Into<String>) -> &mut Self;
}

impl DaggerBinExt for RustService {
    fn with_dagger_bin(&mut self, dagger_version: impl Into<String>) -> &mut Self {
        self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
            DaggerBin::new(self.client.clone(), dagger_version.into()),
        )));

        self
    }
}
