/*
 * Tapis Security API
 *
 * The Tapis Security API provides for management of Security Kernel (SK) role-based authorization and secrets resources.
 *
 * The version of the OpenAPI document: 1.8.2
 * 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 [`delete_share`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DeleteShareError {
    Status400(models::RespBasic),
    Status401(models::RespBasic),
    Status500(models::RespBasic),
    UnknownValue(serde_json::Value),
}

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

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

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

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

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

/// Delete a single shared resource by unique attribute selection. The *grantor*, *grantee*, *tenant*, *resourceType*, *resourceId1* and *privilege* parameters are mandatory; *resourceId2* is optional and assumed to be NULL if not provided.  The shared resource is deleted only if it's in the tenant specified in the required *tenant* query parameter. The calling service must also be the same as the orginal service that granted the share.  This call is idempotent. If no share satisfies the above constraints, a success response code is returned and the indicated number of changes is set to zero. When a share is deleted, the indicated number of changes is one.  For the request to be authorized, the requestor must be the Tapis service that originally granted the share.
pub async fn delete_share(
    configuration: &configuration::Configuration,
    grantor: Option<&str>,
    grantee: Option<&str>,
    tenant: Option<&str>,
    resource_type: Option<&str>,
    resource_id1: Option<&str>,
    resource_id2: Option<&str>,
    privilege: Option<&str>,
) -> Result<models::RespChangeCount, Error<DeleteShareError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_grantor = grantor;
    let p_query_grantee = grantee;
    let p_query_tenant = tenant;
    let p_query_resource_type = resource_type;
    let p_query_resource_id1 = resource_id1;
    let p_query_resource_id2 = resource_id2;
    let p_query_privilege = privilege;

    let uri_str = format!("{}/security/share", configuration.base_path);
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::DELETE, &uri_str);

    if let Some(ref param_value) = p_query_grantor {
        req_builder = req_builder.query(&[("grantor", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_grantee {
        req_builder = req_builder.query(&[("grantee", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_tenant {
        req_builder = req_builder.query(&[("tenant", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_type {
        req_builder = req_builder.query(&[("resourceType", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_id1 {
        req_builder = req_builder.query(&[("resourceId1", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_id2 {
        req_builder = req_builder.query(&[("resourceId2", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_privilege {
        req_builder = req_builder.query(&[("privilege", &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);
    };

    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<DeleteShareError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Delete a shared resource by ID. The shared resource is deleted only if it's in the tenant specified in the required *tenant* query parameter. The calling service must also be the same as the orginal service that created the share.  This call is idempotent. If no share satisfies the above constraints, a success response code is returned and the indicated number of changes is set to zero. When a share is deleted, the indicated number of changes is one.  For the request to be authorized, the requestor must be the Tapis service that originally granted the share.
pub async fn delete_share_by_id(
    configuration: &configuration::Configuration,
    id: i32,
    tenant: Option<&str>,
) -> Result<models::RespChangeCount, Error<DeleteShareByIdError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_id = id;
    let p_query_tenant = tenant;

    let uri_str = format!(
        "{}/security/share/{id}",
        configuration.base_path,
        id = p_path_id
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::DELETE, &uri_str);

    if let Some(ref param_value) = p_query_tenant {
        req_builder = req_builder.query(&[("tenant", &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);
    };

    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<DeleteShareByIdError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Get a shared resource by ID. The shared resource is deleted only if it's in the tenant specified in the required *tenant* query parameter.  For the request to be authorized, the requestor must be a Tapis service.
pub async fn get_share(
    configuration: &configuration::Configuration,
    id: i32,
    tenant: Option<&str>,
) -> Result<models::RespShare, Error<GetShareError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_id = id;
    let p_query_tenant = tenant;

    let uri_str = format!(
        "{}/security/share/{id}",
        configuration.base_path,
        id = p_path_id
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_tenant {
        req_builder = req_builder.query(&[("tenant", &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);
    };

    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::RespShare`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `models::RespShare`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetShareError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Get a filtered list of shared resources. Query parameters are used to restrict the returned shares. The *grantor*, *grantee*, *tenant*, *resourceType*, *resourceId1*, *resourceId2*, *privilege*, *createdBy* and *createdByTenant* parameters are used to match values in shared resource objects. Other query parameters are used to control how matching is performed. The *tenant* parameter is required.  If resourceId1 or resourceId2 end with a percent sign (%) wildcard then the search results will include all shares with IDs that begin with the same prefix string. Percent signs embedded elsewhere in the string are *not* recognized as wildcards.  Specifying the *id* parameter causes the other filtering parameters to be ignored. The result list will contain at most one entry.  The *includePublicGrantees* flag, true by default, controls whether resources granted to **~public** and **~public_no_authn** are also considered for inclusion in the result list.  The *requireNullId2* flag, true by default, applies only when no *resourceId2* value is provided. When set, only shared resources that do not specify a *resourceId2* value are considered for inclusion in the result list. By setting this flag to false the caller indicates a \"don't care\" designation on the *resourceId2* value, allowing shares with any *resourceId2* value to be considered for inclusion in the result list.  For the request to be authorized, the requestor must be a Tapis service.
pub async fn get_shares(
    configuration: &configuration::Configuration,
    grantor: Option<&str>,
    grantee: Option<&str>,
    tenant: Option<&str>,
    resource_type: Option<&str>,
    resource_id1: Option<&str>,
    resource_id2: Option<&str>,
    privilege: Option<&str>,
    created_by: Option<&str>,
    created_by_tenant: Option<&str>,
    include_public_grantees: Option<bool>,
    require_null_id2: Option<bool>,
    id: Option<i32>,
) -> Result<models::RespShareList, Error<GetSharesError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_grantor = grantor;
    let p_query_grantee = grantee;
    let p_query_tenant = tenant;
    let p_query_resource_type = resource_type;
    let p_query_resource_id1 = resource_id1;
    let p_query_resource_id2 = resource_id2;
    let p_query_privilege = privilege;
    let p_query_created_by = created_by;
    let p_query_created_by_tenant = created_by_tenant;
    let p_query_include_public_grantees = include_public_grantees;
    let p_query_require_null_id2 = require_null_id2;
    let p_query_id = id;

    let uri_str = format!("{}/security/share", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_grantor {
        req_builder = req_builder.query(&[("grantor", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_grantee {
        req_builder = req_builder.query(&[("grantee", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_tenant {
        req_builder = req_builder.query(&[("tenant", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_type {
        req_builder = req_builder.query(&[("resourceType", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_id1 {
        req_builder = req_builder.query(&[("resourceId1", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_id2 {
        req_builder = req_builder.query(&[("resourceId2", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_privilege {
        req_builder = req_builder.query(&[("privilege", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_created_by {
        req_builder = req_builder.query(&[("createdBy", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_created_by_tenant {
        req_builder = req_builder.query(&[("createdByTenant", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_include_public_grantees {
        req_builder = req_builder.query(&[("includePublicGrantees", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_require_null_id2 {
        req_builder = req_builder.query(&[("requireNullId2", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_id {
        req_builder = req_builder.query(&[("id", &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);
    };

    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::RespShareList`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `models::RespShareList`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetSharesError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Determine if a user has been granted a specific privilege on a specific resource. The *grantee*, *tenant*, *resourceType*, *resourceId1* and *privilege* parameters are mandatory; *resourceId2* is optional and assumed to be NULL if not provided. Privilege matching is performed for the grantee and tenant specified in the query parameters.  True is returned if the user has been granted the privilege, false otherwise.  By default, both authenticated and unauthenticated public privileges are included in the calculation. For example, if a privilege on a resource has been granted to all authenticated users in a tenant (~public), then true will be returned for all users in the tenant.  The *excludePublic* and *excludePublicNoAuthn* parameters can be used to change the default handling of public grants. Either or both types of public grants can be excluded.  For the request to be authorized, the requestor must be a Tapis service.
pub async fn has_privilege(
    configuration: &configuration::Configuration,
    grantee: Option<&str>,
    tenant: Option<&str>,
    resource_type: Option<&str>,
    resource_id1: Option<&str>,
    resource_id2: Option<&str>,
    privilege: Option<&str>,
    exclude_public: Option<bool>,
    exclude_public_no_authn: Option<bool>,
) -> Result<models::RespBoolean, Error<HasPrivilegeError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_grantee = grantee;
    let p_query_tenant = tenant;
    let p_query_resource_type = resource_type;
    let p_query_resource_id1 = resource_id1;
    let p_query_resource_id2 = resource_id2;
    let p_query_privilege = privilege;
    let p_query_exclude_public = exclude_public;
    let p_query_exclude_public_no_authn = exclude_public_no_authn;

    let uri_str = format!("{}/security/share/hasPrivilege", configuration.base_path);
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);

    if let Some(ref param_value) = p_query_grantee {
        req_builder = req_builder.query(&[("grantee", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_tenant {
        req_builder = req_builder.query(&[("tenant", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_type {
        req_builder = req_builder.query(&[("resourceType", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_id1 {
        req_builder = req_builder.query(&[("resourceId1", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_resource_id2 {
        req_builder = req_builder.query(&[("resourceId2", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_privilege {
        req_builder = req_builder.query(&[("privilege", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_exclude_public {
        req_builder = req_builder.query(&[("excludePublic", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_exclude_public_no_authn {
        req_builder = req_builder.query(&[("excludePublicNoAuthn", &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);
    };

    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::RespBoolean`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `models::RespBoolean`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<HasPrivilegeError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Share a Tapis resource using a request body. Shared resources allow services to indicate that other services should relax their Tapis authorization checking in certain, well-defined contexts.  Grantees can be given shared access to a resource on an individual basis or by using the public granting mechanism. Grants to the distinguished **~public** and **~public_no_authn** pseudo-grantees allow access to a resource to authenticated users or to any user, respectively.  The payload for this request includes these values, with all except *resourceId2* required:     - grantor    - grantee    - tenant    - resourceType    - resourceId1    - resourceId2    - privilege  If the share already exists, then this call has no effect. For the request to be authorized, the requestor must be a Tapis service.
pub async fn share_resource(
    configuration: &configuration::Configuration,
    req_share_resource: models::ReqShareResource,
) -> Result<models::RespResourceUrl, Error<ShareResourceError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_body_req_share_resource = req_share_resource;

    let uri_str = format!("{}/security/share", configuration.base_path);
    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_share_resource);

    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<ShareResourceError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}
