/*
 * Tapis Meta V3 API
 *
 * The Tapis Meta API provides access to a MongoDB database. A standalone service which connects to a MongoDB database and immediately exposes all of MongoDB’s capabilities through a complete REST API, which allows the user to read and write JSON messages and binary data via HTTP.
 *
 * The version of the OpenAPI document: 0.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_document`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CreateDocumentError {
    Status401(serde_json::Value),
    Status500(serde_json::Value),
    UnknownValue(serde_json::Value),
}

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

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

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

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

///  Create a new document in collection.  A document request body with out the field <_id> gets an auto generated id  A document request body with out the field <_id> writes a document with that id unless a duplicate is encountered.  A batch of document creations is possible by submitting an array of documents in the request body. All those documents  will be added to to the collection in bulk.  The addition of the (basic) query parameter set to true will return a response for a single document creation as a   Tapis basic response with the newly created <_id> for later reference.
pub async fn create_document(
    configuration: &configuration::Configuration,
    db: &str,
    collection: &str,
    basic: Option<bool>,
    body: Option<serde_json::Value>,
) -> Result<serde_json::Value, Error<CreateDocumentError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_db = db;
    let p_path_collection = collection;
    let p_query_basic = basic;
    let p_body_body = body;

    let uri_str = format!(
        "{}/meta/{db}/{collection}",
        configuration.base_path,
        db = crate::apis::urlencode(p_path_db),
        collection = crate::apis::urlencode(p_path_collection)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::POST, &uri_str);

    if let Some(ref param_value) = p_query_basic {
        req_builder = req_builder.query(&[("basic", &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 `serde_json::Value`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `serde_json::Value`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<CreateDocumentError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Delete a document in the collection by id.
pub async fn delete_document(
    configuration: &configuration::Configuration,
    db: &str,
    collection: &str,
    doc_id: &str,
) -> Result<(), Error<DeleteDocumentError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_db = db;
    let p_path_collection = collection;
    let p_path_doc_id = doc_id;

    let uri_str = format!(
        "{}/meta/{db}/{collection}/{docId}",
        configuration.base_path,
        db = crate::apis::urlencode(p_path_db),
        collection = crate::apis::urlencode(p_path_collection),
        docId = crate::apis::urlencode(p_path_doc_id)
    );
    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();

    if !status.is_client_error() && !status.is_server_error() {
        Ok(())
    } else {
        let content = resp.text().await?;
        let entity: Option<DeleteDocumentError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Get a document form the collection by its _id.
pub async fn get_document(
    configuration: &configuration::Configuration,
    db: &str,
    collection: &str,
    doc_id: &str,
) -> Result<serde_json::Value, Error<GetDocumentError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_db = db;
    let p_path_collection = collection;
    let p_path_doc_id = doc_id;

    let uri_str = format!(
        "{}/meta/{db}/{collection}/{docId}",
        configuration.base_path,
        db = crate::apis::urlencode(p_path_db),
        collection = crate::apis::urlencode(p_path_collection),
        docId = crate::apis::urlencode(p_path_doc_id)
    );
    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 `serde_json::Value`",
            ))),
            ContentType::Unsupported(unknown_type) => {
                Err(Error::from(serde_json::Error::custom(format!(
                    "Received `{unknown_type}` content type response that cannot be converted to `serde_json::Value`"
                ))))
            }
        }
    } else {
        let content = resp.text().await?;
        let entity: Option<GetDocumentError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Modify a document in the collection with _id. The fields submitted in the json of the request body will replace the same named fields in the current document.
pub async fn modify_document(
    configuration: &configuration::Configuration,
    db: &str,
    collection: &str,
    doc_id: &str,
    np: Option<bool>,
    body: Option<serde_json::Value>,
) -> Result<(), Error<ModifyDocumentError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_db = db;
    let p_path_collection = collection;
    let p_path_doc_id = doc_id;
    let p_query_np = np;
    let p_body_body = body;

    let uri_str = format!(
        "{}/meta/{db}/{collection}/{docId}",
        configuration.base_path,
        db = crate::apis::urlencode(p_path_db),
        collection = crate::apis::urlencode(p_path_collection),
        docId = crate::apis::urlencode(p_path_doc_id)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::PATCH, &uri_str);

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

    if !status.is_client_error() && !status.is_server_error() {
        Ok(())
    } else {
        let content = resp.text().await?;
        let entity: Option<ModifyDocumentError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}

/// Replace a document in the collection with the _id.  Replaces the document with the json document submitted in the request body.
pub async fn replace_document(
    configuration: &configuration::Configuration,
    db: &str,
    collection: &str,
    doc_id: &str,
    body: Option<serde_json::Value>,
) -> Result<(), Error<ReplaceDocumentError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_db = db;
    let p_path_collection = collection;
    let p_path_doc_id = doc_id;
    let p_body_body = body;

    let uri_str = format!(
        "{}/meta/{db}/{collection}/{docId}",
        configuration.base_path,
        db = crate::apis::urlencode(p_path_db),
        collection = crate::apis::urlencode(p_path_collection),
        docId = crate::apis::urlencode(p_path_doc_id)
    );
    let mut req_builder = configuration.client.request(reqwest::Method::PUT, &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_body);

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

    let status = resp.status();

    if !status.is_client_error() && !status.is_server_error() {
        Ok(())
    } else {
        let content = resp.text().await?;
        let entity: Option<ReplaceDocumentError> = serde_json::from_str(&content).ok();
        Err(Error::ResponseError(ResponseContent {
            status,
            content,
            entity,
        }))
    }
}
