// Code generated by TofuPilot SDK Generator. DO NOT EDIT.

use crate::client::TofuPilot;
use crate::error::{Error, Result};
use percent_encoding::{utf8_percent_encode, AsciiSet, NON_ALPHANUMERIC};

/// Percent-encode set matching RFC 3986 unreserved characters.
const URI_COMPONENT: &AsciiSet = &NON_ALPHANUMERIC
    .remove(b'-')
    .remove(b'.')
    .remove(b'_')
    .remove(b'~');
use crate::types::*;

/// Client for the Stations API.
#[derive(Debug, Clone)]
pub struct StationsClient<'a> {
    pub(crate) client: &'a TofuPilot,
}

impl<'a> StationsClient<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self { client }
    }

    /// List and filter stations
    ///
    /// Retrieve a paginated list of test stations in your organization. Search by station name and filter by status for station fleet management.
    pub fn list(&self) -> ListBuilder<'a> {
        ListBuilder::new(self.client)
    }

    /// Create station
    ///
    /// Create a new test station in TofuPilot to register production equipment and link it to test procedures.
    pub fn create(&self) -> CreateBuilder<'a> {
        CreateBuilder::new(self.client)
    }

    /// Get current station
    ///
    /// Retrieve detailed information about the currently authenticated station including linked procedures and connection status.
    pub fn get_current(&self) -> GetCurrentBuilder<'a> {
        GetCurrentBuilder::new(self.client)
    }

    /// Get station
    ///
    /// Retrieve detailed station information including linked procedures, connection status, and recent activity.
    pub fn get(&self) -> GetBuilder<'a> {
        GetBuilder::new(self.client)
    }

    /// Remove station
    ///
    /// Remove a test station. Deletes permanently if unused, or archives with preserved historical data if runs exist.
    pub fn remove(&self) -> RemoveBuilder<'a> {
        RemoveBuilder::new(self.client)
    }

    /// Update station
    ///
    /// Update station name and/or image. The station ID is specified in the URL path. To remove an image, pass an empty string for image_id.
    pub fn update(&self) -> UpdateBuilder<'a> {
        UpdateBuilder::new(self.client)
    }

}

// ---------------------------------------------------------------------------
// ListBuilder
// ---------------------------------------------------------------------------

/// Builder for [`StationsClient::list`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.stations().list()
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct ListBuilder<'a> {
    client: &'a TofuPilot,
    limit: Option<i64>,
    cursor: Option<i64>,
    search_query: Option<String>,
    procedure_ids: Option<Vec<String>>,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> ListBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            limit: None,
            cursor: None,
            search_query: None,
            procedure_ids: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `limit` query parameter.
    ///
    /// Number of stations to return per page
    pub fn limit(mut self, value: impl Into<i64>) -> Self {
        self.limit = Some(value.into());
        self
    }

    /// Set the `cursor` query parameter.
    pub fn cursor(mut self, value: impl Into<i64>) -> Self {
        self.cursor = Some(value.into());
        self
    }

    /// Set the `search_query` query parameter.
    pub fn search_query(mut self, value: impl Into<String>) -> Self {
        self.search_query = Some(value.into());
        self
    }

    /// Set the `procedure_ids` query parameter.
    pub fn procedure_ids(mut self, value: impl Into<Vec<String>>) -> Self {
        self.procedure_ids = Some(value.into());
        self
    }

    /// Override the server URL for this request.
    pub fn server_url(mut self, url: impl Into<String>) -> Self {
        self.server_url = Some(url.into());
        self
    }

    /// Override the timeout for this request.
    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    /// Send the request.
    pub async fn send(self) -> Result<StationListResponse> {

        let base_url = self.server_url
            .as_deref()
            .unwrap_or(&self.client.config.base_url);

        let url = format!("{}{}", base_url, "/v2/stations");

        let mut request = self.client.http.request(
            reqwest::Method::GET,
            &url,
        );

        if let Some(timeout) = self.timeout {
            request = request.timeout(timeout);
        }

        if let Some(ref val) = self.limit {
            request = request.query(&[("limit", val.to_string())]);
        }
        if let Some(ref val) = self.cursor {
            request = request.query(&[("cursor", val.to_string())]);
        }
        if let Some(ref val) = self.search_query {
            request = request.query(&[("search_query", val.to_string())]);
        }
        if let Some(ref val) = self.procedure_ids {
            for item in val {
                request = request.query(&[("procedure_ids", item.to_string())]);
            }
        }


        let response = self.client.execute(
            request,
            "station-list",
            base_url,
        ).await?;
        let result: StationListResponse = response.json().await?;
        Ok(result)
    }
}

// ---------------------------------------------------------------------------
// CreateBuilder
// ---------------------------------------------------------------------------

/// Builder for [`StationsClient::create`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.stations().create()
///     .name("value")
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct CreateBuilder<'a> {
    client: &'a TofuPilot,
    name: Option<String>,
    procedure_id: Option<String>,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> CreateBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            name: None,
            procedure_id: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `name` field.
    ///
    /// Name of the station
    pub fn name(mut self, value: impl Into<String>) -> Self {
        self.name = Some(value.into());
        self
    }

    /// Set the `procedure_id` field.
    ///
    /// Optional procedure ID to link the station to
    pub fn procedure_id(mut self, value: impl Into<String>) -> Self {
        self.procedure_id = Some(value.into());
        self
    }

    /// Set the full request body (alternative to setting individual fields).
    pub fn body(mut self, body: StationCreateRequest) -> Self {
        self.name = Some(body.name);
        if body.procedure_id.is_some() {
            self.procedure_id = body.procedure_id;
        }
        self
    }

    /// Override the server URL for this request.
    pub fn server_url(mut self, url: impl Into<String>) -> Self {
        self.server_url = Some(url.into());
        self
    }

    /// Override the timeout for this request.
    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    /// Send the request.
    pub async fn send(self) -> Result<StationCreateResponse> {

        let base_url = self.server_url
            .as_deref()
            .unwrap_or(&self.client.config.base_url);

        let url = format!("{}{}", base_url, "/v2/stations");

        let mut request = self.client.http.request(
            reqwest::Method::POST,
            &url,
        );

        if let Some(timeout) = self.timeout {
            request = request.timeout(timeout);
        }


        let body = StationCreateRequest {
            name: self.name
                .ok_or_else(|| Error::Validation(
                    "missing required field: name".to_string(),
                ))?,
            procedure_id: self.procedure_id,
        };
        request = request.json(&body);

        let response = self.client.execute(
            request,
            "station-create",
            base_url,
        ).await?;
        let result: StationCreateResponse = response.json().await?;
        Ok(result)
    }
}

// ---------------------------------------------------------------------------
// GetCurrentBuilder
// ---------------------------------------------------------------------------

/// Builder for [`StationsClient::get_current`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.stations().get_current()
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct GetCurrentBuilder<'a> {
    client: &'a TofuPilot,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> GetCurrentBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            server_url: None,
            timeout: None,
        }
    }

    /// Override the server URL for this request.
    pub fn server_url(mut self, url: impl Into<String>) -> Self {
        self.server_url = Some(url.into());
        self
    }

    /// Override the timeout for this request.
    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    /// Send the request.
    pub async fn send(self) -> Result<StationGetCurrentResponse> {

        let base_url = self.server_url
            .as_deref()
            .unwrap_or(&self.client.config.base_url);

        let url = format!("{}{}", base_url, "/v2/stations/current");

        let mut request = self.client.http.request(
            reqwest::Method::GET,
            &url,
        );

        if let Some(timeout) = self.timeout {
            request = request.timeout(timeout);
        }



        let response = self.client.execute(
            request,
            "station-getCurrent",
            base_url,
        ).await?;
        let result: StationGetCurrentResponse = response.json().await?;
        Ok(result)
    }
}

// ---------------------------------------------------------------------------
// GetBuilder
// ---------------------------------------------------------------------------

/// Builder for [`StationsClient::get`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.stations().get()
///     .id("value")
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct GetBuilder<'a> {
    client: &'a TofuPilot,
    id: Option<String>,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> GetBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            id: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `id` path parameter.
    ///
    /// Unique identifier of the station to retrieve
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Override the server URL for this request.
    pub fn server_url(mut self, url: impl Into<String>) -> Self {
        self.server_url = Some(url.into());
        self
    }

    /// Override the timeout for this request.
    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    /// Send the request.
    pub async fn send(self) -> Result<StationGetResponse> {
        let id = self.id
            .ok_or_else(|| Error::Validation(
                "missing required path parameter: id".to_string(),
            ))?;
        let id_encoded = utf8_percent_encode(&id, URI_COMPONENT).to_string();

        let base_url = self.server_url
            .as_deref()
            .unwrap_or(&self.client.config.base_url);

        let url = format!(
            "{}/v2/stations/{id}",
            base_url,
            id = id_encoded,
        );

        let mut request = self.client.http.request(
            reqwest::Method::GET,
            &url,
        );

        if let Some(timeout) = self.timeout {
            request = request.timeout(timeout);
        }



        let response = self.client.execute(
            request,
            "station-get",
            base_url,
        ).await?;
        let result: StationGetResponse = response.json().await?;
        Ok(result)
    }
}

// ---------------------------------------------------------------------------
// RemoveBuilder
// ---------------------------------------------------------------------------

/// Builder for [`StationsClient::remove`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.stations().remove()
///     .id("value")
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct RemoveBuilder<'a> {
    client: &'a TofuPilot,
    id: Option<String>,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> RemoveBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            id: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `id` path parameter.
    ///
    /// Unique identifier of the station to remove
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Override the server URL for this request.
    pub fn server_url(mut self, url: impl Into<String>) -> Self {
        self.server_url = Some(url.into());
        self
    }

    /// Override the timeout for this request.
    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    /// Send the request.
    pub async fn send(self) -> Result<StationRemoveResponse> {
        let id = self.id
            .ok_or_else(|| Error::Validation(
                "missing required path parameter: id".to_string(),
            ))?;
        let id_encoded = utf8_percent_encode(&id, URI_COMPONENT).to_string();

        let base_url = self.server_url
            .as_deref()
            .unwrap_or(&self.client.config.base_url);

        let url = format!(
            "{}/v2/stations/{id}",
            base_url,
            id = id_encoded,
        );

        let mut request = self.client.http.request(
            reqwest::Method::DELETE,
            &url,
        );

        if let Some(timeout) = self.timeout {
            request = request.timeout(timeout);
        }



        let response = self.client.execute(
            request,
            "station-remove",
            base_url,
        ).await?;
        let result: StationRemoveResponse = response.json().await?;
        Ok(result)
    }
}

// ---------------------------------------------------------------------------
// UpdateBuilder
// ---------------------------------------------------------------------------

/// Builder for [`StationsClient::update`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.stations().update()
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct UpdateBuilder<'a> {
    client: &'a TofuPilot,
    id: Option<String>,
    name: Option<String>,
    image_id: Option<String>,
    team_id: Option<NullableField<String>>,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> UpdateBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            id: None,
            name: None,
            image_id: None,
            team_id: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `id` path parameter.
    ///
    /// Unique identifier of the station to update
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `name` field.
    ///
    /// New name for the station
    pub fn name(mut self, value: impl Into<String>) -> Self {
        self.name = Some(value.into());
        self
    }

    /// Set the `image_id` field.
    ///
    /// Upload ID for the station image, or empty string to remove image
    pub fn image_id(mut self, value: impl Into<String>) -> Self {
        self.image_id = Some(value.into());
        self
    }

    /// Set the `team_id` field.
    ///
    /// Team ID to assign this station to, or null to unassign
    pub fn team_id(mut self, value: impl Into<String>) -> Self {
        self.team_id = Some(NullableField::Value(value.into()));
        self
    }

    /// Explicitly set `team_id` to null.
    pub fn team_id_null(mut self) -> Self {
        self.team_id = Some(NullableField::Null);
        self
    }

    /// Set the full request body (alternative to setting individual fields).
    pub fn body(mut self, body: StationUpdateRequestBody) -> Self {
        if body.name.is_some() {
            self.name = body.name;
        }
        if body.image_id.is_some() {
            self.image_id = body.image_id;
        }
        self.team_id = Some(body.team_id);
        self
    }

    /// Override the server URL for this request.
    pub fn server_url(mut self, url: impl Into<String>) -> Self {
        self.server_url = Some(url.into());
        self
    }

    /// Override the timeout for this request.
    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = Some(timeout);
        self
    }

    /// Send the request.
    pub async fn send(self) -> Result<StationUpdateResponse> {
        let id = self.id
            .ok_or_else(|| Error::Validation(
                "missing required path parameter: id".to_string(),
            ))?;
        let id_encoded = utf8_percent_encode(&id, URI_COMPONENT).to_string();

        let base_url = self.server_url
            .as_deref()
            .unwrap_or(&self.client.config.base_url);

        let url = format!(
            "{}/v2/stations/{id}",
            base_url,
            id = id_encoded,
        );

        let mut request = self.client.http.request(
            reqwest::Method::PATCH,
            &url,
        );

        if let Some(timeout) = self.timeout {
            request = request.timeout(timeout);
        }


        let body = StationUpdateRequestBody {
            name: self.name,
            image_id: self.image_id,
            team_id: self.team_id.unwrap_or(NullableField::Absent),
        };
        request = request.json(&body);

        let response = self.client.execute(
            request,
            "station-update",
            base_url,
        ).await?;
        let result: StationUpdateResponse = response.json().await?;
        Ok(result)
    }
}

