// 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 Batches API.
#[derive(Debug, Clone)]
pub struct BatchesClient<'a> {
    pub(crate) client: &'a TofuPilot,
}

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

    /// Get batch
    ///
    /// Retrieve a single batch by its number, including all associated units, serial numbers, and part revisions.
    pub fn get(&self) -> GetBuilder<'a> {
        GetBuilder::new(self.client)
    }

    /// Delete batch
    ///
    /// Permanently delete a batch by number. Units associated with the batch will be disassociated but not deleted. No nested elements are removed.
    pub fn delete(&self) -> DeleteBuilder<'a> {
        DeleteBuilder::new(self.client)
    }

    /// Update batch
    ///
    /// Update a batch number. The current batch number is specified in the URL path with case-insensitive matching.
    pub fn update(&self) -> UpdateBuilder<'a> {
        UpdateBuilder::new(self.client)
    }

    /// List and filter batches
    ///
    /// Retrieve batches with associated units, serial numbers, and part revisions using cursor-based pagination.
    pub fn list(&self) -> ListBuilder<'a> {
        ListBuilder::new(self.client)
    }

    /// Create batch
    ///
    /// Create a new batch without any units attached. Batch numbers are matched case-insensitively (e.g., "BATCH-001" and "batch-001" are considered the same).
    pub fn create(&self) -> CreateBuilder<'a> {
        CreateBuilder::new(self.client)
    }

}

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

/// Builder for [`BatchesClient::get`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.batches().get()
///     .number("value")
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct GetBuilder<'a> {
    client: &'a TofuPilot,
    number: 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,
            number: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `number` path parameter.
    ///
    /// Number of the batch to retrieve.
    pub fn number(mut self, value: impl Into<String>) -> Self {
        self.number = 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<BatchGetResponse> {
        let number = self.number
            .ok_or_else(|| Error::Validation(
                "missing required path parameter: number".to_string(),
            ))?;
        let number_encoded = utf8_percent_encode(&number, URI_COMPONENT).to_string();

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

        let url = format!(
            "{}/v2/batches/{number}",
            base_url,
            number = number_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,
            "batch-get",
            base_url,
        ).await?;
        let result: BatchGetResponse = response.json().await?;
        Ok(result)
    }
}

// ---------------------------------------------------------------------------
// DeleteBuilder
// ---------------------------------------------------------------------------

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

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

    /// Set the `number` path parameter.
    pub fn number(mut self, value: impl Into<String>) -> Self {
        self.number = 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<BatchDeleteResponse> {
        let number = self.number
            .ok_or_else(|| Error::Validation(
                "missing required path parameter: number".to_string(),
            ))?;
        let number_encoded = utf8_percent_encode(&number, URI_COMPONENT).to_string();

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

        let url = format!(
            "{}/v2/batches/{number}",
            base_url,
            number = number_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,
            "batch-delete",
            base_url,
        ).await?;
        let result: BatchDeleteResponse = response.json().await?;
        Ok(result)
    }
}

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

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

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

    /// Set the `number` path parameter.
    ///
    /// Current batch number to update.
    pub fn number(mut self, value: impl Into<String>) -> Self {
        self.number = Some(value.into());
        self
    }

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

    /// Set the full request body (alternative to setting individual fields).
    pub fn body(mut self, body: BatchUpdateRequestBody) -> Self {
        self.new_number = Some(body.new_number);
        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<BatchUpdateResponse> {
        let number = self.number
            .ok_or_else(|| Error::Validation(
                "missing required path parameter: number".to_string(),
            ))?;
        let number_encoded = utf8_percent_encode(&number, URI_COMPONENT).to_string();

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

        let url = format!(
            "{}/v2/batches/{number}",
            base_url,
            number = number_encoded,
        );

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

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


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

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

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

/// Builder for [`BatchesClient::list`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.batches().list()
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct ListBuilder<'a> {
    client: &'a TofuPilot,
    ids: Option<Vec<String>>,
    numbers: Option<Vec<String>>,
    created_after: Option<chrono::DateTime<chrono::Utc>>,
    created_before: Option<chrono::DateTime<chrono::Utc>>,
    limit: Option<i64>,
    cursor: Option<i64>,
    search_query: Option<String>,
    part_numbers: Option<Vec<String>>,
    revision_numbers: Option<Vec<String>>,
    sort_by: Option<BatchListSortBy>,
    sort_order: Option<ListSortOrder>,
    server_url: Option<String>,
    timeout: Option<std::time::Duration>,
}

impl<'a> ListBuilder<'a> {
    pub(crate) fn new(client: &'a TofuPilot) -> Self {
        Self {
            client,
            ids: None,
            numbers: None,
            created_after: None,
            created_before: None,
            limit: None,
            cursor: None,
            search_query: None,
            part_numbers: None,
            revision_numbers: None,
            sort_by: None,
            sort_order: None,
            server_url: None,
            timeout: None,
        }
    }

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

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

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

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

    /// Set the `limit` query parameter.
    ///
    /// Maximum number of batches to return. Use `cursor` to fetch additional results.
    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 `part_numbers` query parameter.
    pub fn part_numbers(mut self, value: impl Into<Vec<String>>) -> Self {
        self.part_numbers = Some(value.into());
        self
    }

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

    /// Set the `sort_by` query parameter.
    ///
    /// Field to sort results by.
    pub fn sort_by(mut self, value: impl Into<BatchListSortBy>) -> Self {
        self.sort_by = Some(value.into());
        self
    }

    /// Set the `sort_order` query parameter.
    ///
    /// Sort order direction.
    pub fn sort_order(mut self, value: impl Into<ListSortOrder>) -> Self {
        self.sort_order = 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<BatchListResponse> {

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

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

        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.ids {
            for item in val {
                request = request.query(&[("ids", item.to_string())]);
            }
        }
        if let Some(ref val) = self.numbers {
            for item in val {
                request = request.query(&[("numbers", item.to_string())]);
            }
        }
        if let Some(ref val) = self.created_after {
            request = request.query(&[("created_after", val.to_rfc3339_opts(chrono::SecondsFormat::Millis, true))]);
        }
        if let Some(ref val) = self.created_before {
            request = request.query(&[("created_before", val.to_rfc3339_opts(chrono::SecondsFormat::Millis, true))]);
        }
        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.part_numbers {
            for item in val {
                request = request.query(&[("part_numbers", item.to_string())]);
            }
        }
        if let Some(ref val) = self.revision_numbers {
            for item in val {
                request = request.query(&[("revision_numbers", item.to_string())]);
            }
        }
        if let Some(ref val) = self.sort_by {
            request = request.query(&[("sort_by", val.to_string())]);
        }
        if let Some(ref val) = self.sort_order {
            request = request.query(&[("sort_order", val.to_string())]);
        }


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

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

/// Builder for [`BatchesClient::create`].
///
/// # Example
///
/// ```no_run
/// use tofupilot::TofuPilot;
///
/// # #[tokio::main]
/// # async fn main() -> tofupilot::Result<()> {
/// let client = TofuPilot::new("your-api-key");
/// let response = client.batches().create()
///     .number("value")
///     .send()
///     .await?;
/// # Ok(())
/// # }
/// ```
#[derive(Debug)]
pub struct CreateBuilder<'a> {
    client: &'a TofuPilot,
    number: 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,
            number: None,
            server_url: None,
            timeout: None,
        }
    }

    /// Set the `number` field.
    ///
    /// The batch number identifier
    pub fn number(mut self, value: impl Into<String>) -> Self {
        self.number = Some(value.into());
        self
    }

    /// Set the full request body (alternative to setting individual fields).
    pub fn body(mut self, body: BatchCreateRequest) -> Self {
        self.number = Some(body.number);
        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<BatchCreateResponse> {

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

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

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

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


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

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

