/*
 * Tapis Notifications API
 *
 * The Tapis Notifications API provides for management of subscriptions and event publication
 *
 * The version of the OpenAPI document: 25Q4.0
 * Contact: cicsupport@tacc.utexas.edu
 * Generated by: https://openapi-generator.tech
 */

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

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

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

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

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

/// Start a test sequence by creating a subscription and publishing one or more events matching the subscription. If more than one event requested then events will be published at the rate of 1 every 3 seconds. Only services may perform this operation.  The subscription will have the following properties:   - owner: *api_user*   - name: *subscription_uuid*   - typeFilter: notifications.test.*   - subjectFilter: *subscription_uuid*   - deliveryTarget:     - deliveryMethod: WEBHOOK     - deliveryAddress: *tenant_base_url*_/v3/notifications/test/callback/_*subscription_uuid*   - ttlMinutes: 60  The default TTL of 1 hour may be overridden using the query parameter *subscriptionTTL*.  The initial event will have the following properties:   - source: *tenant_base_url*_/v3/notifications/test   - type: notifications.test.begin   - subject: *subscription_uuid*   - seriesId: *subscription_uuid*  The requested number of events will be published to the main queue and the subscription will be returned to the caller. The sequence of test events may be continued by publishing events that match the test subscription.  Results will be recorded when notifications associated with the test are received via the callback. The first notification should be recorded shortly after the initial event is published. If query parameter *endSeries* is set to true (the default), when the final event of the test sequence is sent it will have the event attribute *endSeries* set to true. This will result in removal of series tracking data.
pub async fn begin_test_sequence(
    configuration: &configuration::Configuration,
    subscription_ttl: Option<i32>,
    number_of_events: Option<i32>,
    end_series: Option<bool>,
    body: Option<serde_json::Value>,
) -> Result<models::RespSubscription, Error<BeginTestSequenceError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_subscription_ttl = subscription_ttl;
    let p_query_number_of_events = number_of_events;
    let p_query_end_series = end_series;
    let p_body_body = body;

    let uri_str = format!("{}/v3/notifications/test/begin", configuration.base_path);
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);

    if let Some(ref param_value) = p_query_subscription_ttl {
        req_builder = req_builder.query(&[("subscriptionTTL", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_number_of_events {
        req_builder = req_builder.query(&[("numberOfEvents", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_series {
        req_builder = req_builder.query(&[("endSeries", &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_body);

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

/// Delete all test sequence artifacts including the subscription, results and event series tracking data. Only services may perform this operation.
pub async fn delete_test_sequence(
    configuration: &configuration::Configuration,
    name: &str,
) -> Result<models::RespChangeCount, Error<DeleteTestSequenceError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_name = name;

    let uri_str = format!(
        "{}/v3/notifications/test/{name}",
        configuration.base_path,
        name = crate::apis::urlencode(p_path_name)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::DELETE, &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<DeleteTestSequenceError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Retrieve status and result history for a test sequence created using the endpoint *test/begin*.
pub async fn get_test_sequence(
    configuration: &configuration::Configuration,
    name: &str,
) -> Result<models::RespTestSequence, Error<GetTestSequenceError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_name = name;

    let uri_str = format!(
        "{}/v3/notifications/test/{name}",
        configuration.base_path,
        name = crate::apis::urlencode(p_path_name)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::GET, &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::RespTestSequence`"))),
            ContentType::Unsupported(unknown_type) => Err(Error::from(serde_json::Error::custom(format!("Received `{unknown_type}` content type response that cannot be converted to `models::RespTestSequence`")))),
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetTestSequenceError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Callback endpoint for receiving a notification associated with a test sequence. Results will be recorded when notifications associated with the test are received via the callback.
pub async fn record_test_notification(
    configuration: &configuration::Configuration,
    name: &str,
    notification: models::Notification,
) -> Result<models::RespBasic, Error<RecordTestNotificationError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_name = name;
    let p_body_notification = notification;

    let uri_str = format!(
        "{}/v3/notifications/test/callback/{name}",
        configuration.base_path,
        name = crate::apis::urlencode(p_path_name)
    );
    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());
    }
    req_builder = req_builder.json(&p_body_notification);

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