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

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

use crate::dagger_middleware::DaggerMiddleware;

use super::RustService;

pub struct Sqlx {
    client: dagger_sdk::Query,
    migration_path: Option<PathBuf>,
}

impl Sqlx {
    pub fn new(client: dagger_sdk::Query) -> Self {
        Self {
            client,
            migration_path: None,
        }
    }

    pub fn with_migration_path(mut self, migration_path: impl Into<PathBuf>) -> Self {
        self.migration_path = Some(migration_path.into());

        self
    }
}

#[async_trait]
impl DaggerMiddleware for Sqlx {
    async fn handle(&self, container: Container) -> eyre::Result<Container> {
        let container = if std::path::PathBuf::from(".sqlx/").exists() {
            tracing::debug!("found .sqlx folder enabling offline mode");

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

            container
                .with_directory(".sqlx", src)
                .with_env_variable("SQLX_OFFLINE", "true")
        } else {
            tracing::debug!("did not find a .sqlx folder, requires a running database");

            container
        };

        let container = if let Some(migration_path) = &self.migration_path {
            container
                .with_directory(
                    "/mnt/sqlx/migrations",
                    self.client
                        .host()
                        .directory(migration_path.display().to_string()),
                )
                .with_env_variable("NEFARIOUS_DB_MIGRATION_PATH", "/mnt/sqlx/migrations")
        } else {
            container
        };

        Ok(container)
    }
}

pub trait SqlxExt {
    fn with_sqlx(&mut self) -> &mut Self;
    fn with_sqlx_migrations(&mut self, path: impl Into<PathBuf>) -> &mut Self;
}

impl SqlxExt for RustService {
    fn with_sqlx(&mut self) -> &mut Self {
        self.with_stage(super::RustServiceStage::BeforeBuild(Arc::new(Sqlx::new(
            self.client.clone(),
        ))))
    }

    fn with_sqlx_migrations(&mut self, path: impl Into<PathBuf>) -> &mut Self {
        self.with_stage(super::RustServiceStage::BeforeBuild(Arc::new(
            Sqlx::new(self.client.clone()).with_migration_path(path),
        )))
    }
}
