use std::sync::Arc;

use async_trait::async_trait;
use dagger_sdk::{Container, ImageMediaTypes};

use crate::dagger_middleware::DaggerMiddleware;

use super::RustService;

pub struct DockerCache {
    client: dagger_sdk::Query,
    image_name: String,
}

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

#[async_trait]
impl DaggerMiddleware for DockerCache {
    async fn handle(&self, container: Container) -> eyre::Result<Container> {
        match (
            std::env::var("REGISTRY_CACHE_USERNAME"),
            std::env::var("REGISTRY_CACHE_PASSWORD"),
        ) {
            (Ok(username), Ok(password)) => {
                let url = format!("harbor.front.kjuulh.io/cache/{}:cache", self.image_name);
                let secret = self.client.set_secret("REGISTRY_CACHE_PASSWORD", password);

                container
                    .with_registry_auth(&url, &username, secret)
                    .publish_opts(
                        &url,
                        dagger_sdk::ContainerPublishOpts {
                            forced_compression: Some(dagger_sdk::ImageLayerCompression::Zstd),
                            media_types: Some(ImageMediaTypes::OciMediaTypes),
                            platform_variants: None,
                        },
                    )
                    .await?;
            }
            _ => {
                eprintln!("failed to find REGISTRY_CACHE_USERNAME or REGISTRY_CACHE_PASSWORD");
            }
        }

        Ok(container)
    }
}

pub trait DockerCacheExt {
    fn with_docker_cache(&mut self) -> &mut Self {
        self
    }
}

impl DockerCacheExt for RustService {
    fn with_docker_cache(&mut self) -> &mut Self {
        self.with_stage(super::RustServiceStage::AfterPackage(Arc::new(
            DockerCache::new(self.client.clone(), self.bin_name.clone()),
        )));

        self
    }
}
