/*
 * MOTIS API
 *
 * This is the MOTIS routing API.  Overview of MOTIS API versions:  MOTIS 0.x - deprecated/discontinued  MOTIS 2.x - current, providing:  * /api/v5/{plan,trip,stoptimes,map/trips} renamed METRO mode to SUBURBAN, AREAL_LIFT to AERIAL_LIFT; since MOTIS 2.5.0 * /api/v4/{plan,trip,stoptimes,map/trips} new displayName property, routeShortName only contains actual route short name from source; since MOTIS 2.2.0 * /api/v3/plan with correct maxTransfers API parameter (transfers actually corresponding to number of changes between transit legs (and not to number of transit legs), i.e. maxTransfers=0 returns direct public transit connections, as expected); since MOTIS 2.0.84  * /api/v2/{plan,trip} returns Google polylines with precision=6; since MOTIS 2.0.60 * /api/v1/{plan,trip} returns Google polylines with precision=7 (not defined for |longitude|>107) * /api/v1/_* all other endpoints  If you use the JS client lib https://www.npmjs.com/package/@motis-project/motis-client, endpoint versions will be taken into account automatically (i.e. the newest one available will be used). 
 *
 * The version of the OpenAPI document: v5
 * Contact: felix@triptix.tech
 * Generated by: https://openapi-generator.tech
 */


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


/// struct for typed errors of method [`initial`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum InitialError {
    Status400(models::Error),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`levels`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum LevelsError {
    Status400(models::Error),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`rentals`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RentalsError {
    Status400(models::Error),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`stops`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum StopsError {
    Status400(models::Error),
    UnknownValue(serde_json::Value),
}

/// struct for typed errors of method [`trips`]
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(untagged)]
pub enum TripsError {
    Status400(models::Error),
    UnknownValue(serde_json::Value),
}


pub async fn initial(configuration: &configuration::Configuration, ) -> Result<models::Initial200Response, Error<InitialError>> {

    let uri_str = format!("{}/api/v1/map/initial", configuration.base_path);
    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());
    }

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

pub async fn levels(configuration: &configuration::Configuration, min: &str, max: &str) -> Result<Vec<f64>, Error<LevelsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_min = min;
    let p_query_max = max;

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

    req_builder = req_builder.query(&[("min", &p_query_min.to_string())]);
    req_builder = req_builder.query(&[("max", &p_query_max.to_string())]);
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }

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

/// If neither the map section (`min` and `max`) nor a provider filter (either `providerGroups` or `providers`) is provided, returns a list of all available rental providers, but no station, vehicle or zone data. Provide the `withProviders=false` parameter to retrieve only provider groups if detailed feed information is not required.  Either the map section (`min` and `max`) or the provider filter (either `providerGroups` or `providers`) must be provided to retrieve station, vehicle and zone data.  If only the map section is provided, all data in the area is returned. If only the provider filter is provided, all data for the given providers is returned. If both parameters are provided, only data for the given providers in the map section is returned. 
pub async fn rentals(configuration: &configuration::Configuration, min: Option<&str>, max: Option<&str>, provider_groups: Option<Vec<String>>, providers: Option<Vec<String>>, with_providers: Option<bool>, with_stations: Option<bool>, with_vehicles: Option<bool>, with_zones: Option<bool>) -> Result<models::Rentals200Response, Error<RentalsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_min = min;
    let p_query_max = max;
    let p_query_provider_groups = provider_groups;
    let p_query_providers = providers;
    let p_query_with_providers = with_providers;
    let p_query_with_stations = with_stations;
    let p_query_with_vehicles = with_vehicles;
    let p_query_with_zones = with_zones;

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

    if let Some(ref param_value) = p_query_min {
        req_builder = req_builder.query(&[("min", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_max {
        req_builder = req_builder.query(&[("max", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_provider_groups {
        req_builder = match "csv" {
            "multi" => req_builder.query(&param_value.into_iter().map(|p| ("providerGroups".to_owned(), p.to_string())).collect::<Vec<(std::string::String, std::string::String)>>()),
            _ => req_builder.query(&[("providerGroups", &param_value.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(",").to_string())]),
        };
    }
    if let Some(ref param_value) = p_query_providers {
        req_builder = match "csv" {
            "multi" => req_builder.query(&param_value.into_iter().map(|p| ("providers".to_owned(), p.to_string())).collect::<Vec<(std::string::String, std::string::String)>>()),
            _ => req_builder.query(&[("providers", &param_value.into_iter().map(|p| p.to_string()).collect::<Vec<String>>().join(",").to_string())]),
        };
    }
    if let Some(ref param_value) = p_query_with_providers {
        req_builder = req_builder.query(&[("withProviders", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_with_stations {
        req_builder = req_builder.query(&[("withStations", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_with_vehicles {
        req_builder = req_builder.query(&[("withVehicles", &param_value.to_string())]);
    }
    if let Some(ref param_value) = p_query_with_zones {
        req_builder = req_builder.query(&[("withZones", &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());
    }

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

pub async fn stops(configuration: &configuration::Configuration, min: &str, max: &str) -> Result<Vec<models::Place>, Error<StopsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_min = min;
    let p_query_max = max;

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

    req_builder = req_builder.query(&[("min", &p_query_min.to_string())]);
    req_builder = req_builder.query(&[("max", &p_query_max.to_string())]);
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }

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

pub async fn trips(configuration: &configuration::Configuration, zoom: f64, min: &str, max: &str, start_time: String, end_time: String) -> Result<Vec<models::TripSegment>, Error<TripsError>> {
    // add a prefix to parameters to efficiently prevent name collisions
    let p_query_zoom = zoom;
    let p_query_min = min;
    let p_query_max = max;
    let p_query_start_time = start_time;
    let p_query_end_time = end_time;

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

    req_builder = req_builder.query(&[("zoom", &p_query_zoom.to_string())]);
    req_builder = req_builder.query(&[("min", &p_query_min.to_string())]);
    req_builder = req_builder.query(&[("max", &p_query_max.to_string())]);
    req_builder = req_builder.query(&[("startTime", &p_query_start_time.to_string())]);
    req_builder = req_builder.query(&[("endTime", &p_query_end_time.to_string())]);
    if let Some(ref user_agent) = configuration.user_agent {
        req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
    }

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

