/*
 * Mithril
 *
 * Mithril Compute API
 *
 * The version of the OpenAPI document: 1.0.0
 *
 * 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 [`create_reservation_v2_reservation_post`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum CreateReservationV2ReservationPostError {
    Status422(models::HttpValidationError),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`extend_reservation_v2_reservation_reservation_fid_extend_post`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ExtendReservationV2ReservationReservationFidExtendPostError {
    Status422(models::HttpValidationError),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_availability_v2_reservation_availability_get`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetAvailabilityV2ReservationAvailabilityGetError {
    Status422(models::HttpValidationError),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_extension_availability_v2_reservation_reservation_fid_extension_availability_get`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetExtensionAvailabilityV2ReservationReservationFidExtensionAvailabilityGetError {
    Status422(models::HttpValidationError),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`get_reservations_v2_reservation_get`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum GetReservationsV2ReservationGetError {
    Status422(models::HttpValidationError),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`update_reservation_v2_reservation_reservation_fid_patch`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum UpdateReservationV2ReservationReservationFidPatchError {
    Status422(models::HttpValidationError),
    UnknownValue(serde_json::Value),
}

/// Create a new reservation
pub async fn create_reservation_v2_reservation_post(
    configuration: &configuration::Configuration,
    create_reservation_request: models::CreateReservationRequest,
) -> Result<models::ReservationModel, Error<CreateReservationV2ReservationPostError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_body_create_reservation_request = create_reservation_request;

    let uri_str = format!("{}/v2/reservation", 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 token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };
    req_builder = req_builder.json(&p_body_create_reservation_request);

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

/// Extend a reservation to the requested time.
pub async fn extend_reservation_v2_reservation_reservation_fid_extend_post(
    configuration: &configuration::Configuration,
    reservation_fid: &str,
    extend_reservation_request: models::ExtendReservationRequest,
) -> Result<
    models::ReservationModel,
    Error<ExtendReservationV2ReservationReservationFidExtendPostError>,
> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_reservation_fid = reservation_fid;
    let p_body_extend_reservation_request = extend_reservation_request;

    let uri_str = format!(
        "{}/v2/reservation/{reservation_fid}/extend",
        configuration.base_path,
        reservation_fid = crate::apis::urlencode(p_path_reservation_fid)
    );
    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 token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };
    req_builder = req_builder.json(&p_body_extend_reservation_request);

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

/// Get availability information for reservations.  This endpoint supports three different modes for querying availability:  ## Mode: latest_end_time (default) Get the latest possible end time for a reservation given a start time and quantity.  **Required parameters:** - `start_time`: Desired start time for the reservation - `quantity`: Number of instances needed - `project`: Project FID - `instance_type`: Instance type FID - `region`: Region name  **Returns:** Latest possible end time and availability status  **Example:** ``` GET /reservation/availability?     start_time=2024-01-01T00:00:00Z&     quantity=4&     project=proj_01h8x2k9m3n4p5q6r7s8t9u0v&     instance_type=it_01h8x2k9m3n4p5q6r7s8t9u0v&     region=us-central1-a ```  ## Mode: slots Get all available slots in a time range.  **Required parameters:** - `earliest_start_time`: Start of the time range to search - `latest_end_time`: End of the time range to search - `project`: Project FID - `instance_type`: Instance type FID - `region`: Region name  **Returns:** List of available time slots with quantities  **Example:** ``` GET /reservation/availability?     mode=slots&     earliest_start_time=2024-01-01T00:00:00Z&     latest_end_time=2024-01-02T00:00:00Z&     project=proj_01h8x2k9m3n4p5q6r7s8t9u0v&     instance_type=it_01h8x2k9m3n4p5q6r7s8t9u0v&     region=us-central1-a ```  ## Mode: check Check if a specific time slot is available for reservation.  **Required parameters:** - `start_time`: Start of the desired time slot - `end_time`: End of the desired time slot - `quantity`: Number of instances needed - `project`: Project FID - `instance_type`: Instance type FID - `region`: Region name  **Returns:** Boolean indicating if the slot is available  **Example:** ``` GET /reservation/availability?     mode=check&     start_time=2024-01-01T00:00:00Z&     end_time=2024-01-01T12:00:00Z&     quantity=4&     project=proj_01h8x2k9m3n4p5q6r7s8t9u0v&     instance_type=it_01h8x2k9m3n4p5q6r7s8t9u0v&     region=us-central1-a ```  ## Common Parameters All modes require these parameters: - `project`: Project FID - `instance_type`: Instance type FID - `region`: Region name  ## Authentication Requires authentication and user must be a member of the specified project.
pub async fn get_availability_v2_reservation_availability_get(
    configuration: &configuration::Configuration,
    project: &str,
    instance_type: &str,
    region: &str,
    mode: Option<&str>,
    earliest_start_time: Option<&str>,
    latest_end_time: Option<&str>,
    start_time: Option<&str>,
    end_time: Option<&str>,
    quantity: Option<i32>,
) -> Result<
    Vec<models::AvailabilitySlotModel>,
    Error<GetAvailabilityV2ReservationAvailabilityGetError>,
> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_project = project;
    let p_query_instance_type = instance_type;
    let p_query_region = region;
    let p_query_mode = mode;
    let p_query_earliest_start_time = earliest_start_time;
    let p_query_latest_end_time = latest_end_time;
    let p_query_start_time = start_time;
    let p_query_end_time = end_time;
    let p_query_quantity = quantity;

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

    req_builder = req_builder.query(&[("project", &p_query_project.to_string())]);
    req_builder = req_builder.query(&[("instance_type", &p_query_instance_type.to_string())]);
    req_builder = req_builder.query(&[("region", &p_query_region.to_string())]);
    if let Some(ref param_value) = p_query_mode {
        req_builder = req_builder.query(&[("mode", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_earliest_start_time {
        req_builder = req_builder.query(&[("earliest_start_time", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_latest_end_time {
        req_builder = req_builder.query(&[("latest_end_time", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_start_time {
        req_builder = req_builder.query(&[("start_time", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_end_time {
        req_builder = req_builder.query(&[("end_time", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_quantity {
        req_builder = req_builder.query(&[("quantity", &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 token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

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

/// Get extension availability for a reservation
pub async fn get_extension_availability_v2_reservation_reservation_fid_extension_availability_get(
    configuration: &configuration::Configuration,
    reservation_fid: &str,
) -> Result<
    models::ExtensionAvailabilityResponse,
    Error<GetExtensionAvailabilityV2ReservationReservationFidExtensionAvailabilityGetError>,
> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_reservation_fid = reservation_fid;

    let uri_str = format!(
        "{}/v2/reservation/{reservation_fid}/extension-availability",
        configuration.base_path,
        reservation_fid = crate::apis::urlencode(p_path_reservation_fid)
    );
    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 token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

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

/// Get all reservations for a project
pub async fn get_reservations_v2_reservation_get(
    configuration: &configuration::Configuration,
    project: &str,
    next_cursor: Option<serde_json::Value>,
    sort_by: Option<&str>,
    sort_dir: Option<models::SortDirection>,
    instance_type: Option<&str>,
    region: Option<&str>,
    status: Option<&str>,
    limit: Option<i32>,
) -> Result<models::GetReservationsResponse, Error<GetReservationsV2ReservationGetError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_project = project;
    let p_query_next_cursor = next_cursor;
    let p_query_sort_by = sort_by;
    let p_query_sort_dir = sort_dir;
    let p_query_instance_type = instance_type;
    let p_query_region = region;
    let p_query_status = status;
    let p_query_limit = limit;

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

    if let Some(ref param_value) = p_query_next_cursor {
        req_builder = req_builder.query(&[("next_cursor", &serde_json::to_string(param_value)?)]);
    }
    if let Some(ref param_value) = p_query_sort_by {
        req_builder = req_builder.query(&[("sort_by", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_sort_dir {
        req_builder = req_builder.query(&[("sort_dir", &param_value.to_string())]);
    }
    req_builder = req_builder.query(&[("project", &p_query_project.to_string())]);
    if let Some(ref param_value) = p_query_instance_type {
        req_builder = req_builder.query(&[("instance_type", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_region {
        req_builder = req_builder.query(&[("region", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_status {
        req_builder = req_builder.query(&[("status", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_limit {
        req_builder = req_builder.query(&[("limit", &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 token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };

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

/// Update a reservation's pause/resume status and/or volumes
pub async fn update_reservation_v2_reservation_reservation_fid_patch(
    configuration: &configuration::Configuration,
    reservation_fid: &str,
    update_reservation_request: models::UpdateReservationRequest,
) -> Result<models::ReservationModel, Error<UpdateReservationV2ReservationReservationFidPatchError>>
{
    // add a prefix to parameters to efficiently prevent name collisions
    let p_path_reservation_fid = reservation_fid;
    let p_body_update_reservation_request = update_reservation_request;

    let uri_str = format!(
        "{}/v2/reservation/{reservation_fid}",
        configuration.base_path,
        reservation_fid = crate::apis::urlencode(p_path_reservation_fid)
    );
    let mut req_builder = configuration
        .client
        .request(reqwest::Method::PATCH, &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 token) = configuration.bearer_access_token {
        req_builder = req_builder.bearer_auth(token.to_owned());
    };
    req_builder = req_builder.json(&p_body_update_reservation_request);

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