use std::sync::Arc;

use async_trait::async_trait;
use dagger_sdk::{Container, ContainerWithNewFileOptsBuilder};
use eyre::Context;

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

use super::RustService;

pub struct SshAgent {
    client: dagger_sdk::Query,
}

impl SshAgent {
    pub fn new(client: dagger_sdk::Query) -> Self {
        Self { client }
    }
}

#[async_trait]
impl DaggerMiddleware for SshAgent {
    async fn handle(&self, container: Container) -> eyre::Result<Container> {
        let sock_var =
            std::env::var("SSH_AUTH_SOCK").context("failed to find variable SSH_AUTH_SOCK")?;

        let socket = self.client.host().unix_socket(&sock_var);

        let c = container
            .with_new_file_opts(
                ".ssh/config".to_string(),
                r#"
Host *
  UserKnownHostsFile=/dev/null
  StrictHostKeyChecking no

                "#,
                ContainerWithNewFileOptsBuilder::default()
                    .permissions(0o700_isize)
                    .build()?,
            )
            .with_unix_socket(&sock_var, socket)
            .with_env_variable("SSH_AUTH_SOCK", &sock_var);

        Ok(c)
    }
}

pub trait SshAgentExt {
    fn with_ssh_agent(&mut self) -> &mut Self {
        self
    }
}

impl SshAgentExt for RustService {
    fn with_ssh_agent(&mut self) -> &mut Self {
        let client = self.client.clone();

        self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
            SshAgent::new(client.clone()),
        )))
        .with_stage(super::RustServiceStage::BeforeBase(Arc::new(
            SshAgent::new(client),
        )))
    }
}

impl SshAgentExt for LeptosService {
    fn with_ssh_agent(&mut self) -> &mut Self {
        let client = self.client.clone();

        self.with_stage(super::RustServiceStage::BeforeDeps(Arc::new(
            SshAgent::new(client.clone()),
        )))
        .with_stage(super::RustServiceStage::AfterBase(Arc::new(SshAgent::new(
            client,
        ))))
    }
}
