/*
 * 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 [`end_event_series`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum EndEventSeriesError {
    Status400(models::RespBasic),
    Status401(models::RespBasic),
    Status500(models::RespBasic),
    UnknownValue(serde_json::Value),
}

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

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

/// End an event series. Series tracking data will be deleted. A subsequent new event published with the same tenant, source, subject and seriesId will create a new series with the *seriesSeqCount* starting at 1. Associated event source, subject and seriesId must be provided in the request body.  To specify a tenant other than the oboTenant, please use the query parameter *tenant*.
pub async fn end_event_series(
    configuration: &configuration::Configuration,
    event_series: models::EventSeries,
    tenant: Option<&str>,
) -> Result<models::RespBasic, Error<EndEventSeriesError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_body_event_series = event_series;
    let p_query_tenant = tenant;

    let uri_str = format!(
        "{}/v3/notifications/events/endSeries",
        configuration.base_path
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &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);
    };
    req_builder = req_builder.json(&p_body_event_series);

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

/// (**DEPRECATED** Please use endpoint *notifications/events/publishEvent*)  Post an event to be distributed to all subscribers. Only services may post events.  The attributes *source*, *type* and *timestamp* are required. Note that certain attributes, marked as *attribute* in the list below, are allowed but ignored. These attributes are maintained by Tapis. They are present when the event is part of a delivered notification.  Event attributes:   - source: Context in which event happened: Examples: *Jobs*, *Systems*.   - type: Type of event. Used for routing notifications. A series of 3 fields separated by the dot character. Pattern is *service.category.detail*. Examples: *jobs.new_status.complete*, *systems.system.create*, *files.object.delete*   - subject: Subject of event in the context of the service. Examples: job Id, system Id, file path, role name, etc.   - timestamp: When the event happened.   - data: Optional additional information associated with the event. Data specific to the service associated with the event.   - deleteSubscriptionsMatchingSubject: Boolean indicating that all subscriptions whose *subjectFilter* matches the *subject* of the event should be deleted once all notifications are delivered.   - seriesId: Optional Id that may be used to group events from the same tenant, source and subject. In a series, event order is preserved when sending out notifications.   - *tenant*: Tapis tenant associated with the event.   - *uuid*: Tapis generated unique identifier.   - *user*: Tapis user associated with the event.  Note that events are not persisted by the front end api service. When received they are simply sent to a message broker. The back end dispatch service will persist events temporarily in order to support recovery.  An event is delivered to the delivery target in a Notification object. Notification attributes:   - uuid: Unique identifier for the notification.   - subscriptionName: Name of subscription associated with the event.   - event: All information contained in the event.   - eventUuid: Unique identifier for the event.   - tenant: tenant associated with the event.   - deliveryTarget: the delivery target   - created: When the notification was created.  For details on the schema for a Notification object, please see the request body specification included under the endpoint for *recordTestNotification*, at path *_/v3/notifications/test/callback/{name}*  Note that certain attributes in the request body (such as tenant) are allowed but ignored. These attributes are maintained by Tapis. They are present when the event is part of a delivered notification. The attributes that are allowed but ignored are    - tenant   - uuid   - user
#[deprecated]
pub async fn post_event(
    configuration: &configuration::Configuration,
    event: models::Event,
    tenant: Option<&str>,
) -> Result<models::RespBasic, Error<PostEventError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_body_event = event;
    let p_query_tenant = tenant;

    let uri_str = format!("{}/v3/notifications/events", configuration.base_path);
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &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);
    };
    req_builder = req_builder.json(&p_body_event);

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

/// Publish an event to be distributed to all subscribers. Only services may publish events.  The attributes *source*, *type* and *timestamp* are required. Note that certain attributes, marked in *italics* in the list below, are allowed but ignored. These attributes are maintained by Tapis. They are present when the event is part of a delivered notification.  A published event may include a value for the attribute *seriesId*. Each series is intended to sequentially track events of various types coming from a given tenant, source and subject. So for each tenant, source and subject the seriesId is considered unique. For example, the Jobs service (the source) sends out events with the jobUuid as the subject and sets the seriesId to the jobUuid. That way, a subscription can be created to follow (in order) all events of various types related to the job. Examples of event types defined in the Jobs service are JOB_NEW_STATUS, JOB_ERROR_MESSAGE, JOB_USER_EVENT.  Tracking data for a series is created automatically when the first event in a series is received. Note that the subject is required. If an event is received without a subject then it will not be part of a series even if the attribute *seriesId* is set. An event publisher may indicate that this is the last event in a series by publishing an event with the attribute *endSeries* to true or by calling the endpoint *notifications/events/endSeries*. When a series is ended, tracking data for that series is deleted. This effectively resets the seriesSeqCount. A subsequent event published with the same seriesId will create a new series with a seriesSeqCount starting at 1.  Event attributes:   - source: Context in which event happened: Examples: *Jobs*, *Systems*.   - type: Type of event. Used for routing notifications. A series of 3 fields separated by the dot character. Pattern is *service.category.detail*. Examples: *jobs.new_status.complete*, *systems.system.create*, *files.object.delete*   - subject: Subject of event in the context of the service. Examples: job Id, system Id, file path, role name, etc.   - timestamp: When the event happened.   - data: Optional additional information associated with the event. Data specific to the service associated with the event.   - deleteSubscriptionsMatchingSubject: Boolean indicating that all subscriptions whose *subjectFilter* exactly matches the *subject* of the event should be deleted once all notifications are delivered. This will also end the series if seriesId is set.   - seriesId: Optional Id that may be used to group events from the same tenant, source and subject. In a series, event order is preserved when sending out notifications.   - endSeries: Boolean indicating that this is the last event in a series. Series tracking data will be deleted.   - *tenant*: Tapis tenant associated with the event.   - *uuid*: Tapis generated unique identifier.   - *user*: Tapis user associated with the event.   - *received*: Tapis generated timestamp for when the event was received by Tapis.   - *seriesSeqCount*: Tapis generated counter for seriesId. Can be used by notification receivers to track expected order. Notifications for events will be sent in order but may not be received in order.  Note that events are not persisted by the front end api service. When received they are simply sent to a message broker. The back end dispatch service will persist events temporarily in order to support recovery.  An event is delivered to the delivery target in a Notification object. Notification attributes:   - uuid: Unique identifier for the notification.   - subscriptionName: Name of subscription associated with the event.   - event: All information contained in the event.   - eventUuid: Unique identifier for the event.   - tenant: tenant associated with the event.   - deliveryTarget: the delivery target   - created: When the notification was created.  For details on the schema for a Notification object, please see the request body specification included under the endpoint for *recordTestNotification*, at path *_/v3/notifications/test/callback/{name}*  Note that certain attributes in the request body (such as tenant) are allowed but ignored. These attributes are maintained by Tapis. They are present when the event is part of a delivered notification. The attributes that are allowed but ignored are    - tenant   - uuid   - user   - received   - seriesSeqCount
pub async fn publish_event(
    configuration: &configuration::Configuration,
    event: models::Event,
    tenant: Option<&str>,
) -> Result<models::RespBasic, Error<PublishEventError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_body_event = event;
    let p_query_tenant = tenant;

    let uri_str = format!(
        "{}/v3/notifications/events/publish",
        configuration.base_path
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &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);
    };
    req_builder = req_builder.json(&p_body_event);

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