use std::{collections::BTreeMap, path::PathBuf, time::UNIX_EPOCH};

const DRONE_TEMPLATER_IMAGE: &str = "kasperhermansen/drone-templater:main-1711807810";

use async_trait::async_trait;
use eyre::{Context, OptionExt};

use crate::{rust_service::RustServiceContext, MainAction};

#[derive(Clone)]
pub struct DroneTemplater {
    client: dagger_sdk::Query,
    template: PathBuf,

    variables: BTreeMap<String, String>,
}

impl DroneTemplater {
    pub fn new(client: dagger_sdk::Query, template: impl Into<PathBuf>) -> Self {
        Self {
            client,
            template: template.into(),
            variables: BTreeMap::default(),
        }
    }

    pub fn with_variable(
        &mut self,
        name: impl Into<String>,
        value: impl Into<String>,
    ) -> &mut Self {
        self.variables.insert(name.into(), value.into());

        self
    }
}

#[async_trait]
impl MainAction for DroneTemplater {
    async fn execute_main(&self, ctx: &mut crate::Context) -> eyre::Result<()> {
        let image_tag = ctx
            .get_image_tag()?
            .ok_or_eyre(eyre::eyre!("failed to find image tag"))?;

        let src = self.client.host().directory(".cuddle/tmp/");

        let drone_host = std::env::var("DRONE_HOST").context("DRONE_HOST is missing")?;
        let drone_user = std::env::var("DRONE_USER").context("DRONE_USER is missing")?;
        let drone_token = std::env::var("DRONE_TOKEN").context("DRONE_TOKEN is missing")?;

        let drone_token_secret = self.client.set_secret("DRONE_TOKEN", drone_token);

        let now = std::time::SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .context("failed to get system time")?;

        let template_name = self.template.display().to_string();

        let cmd = vec!["drone-templater", "upload", "--template", &template_name]
            .into_iter()
            .map(|v| v.to_string())
            .chain(
                self.variables
                    .iter()
                    .map(|(name, value)| format!(r#"--variable={name}={value}"#)),
            )
            .chain(vec![format!("--variable=image_tag={}", image_tag)])
            .collect::<Vec<_>>();

        self.client
            .container()
            .from(DRONE_TEMPLATER_IMAGE)
            .with_env_variable("RUST_LOG", "drone_templater=trace")
            .with_exec(vec!["echo", &format!("{}", now.as_secs())])
            .with_directory("/src/templates", src)
            .with_workdir("/src")
            .with_env_variable("DRONE_HOST", drone_host)
            .with_env_variable("DRONE_USER", drone_user)
            .with_secret_variable("DRONE_TOKEN", drone_token_secret)
            .with_exec(cmd)
            .sync()
            .await
            .context("failed to upload drone templates with error")?;

        Ok(())
    }
}
