//! RAII guards that delete server-side resources on `Drop`.
//!
//! Each guard owns the minimum it needs to issue a single DELETE: the
//! base URL, an admin bearer token, and the resource identifier.
//! Failures are swallowed because Drop runs during teardown — a panic
//! here would just mask the real failure that the test was reporting.

pub struct AppGuard {
    url: String,
    token: String,
    slug: String,
}

impl AppGuard {
    pub fn new(url: &str, token: &str, slug: &str) -> Self {
        Self {
            url: url.to_string(),
            token: token.to_string(),
            slug: slug.to_string(),
        }
    }

    pub fn slug(&self) -> &str {
        &self.slug
    }
}

impl Drop for AppGuard {
    fn drop(&mut self) {
        let client = reqwest::blocking::Client::new();
        let _ = client
            .delete(format!(
                "{}/api/v1/admin/apps/{}?force=true",
                self.url, self.slug
            ))
            .bearer_auth(&self.token)
            .send();
    }
}

/// Deletes a script by id on drop (best-effort). Phase 4: a group-owned
/// script blocks its group's deletion (`ON DELETE RESTRICT`), so register the
/// `ScriptGuard` *after* the owning `GroupGuard` — the script drops (deletes)
/// first, leaving the group removable.
pub struct ScriptGuard {
    url: String,
    token: String,
    id: String,
}

impl ScriptGuard {
    pub fn new(url: &str, token: &str, id: &str) -> Self {
        Self {
            url: url.to_string(),
            token: token.to_string(),
            id: id.to_string(),
        }
    }
}

impl Drop for ScriptGuard {
    fn drop(&mut self) {
        let client = reqwest::blocking::Client::new();
        let _ = client
            .delete(format!("{}/api/v1/admin/scripts/{}", self.url, self.id))
            .bearer_auth(&self.token)
            .send();
    }
}

pub struct UserGuard {
    url: String,
    token: String,
    user_id: String,
}

/// Deletes a group on drop (best-effort). The group must be empty by then
/// — register an `AppGuard`/child `GroupGuard` *after* this one so the
/// child drops (deletes) first, leaving an empty node here.
pub struct GroupGuard {
    url: String,
    token: String,
    slug: String,
}

impl GroupGuard {
    pub fn new(url: &str, token: &str, slug: &str) -> Self {
        Self {
            url: url.to_string(),
            token: token.to_string(),
            slug: slug.to_string(),
        }
    }
}

impl Drop for GroupGuard {
    fn drop(&mut self) {
        let client = reqwest::blocking::Client::new();
        let _ = client
            .delete(format!("{}/api/v1/admin/groups/{}", self.url, self.slug))
            .bearer_auth(&self.token)
            .send();
    }
}

impl UserGuard {
    pub fn new(url: &str, token: &str, user_id: &str) -> Self {
        Self {
            url: url.to_string(),
            token: token.to_string(),
            user_id: user_id.to_string(),
        }
    }
}

impl Drop for UserGuard {
    fn drop(&mut self) {
        let client = reqwest::blocking::Client::new();
        let _ = client
            .delete(format!("{}/api/v1/admin/admins/{}", self.url, self.user_id))
            .bearer_auth(&self.token)
            .send();
    }
}
