/*
 * Tapis Systems API
 *
 * The Tapis Systems API provides for management of Tapis Systems including permissions, credentials and Scheduler Profiles.
 *
 * The version of the OpenAPI document: 26Q1.1
 * Contact: cicsupport@tacc.utexas.edu
 * Generated by: https://openapi-generator.tech
 */

use super::{ContentType, Error, configuration};
use crate::{apis::ResponseContent, models};
use reqwest;
use serde::{Deserialize, Serialize, de::Error as _};

/// struct for typed errors of method [`create_child_system`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CreateChildSystemError {
    Status400(models::RespBasic),
    Status403(models::RespBasic),
    Status409(models::RespResourceUrl),
    Status500(models::RespBasic),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`unlink_children`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UnlinkChildrenError {
    Status403(models::RespBasic),
    Status404(models::RespBasic),
    Status500(models::RespBasic),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`unlink_from_parent`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UnlinkFromParentError {
    Status403(models::RespBasic),
    Status404(models::RespBasic),
    Status500(models::RespBasic),
    UnknownValue(serde_json::Value),
}

/// Create a child system based on a parent system. The child system inherits most attributes from the parent. The following fields are filled in when the child system is created:   - *id*   - *effectiveUserId*   - *rootDir*   - *owner*  The owner will be the user who is creating the system. The caller must have read permission on the parent system.
pub async fn create_child_system(
    configuration: &configuration::Configuration,
    parent_id: &str,
    req_post_child_system: models::ReqPostChildSystem,
) -> Result<models::RespResourceUrl, Error<CreateChildSystemError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_parent_id = parent_id;
    let p_body_req_post_child_system = req_post_child_system;

    let uri_str = format!(
        "{}/v3/systems/{parentId}/createChildSystem",
        configuration.base_path,
        parentId = crate::apis::urlencode(p_path_parent_id)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);

    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref apikey) = configuration.api_key {
        let key = apikey.key.clone();
        let value = match apikey.prefix {
            Some(ref prefix) => format!("{} {}", prefix, key),
            None => key,
        };
        req_builder = req_builder.header("X-Tapis-Token", value);
    };
    req_builder = req_builder.json(&p_body_req_post_child_system);

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => Err(Error::from(serde_json::Error::custom(
                "Received `text/plain` content type response that cannot be converted to `models::RespResourceUrl`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `models::RespResourceUrl`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<CreateChildSystemError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Make a child system a standalone system.  This will break the connection with it's parent, and from this point on, the child system will not be connected to the parent.  This is similar to unlinkFromParent, but permissions are required for the parent system rather than the child system. **WARNING** This cannot be undone.
pub async fn unlink_children(
    configuration: &configuration::Configuration,
    parent_system_id: &str,
    all: Option<bool>,
    req_unlink_children: Option<models::ReqUnlinkChildren>,
) -> Result<models::RespChangeCount, Error<UnlinkChildrenError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_parent_system_id = parent_system_id;
    let p_query_all = all;
    let p_body_req_unlink_children = req_unlink_children;

    let uri_str = format!(
        "{}/v3/systems/{parentSystemId}/unlinkChildren",
        configuration.base_path,
        parentSystemId = crate::apis::urlencode(p_path_parent_system_id)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);

    if let Some(ref param_value) = p_query_all {
        req_builder = req_builder.query(&[("all", &param_value.to_string())]);
    }
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref apikey) = configuration.api_key {
        let key = apikey.key.clone();
        let value = match apikey.prefix {
            Some(ref prefix) => format!("{} {}", prefix, key),
            None => key,
        };
        req_builder = req_builder.header("X-Tapis-Token", value);
    };
    req_builder = req_builder.json(&p_body_req_unlink_children);

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => Err(Error::from(serde_json::Error::custom(
                "Received `text/plain` content type response that cannot be converted to `models::RespChangeCount`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `models::RespChangeCount`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<UnlinkChildrenError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Make a child system a standalone system. This will break the connection with it's parent. From this point on, the child system will not be connected to the parent. **WARNING** This cannot be undone.
pub async fn unlink_from_parent(
    configuration: &configuration::Configuration,
    child_system_id: &str,
) -> Result<models::RespChangeCount, Error<UnlinkFromParentError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_child_system_id = child_system_id;

    let uri_str = format!(
        "{}/v3/systems/{childSystemId}/unlinkFromParent",
        configuration.base_path,
        childSystemId = crate::apis::urlencode(p_path_child_system_id)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);

    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }
    if let Some(ref apikey) = configuration.api_key {
        let key = apikey.key.clone();
        let value = match apikey.prefix {
            Some(ref prefix) => format!("{} {}", prefix, key),
            None => key,
        };
        req_builder = req_builder.header("X-Tapis-Token", value);
    };

    let req = req_builder.build()?;
    let resp = configuration.client.execute(req).await?;

    let status = resp.status();
    let content_type = resp
        .headers()
        .get("content-type")
        .and_then(|v| v.to_str().ok())
        .unwrap_or("application/octet-stream");
    let content_type = super::ContentType::from(content_type);

    if !status.is_client_error() && !status.is_server_error() {
        let content = resp.text().await?;
        match content_type {
            ContentType::Json => serde_json::from_str(&content).map_err(Error::from),
            ContentType::Text => Err(Error::from(serde_json::Error::custom(
                "Received `text/plain` content type response that cannot be converted to `models::RespChangeCount`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `models::RespChangeCount`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<UnlinkFromParentError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}
