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

use serde::{Deserialize, Serialize};

/// Represents a field that distinguishes between "not sent" and "explicitly null".
///
/// - `NullableField::Absent` — field is omitted from the request
/// - `NullableField::Null` — field is explicitly set to `null`
/// - `NullableField::Value(T)` — field has a value
#[derive(Debug, Clone, PartialEq, Default)]
pub enum NullableField<T> {
    /// Field is not included in the serialized output.
    #[default]
    Absent,
    /// Field is explicitly set to null.
    Null,
    /// Field has a value.
    Value(T),
}

impl<T: Serialize> Serialize for NullableField<T> {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            // Absent fields should be skipped by #[serde(skip_serializing_if = "nullable_is_absent")].
            // If we reach here, serialize as none as a safe fallback.
            NullableField::Absent => serializer.serialize_none(),
            NullableField::Null => serializer.serialize_none(),
            NullableField::Value(v) => v.serialize(serializer),
        }
    }
}

impl<'de, T: Deserialize<'de>> Deserialize<'de> for NullableField<T> {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        Option::<T>::deserialize(deserializer).map(|opt| match opt {
            Some(v) => NullableField::Value(v),
            None => NullableField::Null,
        })
    }
}

impl<T> NullableField<T> {
    /// Create a `Value` variant.
    pub fn value(v: T) -> Self {
        NullableField::Value(v)
    }

    /// Create a `Null` variant.
    pub fn null() -> Self {
        NullableField::Null
    }
}

impl<T> From<T> for NullableField<T> {
    fn from(v: T) -> Self {
        NullableField::Value(v)
    }
}

/// Returns true if the NullableField is Absent (for skip_serializing_if).
pub fn nullable_is_absent<T>(field: &NullableField<T>) -> bool {
    matches!(field, NullableField::Absent)
}

/// Field to sort results by.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum RunListSortBy {
    #[serde(rename = "started_at")]
    StartedAt,
    #[serde(rename = "created_at")]
    CreatedAt,
    #[serde(rename = "duration")]
    Duration,
    #[serde(rename = "outcome")]
    Outcome,
    #[serde(rename = "serial_number")]
    SerialNumber,
    #[serde(rename = "part_number")]
    PartNumber,
    #[serde(rename = "revision_number")]
    RevisionNumber,
}

impl std::fmt::Display for RunListSortBy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::StartedAt => write!(f, "started_at"),
            Self::CreatedAt => write!(f, "created_at"),
            Self::Duration => write!(f, "duration"),
            Self::Outcome => write!(f, "outcome"),
            Self::SerialNumber => write!(f, "serial_number"),
            Self::PartNumber => write!(f, "part_number"),
            Self::RevisionNumber => write!(f, "revision_number"),
        }
    }
}

/// Field to sort results by. last_run_at sorts by most recent test run date. last_run_procedure sorts by procedure name of the last run.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum UnitListSortBy {
    #[serde(rename = "serial_number")]
    SerialNumber,
    #[serde(rename = "created_at")]
    CreatedAt,
    #[serde(rename = "last_run_at")]
    LastRunAt,
    #[serde(rename = "part_number")]
    PartNumber,
    #[serde(rename = "last_run_procedure")]
    LastRunProcedure,
}

impl std::fmt::Display for UnitListSortBy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::SerialNumber => write!(f, "serial_number"),
            Self::CreatedAt => write!(f, "created_at"),
            Self::LastRunAt => write!(f, "last_run_at"),
            Self::PartNumber => write!(f, "part_number"),
            Self::LastRunProcedure => write!(f, "last_run_procedure"),
        }
    }
}

/// Field to sort results by.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PartListSortBy {
    #[serde(rename = "name")]
    Name,
    #[serde(rename = "number")]
    Number,
    #[serde(rename = "created_at")]
    CreatedAt,
}

impl std::fmt::Display for PartListSortBy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Name => write!(f, "name"),
            Self::Number => write!(f, "number"),
            Self::CreatedAt => write!(f, "created_at"),
        }
    }
}

/// Field to sort results by.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum BatchListSortBy {
    #[serde(rename = "number")]
    Number,
    #[serde(rename = "created_at")]
    CreatedAt,
}

impl std::fmt::Display for BatchListSortBy {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Number => write!(f, "number"),
            Self::CreatedAt => write!(f, "created_at"),
        }
    }
}

/// Git provider
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Provider {
    #[serde(rename = "github")]
    Github,
    #[serde(rename = "gitlab")]
    Gitlab,
}

impl std::fmt::Display for Provider {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Github => write!(f, "github"),
            Self::Gitlab => write!(f, "gitlab"),
        }
    }
}

/// Overall test result. Use PASS when test succeeds, FAIL when test fails but script execution completed successfully, ERROR when script execution fails, TIMEOUT when test exceeds time limit, ABORTED for manual script interruption.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Outcome {
    #[serde(rename = "PASS")]
    Pass,
    #[serde(rename = "FAIL")]
    Fail,
    #[serde(rename = "ERROR")]
    Error,
    #[serde(rename = "TIMEOUT")]
    Timeout,
    #[serde(rename = "ABORTED")]
    Aborted,
}

impl std::fmt::Display for Outcome {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Pass => write!(f, "PASS"),
            Self::Fail => write!(f, "FAIL"),
            Self::Error => write!(f, "ERROR"),
            Self::Timeout => write!(f, "TIMEOUT"),
            Self::Aborted => write!(f, "ABORTED"),
        }
    }
}

/// Overall result of the phase execution. Use PASS when phase succeeds, FAIL when phase fails but execution completed successfully, ERROR when phase execution fails, SKIP when phase was not executed.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum PhasesOutcome {
    #[serde(rename = "PASS")]
    Pass,
    #[serde(rename = "FAIL")]
    Fail,
    #[serde(rename = "SKIP")]
    Skip,
    #[serde(rename = "ERROR")]
    Error,
}

impl std::fmt::Display for PhasesOutcome {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Pass => write!(f, "PASS"),
            Self::Fail => write!(f, "FAIL"),
            Self::Skip => write!(f, "SKIP"),
            Self::Error => write!(f, "ERROR"),
        }
    }
}

/// Result of the measurement validation. Use PASS when measurement meets all criteria, FAIL when measurement is outside acceptable limits or validation fails, UNSET when no validation was performed.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ValidatorsOutcome {
    #[serde(rename = "PASS")]
    Pass,
    #[serde(rename = "FAIL")]
    Fail,
    #[serde(rename = "UNSET")]
    Unset,
}

impl std::fmt::Display for ValidatorsOutcome {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Pass => write!(f, "PASS"),
            Self::Fail => write!(f, "FAIL"),
            Self::Unset => write!(f, "UNSET"),
        }
    }
}

/// Severity level of the log message following standard system logging levels. Use DEBUG for detailed diagnostic information, INFO for general execution information, WARNING for unexpected events or potential issues, ERROR for serious problems that prevented function execution, CRITICAL for severe errors that may cause program termination.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Level {
    #[serde(rename = "DEBUG")]
    Debug,
    #[serde(rename = "INFO")]
    Info,
    #[serde(rename = "WARNING")]
    Warning,
    #[serde(rename = "ERROR")]
    Error,
    #[serde(rename = "CRITICAL")]
    Critical,
}

impl std::fmt::Display for Level {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Debug => write!(f, "DEBUG"),
            Self::Info => write!(f, "INFO"),
            Self::Warning => write!(f, "WARNING"),
            Self::Error => write!(f, "ERROR"),
            Self::Critical => write!(f, "CRITICAL"),
        }
    }
}

/// Sort order direction.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum ListSortOrder {
    #[serde(rename = "asc")]
    Asc,
    #[serde(rename = "desc")]
    Desc,
}

impl std::fmt::Display for ListSortOrder {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Asc => write!(f, "asc"),
            Self::Desc => write!(f, "desc"),
        }
    }
}

/// Expected value for comparison. Type depends on operator.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateExpectedValue {
    Boolean(bool),
    Number(f64),
    Str(String),
    NumberArray(Vec<f64>),
    StringArray(Vec<String>),
}

/// Expected value for comparison. Type depends on operator.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateAggregationsExpectedValue {
    Boolean(bool),
    Number(f64),
    Str(String),
    NumberArray(Vec<f64>),
    StringArray(Vec<String>),
}

/// Computed aggregation value.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateValue {
    Number(f64),
    Str(String),
    Boolean(bool),
}

/// Expected value for comparison. Type depends on operator.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateYAxisExpectedValue {
    Boolean(bool),
    Number(f64),
    Str(String),
    NumberArray(Vec<f64>),
    StringArray(Vec<String>),
}

/// Expected value for comparison. Type depends on operator.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateYAxisAggregationsExpectedValue {
    Boolean(bool),
    Number(f64),
    Str(String),
    NumberArray(Vec<f64>),
    StringArray(Vec<String>),
}

/// Computed aggregation value.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateYAxisValue {
    Number(f64),
    Str(String),
    Boolean(bool),
}

/// Expected value for comparison. Type depends on operator.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateMeasurementsExpectedValue {
    Boolean(bool),
    Number(f64),
    Str(String),
    NumberArray(Vec<f64>),
    StringArray(Vec<String>),
}

/// Expected value for comparison. Type depends on operator.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateMeasurementsAggregationsExpectedValue {
    Boolean(bool),
    Number(f64),
    Str(String),
    NumberArray(Vec<f64>),
    StringArray(Vec<String>),
}

/// Computed aggregation value.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateMeasurementsValue {
    Number(f64),
    Str(String),
    Boolean(bool),
}

/// [LEGACY for multi-dim] Units of measurement. For structured multi-dimensional, use units within x_axis/y_axis instead.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunCreateUnits {
    Str(String),
    StringArray(Vec<String>),
}

/// Computed aggregation value. Type depends on aggregation type.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunGetValue {
    Number(f64),
    Str(String),
    Boolean(bool),
}

/// Computed aggregation value. Type depends on aggregation type.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum RunGetDataSeriesValue {
    Number(f64),
    Str(String),
    Boolean(bool),
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureCreateRequest {
    /// Name of the procedure. Must be unique within the organization.
    pub name: String,
}

/// Procedure created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureCreateResponse {
    /// Unique identifier for the created procedure.
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct ProcedureListRequest {
    /// Maximum number of procedures to return per page.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cursor: Option<f64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_before: Option<chrono::DateTime<chrono::Utc>>,
}

impl ProcedureListRequest {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureListRequestBuilder {
        ProcedureListRequestBuilder::default()
    }
}

/// Builder for [`ProcedureListRequest`].
#[derive(Debug, Default)]
pub struct ProcedureListRequestBuilder {
    limit: Option<i64>,
    cursor: Option<f64>,
    search_query: Option<String>,
    created_after: Option<chrono::DateTime<chrono::Utc>>,
    created_before: Option<chrono::DateTime<chrono::Utc>>,
}

impl ProcedureListRequestBuilder {
    /// Set the `limit` field.
    ///
    /// Maximum number of procedures to return per page.
    pub fn limit(mut self, value: impl Into<i64>) -> Self {
        self.limit = Some(value.into());
        self
    }

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

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

    /// Set the `created_after` field.
    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` field.
    pub fn created_before(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_before = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureListRequest, String> {
        Ok(ProcedureListRequest {
            limit: self.limit,
            cursor: self.cursor,
            search_query: self.search_query,
            created_after: self.created_after,
            created_before: self.created_before,
        })
    }
}

/// User who created the procedure.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureListCreatedByUser {
    /// Unique identifier for the user who created the procedure.
    pub id: String,
    /// Name of the user who created the procedure.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// Email of the user who created the procedure.
    pub email: String,
}

impl ProcedureListCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureListCreatedByUserBuilder {
        ProcedureListCreatedByUserBuilder::default()
    }
}

/// Builder for [`ProcedureListCreatedByUser`].
#[derive(Debug, Default)]
pub struct ProcedureListCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl ProcedureListCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the user who created the procedure.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `email` field.
    ///
    /// Email of the user who created the procedure.
    pub fn email(mut self, value: impl Into<String>) -> Self {
        self.email = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureListCreatedByUser, String> {
        Ok(ProcedureListCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
            email: self.email
                .ok_or_else(|| "missing required field: email".to_string())?,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureListLinkedRepository {
    /// Unique identifier for the linked repository.
    pub id: String,
    /// Name of the repository.
    pub name: String,
    /// Full name of the repository (owner/repo).
    #[serde(rename = "fullName")]
    pub full_name: String,
    pub provider: Provider,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureListData {
    /// Unique identifier for the procedure.
    pub id: String,
    /// Name of the procedure.
    pub name: String,
    /// ISO 8601 timestamp when the procedure was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created the procedure.
    pub created_by_user: ProcedureListCreatedByUser,
    /// Linked repository for this procedure.
    #[serde(rename = "linkedRepository")]
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub linked_repository: Option<ProcedureListLinkedRepository>,
}

impl ProcedureListData {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureListDataBuilder {
        ProcedureListDataBuilder::default()
    }
}

/// Builder for [`ProcedureListData`].
#[derive(Debug, Default)]
pub struct ProcedureListDataBuilder {
    id: Option<String>,
    name: Option<String>,
    created_at: Option<chrono::DateTime<chrono::Utc>>,
    created_by_user: Option<ProcedureListCreatedByUser>,
    linked_repository: Option<ProcedureListLinkedRepository>,
}

impl ProcedureListDataBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the procedure.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `created_at` field.
    ///
    /// ISO 8601 timestamp when the procedure was created.
    pub fn created_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_at = Some(value.into());
        self
    }

    /// Set the `created_by_user` field.
    ///
    /// User who created the procedure.
    pub fn created_by_user(mut self, value: impl Into<ProcedureListCreatedByUser>) -> Self {
        self.created_by_user = Some(value.into());
        self
    }

    /// Set the `linkedRepository` field.
    ///
    /// Linked repository for this procedure.
    pub fn linked_repository(mut self, value: impl Into<ProcedureListLinkedRepository>) -> Self {
        self.linked_repository = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureListData, String> {
        Ok(ProcedureListData {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            created_at: self.created_at
                .ok_or_else(|| "missing required field: created_at".to_string())?,
            created_by_user: self.created_by_user
                .ok_or_else(|| "missing required field: created_by_user".to_string())?,
            linked_repository: self.linked_repository,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureListMeta {
    /// Whether there are more results available for pagination.
    pub has_more: bool,
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<i64>,
}

impl ProcedureListMeta {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureListMetaBuilder {
        ProcedureListMetaBuilder::default()
    }
}

/// Builder for [`ProcedureListMeta`].
#[derive(Debug, Default)]
pub struct ProcedureListMetaBuilder {
    has_more: Option<bool>,
    next_cursor: Option<i64>,
}

impl ProcedureListMetaBuilder {
    /// Set the `has_more` field.
    ///
    /// Whether there are more results available for pagination.
    pub fn has_more(mut self, value: impl Into<bool>) -> Self {
        self.has_more = Some(value.into());
        self
    }

    /// Set the `next_cursor` field.
    ///
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    pub fn next_cursor(mut self, value: impl Into<i64>) -> Self {
        self.next_cursor = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureListMeta, String> {
        Ok(ProcedureListMeta {
            has_more: self.has_more
                .ok_or_else(|| "missing required field: has_more".to_string())?,
            next_cursor: self.next_cursor,
        })
    }
}

/// Procedures retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureListResponse {
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<ProcedureListData>,
    pub meta: ProcedureListMeta,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetRequest {
    /// Unique identifier of the procedure to retrieve.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

impl ProcedureGetCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureGetCreatedByUserBuilder {
        ProcedureGetCreatedByUserBuilder::default()
    }
}

/// Builder for [`ProcedureGetCreatedByUser`].
#[derive(Debug, Default)]
pub struct ProcedureGetCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl ProcedureGetCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureGetCreatedByUser, String> {
        Ok(ProcedureGetCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
            email: self.email,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetUnit {
    /// Unit serial number.
    pub serial_number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetRecentRuns {
    /// Run ID.
    pub id: String,
    /// ISO 8601 timestamp when the run started.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// Run outcome.
    pub outcome: Outcome,
    /// Unit information.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub unit: Option<ProcedureGetUnit>,
}

impl ProcedureGetRecentRuns {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureGetRecentRunsBuilder {
        ProcedureGetRecentRunsBuilder::default()
    }
}

/// Builder for [`ProcedureGetRecentRuns`].
#[derive(Debug, Default)]
pub struct ProcedureGetRecentRunsBuilder {
    id: Option<String>,
    started_at: Option<chrono::DateTime<chrono::Utc>>,
    outcome: Option<Outcome>,
    unit: Option<ProcedureGetUnit>,
}

impl ProcedureGetRecentRunsBuilder {
    /// Set the `id` field.
    ///
    /// Run ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `started_at` field.
    ///
    /// ISO 8601 timestamp when the run started.
    pub fn started_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.started_at = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Run outcome.
    pub fn outcome(mut self, value: impl Into<Outcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `unit` field.
    ///
    /// Unit information.
    pub fn unit(mut self, value: impl Into<ProcedureGetUnit>) -> Self {
        self.unit = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureGetRecentRuns, String> {
        Ok(ProcedureGetRecentRuns {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            started_at: self.started_at
                .ok_or_else(|| "missing required field: started_at".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            unit: self.unit,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetStations {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

/// Procedure retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetResponse {
    /// Unique identifier for the procedure.
    pub id: String,
    /// Procedure name.
    pub name: String,
    /// ISO 8601 timestamp when the procedure was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this procedure.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_user: Option<ProcedureGetCreatedByUser>,
    /// Total number of runs for this procedure.
    pub runs_count: f64,
    /// List of recent runs for this procedure.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub recent_runs: Vec<ProcedureGetRecentRuns>,
    /// Stations linked to this procedure.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub stations: Vec<ProcedureGetStations>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureDeleteRequest {
    /// Unique identifier of the procedure to delete.
    pub id: String,
}

/// Procedure deleted successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureDeleteResponse {
    /// Unique identifier of the deleted procedure.
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct ProcedureUpdateRequestBody {
    /// New name for the procedure.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// Branch treated as production. Pushes to this branch deploy as production; every other branch deploys as preview. Null = no branch promoted to production.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub production_branch: NullableField<String>,
    /// Master switch for auto-pushing builds to linked stations. Build artifacts are always recorded; this only gates the station fan-out.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub auto_push_enabled: Option<bool>,
    /// Branches matching any of these patterns (exact name or minimatch glob, e.g. "renovate/*") skip preview deployments. Empty array = no exclusions.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub excluded_branch_patterns: Option<Vec<String>>,
    /// Path within the linked repo to the directory holding this procedure's `pyproject.toml` (and `procedure.yaml` for framework procedures). Empty/null = repo root.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub root_directory: NullableField<String>,
}

impl ProcedureUpdateRequestBody {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureUpdateRequestBodyBuilder {
        ProcedureUpdateRequestBodyBuilder::default()
    }
}

/// Builder for [`ProcedureUpdateRequestBody`].
#[derive(Debug, Default)]
pub struct ProcedureUpdateRequestBodyBuilder {
    name: Option<String>,
    production_branch: NullableField<String>,
    auto_push_enabled: Option<bool>,
    excluded_branch_patterns: Option<Vec<String>>,
    root_directory: NullableField<String>,
}

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

    /// Set the `production_branch` field.
    ///
    /// Branch treated as production. Pushes to this branch deploy as production; every other branch deploys as preview. Null = no branch promoted to production.
    pub fn production_branch(mut self, value: impl Into<String>) -> Self {
        self.production_branch = NullableField::Value(value.into());
        self
    }

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

    /// Set the `auto_push_enabled` field.
    ///
    /// Master switch for auto-pushing builds to linked stations. Build artifacts are always recorded; this only gates the station fan-out.
    pub fn auto_push_enabled(mut self, value: impl Into<bool>) -> Self {
        self.auto_push_enabled = Some(value.into());
        self
    }

    /// Set the `excluded_branch_patterns` field.
    ///
    /// Branches matching any of these patterns (exact name or minimatch glob, e.g. "renovate/*") skip preview deployments. Empty array = no exclusions.
    pub fn excluded_branch_patterns(mut self, value: impl Into<Vec<String>>) -> Self {
        self.excluded_branch_patterns = Some(value.into());
        self
    }

    /// Set the `root_directory` field.
    ///
    /// Path within the linked repo to the directory holding this procedure's `pyproject.toml` (and `procedure.yaml` for framework procedures). Empty/null = repo root.
    pub fn root_directory(mut self, value: impl Into<String>) -> Self {
        self.root_directory = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureUpdateRequestBody, String> {
        Ok(ProcedureUpdateRequestBody {
            name: self.name,
            production_branch: self.production_branch,
            auto_push_enabled: self.auto_push_enabled,
            excluded_branch_patterns: self.excluded_branch_patterns,
            root_directory: self.root_directory,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureUpdateRequest {
    /// Unique identifier of the procedure to update.
    pub id: String,
    pub request_body: ProcedureUpdateRequestBody,
}

/// Procedure updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureUpdateResponse {
    /// Unique identifier of the updated procedure.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetVersionRequest {
    /// ID of the procedure that owns this version.
    pub procedure_id: String,
    /// Version tag to retrieve.
    pub tag: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetVersionCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl ProcedureGetVersionCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> ProcedureGetVersionCreatedByUserBuilder {
        ProcedureGetVersionCreatedByUserBuilder::default()
    }
}

/// Builder for [`ProcedureGetVersionCreatedByUser`].
#[derive(Debug, Default)]
pub struct ProcedureGetVersionCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl ProcedureGetVersionCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<ProcedureGetVersionCreatedByUser, String> {
        Ok(ProcedureGetVersionCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetVersionCreatedByStation {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

/// Procedure this version belongs to.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetVersionProcedure {
    /// Procedure ID.
    pub id: String,
    /// Procedure name.
    pub name: String,
}

/// Procedure version retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureGetVersionResponse {
    /// Unique identifier for the procedure version.
    pub id: String,
    /// Version tag.
    pub tag: String,
    /// ISO 8601 timestamp when the procedure version was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this procedure version.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<ProcedureGetVersionCreatedByUser>,
    /// Station that created this procedure version.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<ProcedureGetVersionCreatedByStation>,
    /// Procedure this version belongs to.
    pub procedure: ProcedureGetVersionProcedure,
    /// Number of runs using this procedure version.
    pub run_count: i64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureDeleteVersionRequest {
    /// ID of the procedure that owns this version
    pub procedure_id: String,
    /// Version tag to delete
    pub tag: String,
}

/// Procedure version deleted successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureDeleteVersionResponse {
    /// ID of the deleted procedure version
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureCreateVersionRequestBody {
    /// The version tag
    pub tag: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureCreateVersionRequest {
    /// The ID of the procedure this version belongs to
    pub procedure_id: String,
    pub request_body: ProcedureCreateVersionRequestBody,
}

/// Procedure version created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProcedureCreateVersionResponse {
    /// Unique identifier for the created procedure version
    pub id: String,
}

/// Structured validator specification with operator and expected value.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunCreateValidators {
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operator: NullableField<String>,
    /// Expected value for comparison. Type depends on operator.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expected_value: NullableField<serde_json::Value>,
    /// Original expression string for display/audit purposes.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expression: NullableField<String>,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub is_decisive: NullableField<bool>,
}

impl RunCreateValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateValidatorsBuilder {
        RunCreateValidatorsBuilder::default()
    }
}

/// Builder for [`RunCreateValidators`].
#[derive(Debug, Default)]
pub struct RunCreateValidatorsBuilder {
    outcome: NullableField<String>,
    operator: NullableField<String>,
    expected_value: NullableField<serde_json::Value>,
    expression: NullableField<String>,
    is_decisive: NullableField<bool>,
}

impl RunCreateValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operator` field.
    ///
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    pub fn operator(mut self, value: impl Into<String>) -> Self {
        self.operator = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on operator.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expression` field.
    ///
    /// Original expression string for display/audit purposes.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = NullableField::Value(value.into());
        self
    }

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

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateValidators, String> {
        Ok(RunCreateValidators {
            outcome: self.outcome,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression,
            is_decisive: self.is_decisive,
        })
    }
}

/// Structured validator specification with operator, expected value, and outcome.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunCreateAggregationsValidators {
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operator: NullableField<String>,
    /// Expected value for comparison. Type depends on operator.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expected_value: NullableField<serde_json::Value>,
    /// Original expression string for display/audit purposes.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expression: NullableField<String>,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub is_decisive: NullableField<bool>,
}

impl RunCreateAggregationsValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateAggregationsValidatorsBuilder {
        RunCreateAggregationsValidatorsBuilder::default()
    }
}

/// Builder for [`RunCreateAggregationsValidators`].
#[derive(Debug, Default)]
pub struct RunCreateAggregationsValidatorsBuilder {
    outcome: NullableField<String>,
    operator: NullableField<String>,
    expected_value: NullableField<serde_json::Value>,
    expression: NullableField<String>,
    is_decisive: NullableField<bool>,
}

impl RunCreateAggregationsValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operator` field.
    ///
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    pub fn operator(mut self, value: impl Into<String>) -> Self {
        self.operator = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on operator.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expression` field.
    ///
    /// Original expression string for display/audit purposes.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = NullableField::Value(value.into());
        self
    }

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

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateAggregationsValidators, String> {
        Ok(RunCreateAggregationsValidators {
            outcome: self.outcome,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression,
            is_decisive: self.is_decisive,
        })
    }
}

/// Aggregation specification with computed value and optional validators.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateAggregations {
    /// Aggregation function: "min", "max", "avg", "sum", "count", "std", "median", "percentile_95", etc.
    #[serde(rename = "type")]
    pub r#type: String,
    /// Computed result of aggregation validation. Server stores as-is.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Computed aggregation value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub value: NullableField<serde_json::Value>,
    /// Unit for the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub unit: NullableField<String>,
    /// Validators applied to the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunCreateAggregationsValidators>>,
}

impl RunCreateAggregations {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateAggregationsBuilder {
        RunCreateAggregationsBuilder::default()
    }
}

/// Builder for [`RunCreateAggregations`].
#[derive(Debug, Default)]
pub struct RunCreateAggregationsBuilder {
    r#type: Option<String>,
    outcome: NullableField<String>,
    value: NullableField<serde_json::Value>,
    unit: NullableField<String>,
    validators: NullableField<Vec<RunCreateAggregationsValidators>>,
}

impl RunCreateAggregationsBuilder {
    /// Set the `type` field.
    ///
    /// Aggregation function: "min", "max", "avg", "sum", "count", "std", "median", "percentile_95", etc.
    pub fn r#type(mut self, value: impl Into<String>) -> Self {
        self.r#type = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Computed result of aggregation validation. Server stores as-is.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `value` field.
    ///
    /// Computed aggregation value.
    pub fn value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `unit` field.
    ///
    /// Unit for the aggregated value.
    pub fn unit(mut self, value: impl Into<String>) -> Self {
        self.unit = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators applied to the aggregated value.
    pub fn validators(mut self, value: impl Into<Vec<RunCreateAggregationsValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateAggregations, String> {
        Ok(RunCreateAggregations {
            r#type: self.r#type
                .ok_or_else(|| "missing required field: type".to_string())?,
            outcome: self.outcome,
            value: self.value,
            unit: self.unit,
            validators: self.validators,
        })
    }
}

/// Data series with numeric data, unit, and optional validators/aggregations.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateXAxis {
    /// Array of numeric data points for this axis.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<f64>,
    /// Unit for this axis.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub units: NullableField<String>,
    /// Name of this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub name: NullableField<String>,
    /// Description of this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub description: NullableField<String>,
    /// Validators for this specific axis/series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunCreateValidators>>,
    /// Aggregations computed over this axis data (min, max, avg, etc.).
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub aggregations: NullableField<Vec<RunCreateAggregations>>,
}

impl RunCreateXAxis {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateXAxisBuilder {
        RunCreateXAxisBuilder::default()
    }
}

/// Builder for [`RunCreateXAxis`].
#[derive(Debug, Default)]
pub struct RunCreateXAxisBuilder {
    data: Option<Vec<f64>>,
    units: NullableField<String>,
    name: NullableField<String>,
    description: NullableField<String>,
    validators: NullableField<Vec<RunCreateValidators>>,
    aggregations: NullableField<Vec<RunCreateAggregations>>,
}

impl RunCreateXAxisBuilder {
    /// Set the `data` field.
    ///
    /// Array of numeric data points for this axis.
    pub fn data(mut self, value: impl Into<Vec<f64>>) -> Self {
        self.data = Some(value.into());
        self
    }

    /// Set the `units` field.
    ///
    /// Unit for this axis.
    pub fn units(mut self, value: impl Into<String>) -> Self {
        self.units = NullableField::Value(value.into());
        self
    }

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

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

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

    /// Set the `description` field.
    ///
    /// Description of this data series.
    pub fn description(mut self, value: impl Into<String>) -> Self {
        self.description = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators for this specific axis/series.
    pub fn validators(mut self, value: impl Into<Vec<RunCreateValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Set the `aggregations` field.
    ///
    /// Aggregations computed over this axis data (min, max, avg, etc.).
    pub fn aggregations(mut self, value: impl Into<Vec<RunCreateAggregations>>) -> Self {
        self.aggregations = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateXAxis, String> {
        Ok(RunCreateXAxis {
            data: self.data.unwrap_or_default(),
            units: self.units,
            name: self.name,
            description: self.description,
            validators: self.validators,
            aggregations: self.aggregations,
        })
    }
}

/// Structured validator specification with operator and expected value.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunCreateYAxisValidators {
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operator: NullableField<String>,
    /// Expected value for comparison. Type depends on operator.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expected_value: NullableField<serde_json::Value>,
    /// Original expression string for display/audit purposes.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expression: NullableField<String>,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub is_decisive: NullableField<bool>,
}

impl RunCreateYAxisValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateYAxisValidatorsBuilder {
        RunCreateYAxisValidatorsBuilder::default()
    }
}

/// Builder for [`RunCreateYAxisValidators`].
#[derive(Debug, Default)]
pub struct RunCreateYAxisValidatorsBuilder {
    outcome: NullableField<String>,
    operator: NullableField<String>,
    expected_value: NullableField<serde_json::Value>,
    expression: NullableField<String>,
    is_decisive: NullableField<bool>,
}

impl RunCreateYAxisValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operator` field.
    ///
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    pub fn operator(mut self, value: impl Into<String>) -> Self {
        self.operator = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on operator.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expression` field.
    ///
    /// Original expression string for display/audit purposes.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = NullableField::Value(value.into());
        self
    }

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

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateYAxisValidators, String> {
        Ok(RunCreateYAxisValidators {
            outcome: self.outcome,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression,
            is_decisive: self.is_decisive,
        })
    }
}

/// Structured validator specification with operator, expected value, and outcome.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunCreateYAxisAggregationsValidators {
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operator: NullableField<String>,
    /// Expected value for comparison. Type depends on operator.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expected_value: NullableField<serde_json::Value>,
    /// Original expression string for display/audit purposes.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expression: NullableField<String>,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub is_decisive: NullableField<bool>,
}

impl RunCreateYAxisAggregationsValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateYAxisAggregationsValidatorsBuilder {
        RunCreateYAxisAggregationsValidatorsBuilder::default()
    }
}

/// Builder for [`RunCreateYAxisAggregationsValidators`].
#[derive(Debug, Default)]
pub struct RunCreateYAxisAggregationsValidatorsBuilder {
    outcome: NullableField<String>,
    operator: NullableField<String>,
    expected_value: NullableField<serde_json::Value>,
    expression: NullableField<String>,
    is_decisive: NullableField<bool>,
}

impl RunCreateYAxisAggregationsValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operator` field.
    ///
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    pub fn operator(mut self, value: impl Into<String>) -> Self {
        self.operator = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on operator.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expression` field.
    ///
    /// Original expression string for display/audit purposes.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = NullableField::Value(value.into());
        self
    }

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

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateYAxisAggregationsValidators, String> {
        Ok(RunCreateYAxisAggregationsValidators {
            outcome: self.outcome,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression,
            is_decisive: self.is_decisive,
        })
    }
}

/// Aggregation specification with computed value and optional validators.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateYAxisAggregations {
    /// Aggregation function: "min", "max", "avg", "sum", "count", "std", "median", "percentile_95", etc.
    #[serde(rename = "type")]
    pub r#type: String,
    /// Computed result of aggregation validation. Server stores as-is.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Computed aggregation value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub value: NullableField<serde_json::Value>,
    /// Unit for the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub unit: NullableField<String>,
    /// Validators applied to the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunCreateYAxisAggregationsValidators>>,
}

impl RunCreateYAxisAggregations {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateYAxisAggregationsBuilder {
        RunCreateYAxisAggregationsBuilder::default()
    }
}

/// Builder for [`RunCreateYAxisAggregations`].
#[derive(Debug, Default)]
pub struct RunCreateYAxisAggregationsBuilder {
    r#type: Option<String>,
    outcome: NullableField<String>,
    value: NullableField<serde_json::Value>,
    unit: NullableField<String>,
    validators: NullableField<Vec<RunCreateYAxisAggregationsValidators>>,
}

impl RunCreateYAxisAggregationsBuilder {
    /// Set the `type` field.
    ///
    /// Aggregation function: "min", "max", "avg", "sum", "count", "std", "median", "percentile_95", etc.
    pub fn r#type(mut self, value: impl Into<String>) -> Self {
        self.r#type = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Computed result of aggregation validation. Server stores as-is.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `value` field.
    ///
    /// Computed aggregation value.
    pub fn value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `unit` field.
    ///
    /// Unit for the aggregated value.
    pub fn unit(mut self, value: impl Into<String>) -> Self {
        self.unit = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators applied to the aggregated value.
    pub fn validators(mut self, value: impl Into<Vec<RunCreateYAxisAggregationsValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateYAxisAggregations, String> {
        Ok(RunCreateYAxisAggregations {
            r#type: self.r#type
                .ok_or_else(|| "missing required field: type".to_string())?,
            outcome: self.outcome,
            value: self.value,
            unit: self.unit,
            validators: self.validators,
        })
    }
}

/// Data series with numeric data, unit, and optional validators/aggregations.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateYAxis {
    /// Array of numeric data points for this axis.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<f64>,
    /// Unit for this axis.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub units: NullableField<String>,
    /// Name of this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub name: NullableField<String>,
    /// Description of this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub description: NullableField<String>,
    /// Validators for this specific axis/series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunCreateYAxisValidators>>,
    /// Aggregations computed over this axis data (min, max, avg, etc.).
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub aggregations: NullableField<Vec<RunCreateYAxisAggregations>>,
}

impl RunCreateYAxis {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateYAxisBuilder {
        RunCreateYAxisBuilder::default()
    }
}

/// Builder for [`RunCreateYAxis`].
#[derive(Debug, Default)]
pub struct RunCreateYAxisBuilder {
    data: Option<Vec<f64>>,
    units: NullableField<String>,
    name: NullableField<String>,
    description: NullableField<String>,
    validators: NullableField<Vec<RunCreateYAxisValidators>>,
    aggregations: NullableField<Vec<RunCreateYAxisAggregations>>,
}

impl RunCreateYAxisBuilder {
    /// Set the `data` field.
    ///
    /// Array of numeric data points for this axis.
    pub fn data(mut self, value: impl Into<Vec<f64>>) -> Self {
        self.data = Some(value.into());
        self
    }

    /// Set the `units` field.
    ///
    /// Unit for this axis.
    pub fn units(mut self, value: impl Into<String>) -> Self {
        self.units = NullableField::Value(value.into());
        self
    }

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

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

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

    /// Set the `description` field.
    ///
    /// Description of this data series.
    pub fn description(mut self, value: impl Into<String>) -> Self {
        self.description = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators for this specific axis/series.
    pub fn validators(mut self, value: impl Into<Vec<RunCreateYAxisValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Set the `aggregations` field.
    ///
    /// Aggregations computed over this axis data (min, max, avg, etc.).
    pub fn aggregations(mut self, value: impl Into<Vec<RunCreateYAxisAggregations>>) -> Self {
        self.aggregations = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateYAxis, String> {
        Ok(RunCreateYAxis {
            data: self.data.unwrap_or_default(),
            units: self.units,
            name: self.name,
            description: self.description,
            validators: self.validators,
            aggregations: self.aggregations,
        })
    }
}

/// Structured validator specification with operator and expected value.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunCreateMeasurementsValidators {
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operator: NullableField<String>,
    /// Expected value for comparison. Type depends on operator.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expected_value: NullableField<serde_json::Value>,
    /// Original expression string for display/audit purposes.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expression: NullableField<String>,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub is_decisive: NullableField<bool>,
}

impl RunCreateMeasurementsValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateMeasurementsValidatorsBuilder {
        RunCreateMeasurementsValidatorsBuilder::default()
    }
}

/// Builder for [`RunCreateMeasurementsValidators`].
#[derive(Debug, Default)]
pub struct RunCreateMeasurementsValidatorsBuilder {
    outcome: NullableField<String>,
    operator: NullableField<String>,
    expected_value: NullableField<serde_json::Value>,
    expression: NullableField<String>,
    is_decisive: NullableField<bool>,
}

impl RunCreateMeasurementsValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operator` field.
    ///
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    pub fn operator(mut self, value: impl Into<String>) -> Self {
        self.operator = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on operator.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expression` field.
    ///
    /// Original expression string for display/audit purposes.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = NullableField::Value(value.into());
        self
    }

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

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateMeasurementsValidators, String> {
        Ok(RunCreateMeasurementsValidators {
            outcome: self.outcome,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression,
            is_decisive: self.is_decisive,
        })
    }
}

/// Structured validator specification with operator, expected value, and outcome.
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunCreateMeasurementsAggregationsValidators {
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operator: NullableField<String>,
    /// Expected value for comparison. Type depends on operator.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expected_value: NullableField<serde_json::Value>,
    /// Original expression string for display/audit purposes.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub expression: NullableField<String>,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub is_decisive: NullableField<bool>,
}

impl RunCreateMeasurementsAggregationsValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateMeasurementsAggregationsValidatorsBuilder {
        RunCreateMeasurementsAggregationsValidatorsBuilder::default()
    }
}

/// Builder for [`RunCreateMeasurementsAggregationsValidators`].
#[derive(Debug, Default)]
pub struct RunCreateMeasurementsAggregationsValidatorsBuilder {
    outcome: NullableField<String>,
    operator: NullableField<String>,
    expected_value: NullableField<serde_json::Value>,
    expression: NullableField<String>,
    is_decisive: NullableField<bool>,
}

impl RunCreateMeasurementsAggregationsValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Pre-computed validation result from test framework. Server stores as-is, does not re-evaluate.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operator` field.
    ///
    /// Comparison operator: ">", ">=", "<", "<=", "==", "!=", "matches", "in", "range"
    pub fn operator(mut self, value: impl Into<String>) -> Self {
        self.operator = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on operator.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `expression` field.
    ///
    /// Original expression string for display/audit purposes.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = NullableField::Value(value.into());
        self
    }

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

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators. Defaults to true.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateMeasurementsAggregationsValidators, String> {
        Ok(RunCreateMeasurementsAggregationsValidators {
            outcome: self.outcome,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression,
            is_decisive: self.is_decisive,
        })
    }
}

/// Aggregation specification with computed value and optional validators.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateMeasurementsAggregations {
    /// Aggregation function: "min", "max", "avg", "sum", "count", "std", "median", "percentile_95", etc.
    #[serde(rename = "type")]
    pub r#type: String,
    /// Computed result of aggregation validation. Server stores as-is.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub outcome: NullableField<String>,
    /// Computed aggregation value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub value: NullableField<serde_json::Value>,
    /// Unit for the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub unit: NullableField<String>,
    /// Validators applied to the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunCreateMeasurementsAggregationsValidators>>,
}

impl RunCreateMeasurementsAggregations {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateMeasurementsAggregationsBuilder {
        RunCreateMeasurementsAggregationsBuilder::default()
    }
}

/// Builder for [`RunCreateMeasurementsAggregations`].
#[derive(Debug, Default)]
pub struct RunCreateMeasurementsAggregationsBuilder {
    r#type: Option<String>,
    outcome: NullableField<String>,
    value: NullableField<serde_json::Value>,
    unit: NullableField<String>,
    validators: NullableField<Vec<RunCreateMeasurementsAggregationsValidators>>,
}

impl RunCreateMeasurementsAggregationsBuilder {
    /// Set the `type` field.
    ///
    /// Aggregation function: "min", "max", "avg", "sum", "count", "std", "median", "percentile_95", etc.
    pub fn r#type(mut self, value: impl Into<String>) -> Self {
        self.r#type = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Computed result of aggregation validation. Server stores as-is.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = NullableField::Value(value.into());
        self
    }

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

    /// Set the `value` field.
    ///
    /// Computed aggregation value.
    pub fn value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `unit` field.
    ///
    /// Unit for the aggregated value.
    pub fn unit(mut self, value: impl Into<String>) -> Self {
        self.unit = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators applied to the aggregated value.
    pub fn validators(mut self, value: impl Into<Vec<RunCreateMeasurementsAggregationsValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateMeasurementsAggregations, String> {
        Ok(RunCreateMeasurementsAggregations {
            r#type: self.r#type
                .ok_or_else(|| "missing required field: type".to_string())?,
            outcome: self.outcome,
            value: self.value,
            unit: self.unit,
            validators: self.validators,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateMeasurements {
    /// Name identifier for the measurement. Each measurement should have a descriptive name that identifies the specific data point being captured. Analytics at measurement level are computed using this name as unique identifier.
    pub name: String,
    /// Result of the measurement validation. Use PASS when measurement meets all criteria, FAIL when measurement is outside acceptable limits or validation fails, UNSET when no validation was performed.
    pub outcome: ValidatorsOutcome,
    /// X-axis data series for multi-dimensional measurements. Use with y_axis for structured multi-dimensional data with per-axis validators/aggregations.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub x_axis: NullableField<RunCreateXAxis>,
    /// Y-axis data series (one or more) for multi-dimensional measurements. Each series can have its own validators and aggregations.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub y_axis: NullableField<Vec<RunCreateYAxis>>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub measured_value: NullableField<serde_json::Value>,
    /// [LEGACY for multi-dim] Units of measurement. For structured multi-dimensional, use units within x_axis/y_axis instead.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub units: NullableField<serde_json::Value>,
    /// Use validators with operator ">=" instead. Will be converted to a validator automatically.
    #[deprecated]
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub lower_limit: Option<f64>,
    /// Use validators with operator "<=" instead. Will be converted to a validator automatically.
    #[deprecated]
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub upper_limit: Option<f64>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunCreateMeasurementsValidators>>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub aggregations: NullableField<Vec<RunCreateMeasurementsAggregations>>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub docstring: NullableField<String>,
}

impl RunCreateMeasurements {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateMeasurementsBuilder {
        RunCreateMeasurementsBuilder::default()
    }
}

/// Builder for [`RunCreateMeasurements`].
#[derive(Debug, Default)]
pub struct RunCreateMeasurementsBuilder {
    name: Option<String>,
    outcome: Option<ValidatorsOutcome>,
    x_axis: NullableField<RunCreateXAxis>,
    y_axis: NullableField<Vec<RunCreateYAxis>>,
    measured_value: NullableField<serde_json::Value>,
    units: NullableField<serde_json::Value>,
    lower_limit: Option<f64>,
    upper_limit: Option<f64>,
    validators: NullableField<Vec<RunCreateMeasurementsValidators>>,
    aggregations: NullableField<Vec<RunCreateMeasurementsAggregations>>,
    docstring: NullableField<String>,
}

impl RunCreateMeasurementsBuilder {
    /// Set the `name` field.
    ///
    /// Name identifier for the measurement. Each measurement should have a descriptive name that identifies the specific data point being captured. Analytics at measurement level are computed using this name as unique identifier.
    pub fn name(mut self, value: impl Into<String>) -> Self {
        self.name = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Result of the measurement validation. Use PASS when measurement meets all criteria, FAIL when measurement is outside acceptable limits or validation fails, UNSET when no validation was performed.
    pub fn outcome(mut self, value: impl Into<ValidatorsOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `x_axis` field.
    ///
    /// X-axis data series for multi-dimensional measurements. Use with y_axis for structured multi-dimensional data with per-axis validators/aggregations.
    pub fn x_axis(mut self, value: impl Into<RunCreateXAxis>) -> Self {
        self.x_axis = NullableField::Value(value.into());
        self
    }

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

    /// Set the `y_axis` field.
    ///
    /// Y-axis data series (one or more) for multi-dimensional measurements. Each series can have its own validators and aggregations.
    pub fn y_axis(mut self, value: impl Into<Vec<RunCreateYAxis>>) -> Self {
        self.y_axis = NullableField::Value(value.into());
        self
    }

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

    /// Set the `measured_value` field.
    pub fn measured_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.measured_value = NullableField::Value(value.into());
        self
    }

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

    /// Set the `units` field.
    ///
    /// [LEGACY for multi-dim] Units of measurement. For structured multi-dimensional, use units within x_axis/y_axis instead.
    pub fn units(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.units = NullableField::Value(value.into());
        self
    }

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

    /// Set the `lower_limit` field.
    ///
    /// Use validators with operator ">=" instead. Will be converted to a validator automatically.
    #[deprecated]
    pub fn lower_limit(mut self, value: impl Into<f64>) -> Self {
        self.lower_limit = Some(value.into());
        self
    }

    /// Set the `upper_limit` field.
    ///
    /// Use validators with operator "<=" instead. Will be converted to a validator automatically.
    #[deprecated]
    pub fn upper_limit(mut self, value: impl Into<f64>) -> Self {
        self.upper_limit = Some(value.into());
        self
    }

    /// Set the `validators` field.
    pub fn validators(mut self, value: impl Into<Vec<RunCreateMeasurementsValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Set the `aggregations` field.
    pub fn aggregations(mut self, value: impl Into<Vec<RunCreateMeasurementsAggregations>>) -> Self {
        self.aggregations = NullableField::Value(value.into());
        self
    }

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

    /// Set the `docstring` field.
    pub fn docstring(mut self, value: impl Into<String>) -> Self {
        self.docstring = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    #[allow(deprecated)]
    pub fn build(self) -> std::result::Result<RunCreateMeasurements, String> {
        Ok(RunCreateMeasurements {
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            x_axis: self.x_axis,
            y_axis: self.y_axis,
            measured_value: self.measured_value,
            units: self.units,
            lower_limit: self.lower_limit,
            upper_limit: self.upper_limit,
            validators: self.validators,
            aggregations: self.aggregations,
            docstring: self.docstring,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreatePhases {
    /// Name identifier for the test phase. Each phase should have a descriptive name that identifies the specific stage of testing being performed. Analytics at phase level are computed using this name as unique identifier.
    pub name: String,
    /// Overall result of the phase execution. Use PASS when phase succeeds, FAIL when phase fails but execution completed successfully, ERROR when phase execution fails, SKIP when phase was not executed.
    pub outcome: PhasesOutcome,
    /// ISO 8601 timestamp when the phase execution began.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the phase execution completed.
    pub ended_at: chrono::DateTime<chrono::Utc>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub docstring: NullableField<String>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub measurements: NullableField<Vec<RunCreateMeasurements>>,
    /// Zero-based retry attempt index for this phase. 0 = first attempt, 1 = first retry, etc. When a phase is retried, all attempts are stored with the same name and increasing retry_count.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub retry_count: Option<i64>,
    /// True when the phase was marked as expected-to-fail by the test framework (pytest @pytest.mark.xfail). Lets dashboards distinguish an expected failure from a generic SKIP. Defaults to false; OpenHTF and YAML procedures never set this.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expected_to_fail: Option<bool>,
}

impl RunCreatePhases {
    /// Create a builder for this type.
    pub fn builder() -> RunCreatePhasesBuilder {
        RunCreatePhasesBuilder::default()
    }
}

/// Builder for [`RunCreatePhases`].
#[derive(Debug, Default)]
pub struct RunCreatePhasesBuilder {
    name: Option<String>,
    outcome: Option<PhasesOutcome>,
    started_at: Option<chrono::DateTime<chrono::Utc>>,
    ended_at: Option<chrono::DateTime<chrono::Utc>>,
    docstring: NullableField<String>,
    measurements: NullableField<Vec<RunCreateMeasurements>>,
    retry_count: Option<i64>,
    expected_to_fail: Option<bool>,
}

impl RunCreatePhasesBuilder {
    /// Set the `name` field.
    ///
    /// Name identifier for the test phase. Each phase should have a descriptive name that identifies the specific stage of testing being performed. Analytics at phase level are computed using this name as unique identifier.
    pub fn name(mut self, value: impl Into<String>) -> Self {
        self.name = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Overall result of the phase execution. Use PASS when phase succeeds, FAIL when phase fails but execution completed successfully, ERROR when phase execution fails, SKIP when phase was not executed.
    pub fn outcome(mut self, value: impl Into<PhasesOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `started_at` field.
    ///
    /// ISO 8601 timestamp when the phase execution began.
    pub fn started_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.started_at = Some(value.into());
        self
    }

    /// Set the `ended_at` field.
    ///
    /// ISO 8601 timestamp when the phase execution completed.
    pub fn ended_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.ended_at = Some(value.into());
        self
    }

    /// Set the `docstring` field.
    pub fn docstring(mut self, value: impl Into<String>) -> Self {
        self.docstring = NullableField::Value(value.into());
        self
    }

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

    /// Set the `measurements` field.
    pub fn measurements(mut self, value: impl Into<Vec<RunCreateMeasurements>>) -> Self {
        self.measurements = NullableField::Value(value.into());
        self
    }

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

    /// Set the `retry_count` field.
    ///
    /// Zero-based retry attempt index for this phase. 0 = first attempt, 1 = first retry, etc. When a phase is retried, all attempts are stored with the same name and increasing retry_count.
    pub fn retry_count(mut self, value: impl Into<i64>) -> Self {
        self.retry_count = Some(value.into());
        self
    }

    /// Set the `expected_to_fail` field.
    ///
    /// True when the phase was marked as expected-to-fail by the test framework (pytest @pytest.mark.xfail).
    pub fn expected_to_fail(mut self, value: impl Into<bool>) -> Self {
        self.expected_to_fail = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreatePhases, String> {
        Ok(RunCreatePhases {
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            started_at: self.started_at
                .ok_or_else(|| "missing required field: started_at".to_string())?,
            ended_at: self.ended_at
                .ok_or_else(|| "missing required field: ended_at".to_string())?,
            docstring: self.docstring,
            measurements: self.measurements,
            retry_count: self.retry_count,
            expected_to_fail: self.expected_to_fail,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateLogs {
    /// Severity level of the log message following standard system logging levels. Use DEBUG for detailed diagnostic information, INFO for general execution information, WARNING for unexpected events or potential issues, ERROR for serious problems that prevented function execution, CRITICAL for severe errors that may cause program termination.
    pub level: Level,
    /// ISO 8601 timestamp when the log message was generated.
    pub timestamp: chrono::DateTime<chrono::Utc>,
    /// Content of the log message. Contains the actual log text describing the event, error, or information being logged. Messages longer than 10,000 characters will be truncated.
    pub message: String,
    /// Name or path of the source file where the log message originated. Helps identify the code location that generated the log entry.
    pub source_file: String,
    /// Line number in the source file where the log message was generated. Used for debugging and tracing log origins.
    pub line_number: i64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateRequest {
    /// Overall test result. Use PASS when test succeeds, FAIL when test fails but script execution completed successfully, ERROR when script execution fails, TIMEOUT when test exceeds time limit, ABORTED for manual script interruption.
    pub outcome: Outcome,
    /// Procedure ID. Create the procedure in the app first, then find the auto-generated ID on the procedure page.
    pub procedure_id: String,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub deployment_id: NullableField<String>,
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub procedure_version: NullableField<String>,
    /// Email address of the operator who executed the test run. The operator must exist as a user in the system. The run will be linked to this user to track who performed the test.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operated_by: Option<String>,
    /// ISO 8601 timestamp when the test run began execution. This timestamp will be used to track when the test execution started and for historical analysis of test runs. A separate created_at timestamp is stored internally server side to track upload date.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the test run finished execution.
    pub ended_at: chrono::DateTime<chrono::Utc>,
    /// Unique serial number of the unit under test. Matched case-insensitively. If no unit with this serial number exists, one will be created.
    pub serial_number: String,
    /// Component part number for the unit. Matched case-insensitively. This field is required if the part number cannot be extracted from the serial number (as set in the settings). This field takes precedence over extraction from serial number. A component with the provided or extracted part number will be created if one does not exist.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part_number: Option<String>,
    /// Hardware revision identifier for the unit. Matched case-insensitively. If none exist, a revision with this number will be created. If no revision is specified, the unit will be linked to the default revision of the part number.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_number: Option<String>,
    /// Production batch identifier for grouping units manufactured together. Matched case-insensitively. If none exist, a batch with this batch number will be created. If no batch number is specified, the unit will not be linked to any batch.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub batch_number: Option<String>,
    /// Array of sub-unit serial numbers that are part of this main unit. Matched case-insensitively. Each sub-unit must already exist and will be linked as a sub-component of the main unit under test. If no sub-units are specified, the unit will be created without sub-unit relationships.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sub_units: Option<Vec<String>>,
    /// Additional notes or documentation about this test run.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub docstring: Option<String>,
    /// Array of test phases with measurements and results. Each phase represents a distinct stage of the test execution with timing information, outcome status, and optional measurements. If no phases are specified, the run will be created without phase-level organization of test data.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub phases: Option<Vec<RunCreatePhases>>,
    /// Array of log messages generated during the test execution. Each log entry captures events, errors, and diagnostic information with severity levels and source code references. If no logs are specified, the run will be created without log entries.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub logs: Option<Vec<RunCreateLogs>>,
}

impl RunCreateRequest {
    /// Create a builder for this type.
    pub fn builder() -> RunCreateRequestBuilder {
        RunCreateRequestBuilder::default()
    }
}

/// Builder for [`RunCreateRequest`].
#[derive(Debug, Default)]
pub struct RunCreateRequestBuilder {
    outcome: Option<Outcome>,
    procedure_id: Option<String>,
    deployment_id: NullableField<String>,
    procedure_version: NullableField<String>,
    operated_by: Option<String>,
    started_at: Option<chrono::DateTime<chrono::Utc>>,
    ended_at: Option<chrono::DateTime<chrono::Utc>>,
    serial_number: Option<String>,
    part_number: Option<String>,
    revision_number: Option<String>,
    batch_number: Option<String>,
    sub_units: Option<Vec<String>>,
    docstring: Option<String>,
    phases: Option<Vec<RunCreatePhases>>,
    logs: Option<Vec<RunCreateLogs>>,
}

impl RunCreateRequestBuilder {
    /// Set the `outcome` field.
    ///
    /// Overall test result. Use PASS when test succeeds, FAIL when test fails but script execution completed successfully, ERROR when script execution fails, TIMEOUT when test exceeds time limit, ABORTED for manual script interruption.
    pub fn outcome(mut self, value: impl Into<Outcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `procedure_id` field.
    ///
    /// Procedure ID. Create the procedure in the app first, then find the auto-generated ID on the procedure page.
    pub fn procedure_id(mut self, value: impl Into<String>) -> Self {
        self.procedure_id = Some(value.into());
        self
    }

    /// Set the `deployment_id` field.
    pub fn deployment_id(mut self, value: impl Into<String>) -> Self {
        self.deployment_id = NullableField::Value(value.into());
        self
    }

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

    /// Set the `procedure_version` field.
    pub fn procedure_version(mut self, value: impl Into<String>) -> Self {
        self.procedure_version = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operated_by` field.
    ///
    /// Email address of the operator who executed the test run. The operator must exist as a user in the system. The run will be linked to this user to track who performed the test.
    pub fn operated_by(mut self, value: impl Into<String>) -> Self {
        self.operated_by = Some(value.into());
        self
    }

    /// Set the `started_at` field.
    ///
    /// ISO 8601 timestamp when the test run began execution. This timestamp will be used to track when the test execution started and for historical analysis of test runs. A separate created_at timestamp is stored internally server side to track upload date.
    pub fn started_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.started_at = Some(value.into());
        self
    }

    /// Set the `ended_at` field.
    ///
    /// ISO 8601 timestamp when the test run finished execution.
    pub fn ended_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.ended_at = Some(value.into());
        self
    }

    /// Set the `serial_number` field.
    ///
    /// Unique serial number of the unit under test. Matched case-insensitively. If no unit with this serial number exists, one will be created.
    pub fn serial_number(mut self, value: impl Into<String>) -> Self {
        self.serial_number = Some(value.into());
        self
    }

    /// Set the `part_number` field.
    ///
    /// Component part number for the unit. Matched case-insensitively. This field is required if the part number cannot be extracted from the serial number (as set in the settings). This field takes precedence over extraction from serial number. A component with the provided or extracted part number will be created if one does not exist.
    pub fn part_number(mut self, value: impl Into<String>) -> Self {
        self.part_number = Some(value.into());
        self
    }

    /// Set the `revision_number` field.
    ///
    /// Hardware revision identifier for the unit. Matched case-insensitively. If none exist, a revision with this number will be created. If no revision is specified, the unit will be linked to the default revision of the part number.
    pub fn revision_number(mut self, value: impl Into<String>) -> Self {
        self.revision_number = Some(value.into());
        self
    }

    /// Set the `batch_number` field.
    ///
    /// Production batch identifier for grouping units manufactured together. Matched case-insensitively. If none exist, a batch with this batch number will be created. If no batch number is specified, the unit will not be linked to any batch.
    pub fn batch_number(mut self, value: impl Into<String>) -> Self {
        self.batch_number = Some(value.into());
        self
    }

    /// Set the `sub_units` field.
    ///
    /// Array of sub-unit serial numbers that are part of this main unit. Matched case-insensitively. Each sub-unit must already exist and will be linked as a sub-component of the main unit under test. If no sub-units are specified, the unit will be created without sub-unit relationships.
    pub fn sub_units(mut self, value: impl Into<Vec<String>>) -> Self {
        self.sub_units = Some(value.into());
        self
    }

    /// Set the `docstring` field.
    ///
    /// Additional notes or documentation about this test run.
    pub fn docstring(mut self, value: impl Into<String>) -> Self {
        self.docstring = Some(value.into());
        self
    }

    /// Set the `phases` field.
    ///
    /// Array of test phases with measurements and results. Each phase represents a distinct stage of the test execution with timing information, outcome status, and optional measurements. If no phases are specified, the run will be created without phase-level organization of test data.
    pub fn phases(mut self, value: impl Into<Vec<RunCreatePhases>>) -> Self {
        self.phases = Some(value.into());
        self
    }

    /// Set the `logs` field.
    ///
    /// Array of log messages generated during the test execution. Each log entry captures events, errors, and diagnostic information with severity levels and source code references. If no logs are specified, the run will be created without log entries.
    pub fn logs(mut self, value: impl Into<Vec<RunCreateLogs>>) -> Self {
        self.logs = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunCreateRequest, String> {
        Ok(RunCreateRequest {
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            procedure_id: self.procedure_id
                .ok_or_else(|| "missing required field: procedure_id".to_string())?,
            deployment_id: self.deployment_id,
            procedure_version: self.procedure_version,
            operated_by: self.operated_by,
            started_at: self.started_at
                .ok_or_else(|| "missing required field: started_at".to_string())?,
            ended_at: self.ended_at
                .ok_or_else(|| "missing required field: ended_at".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            part_number: self.part_number,
            revision_number: self.revision_number,
            batch_number: self.batch_number,
            sub_units: self.sub_units,
            docstring: self.docstring,
            phases: self.phases,
            logs: self.logs,
        })
    }
}

/// Run created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateResponse {
    /// Unique identifier of the created run.
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunListRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub outcomes: Option<Vec<Outcome>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure_ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure_versions: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub serial_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub batch_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub duration_min: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub duration_max: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub started_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub started_before: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub ended_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub ended_before: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_before: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_user_ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_station_ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operated_by_ids: Option<Vec<String>>,
    /// Maximum number of runs to return per page.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cursor: Option<i64>,
    /// Field to sort results by.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_by: Option<RunListSortBy>,
    /// Sort order direction.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_order: Option<ListSortOrder>,
}

impl RunListRequest {
    /// Create a builder for this type.
    pub fn builder() -> RunListRequestBuilder {
        RunListRequestBuilder::default()
    }
}

/// Builder for [`RunListRequest`].
#[derive(Debug, Default)]
pub struct RunListRequestBuilder {
    search_query: Option<String>,
    ids: Option<Vec<String>>,
    outcomes: Option<Vec<Outcome>>,
    procedure_ids: Option<Vec<String>>,
    procedure_versions: Option<Vec<String>>,
    serial_numbers: Option<Vec<String>>,
    part_numbers: Option<Vec<String>>,
    revision_numbers: Option<Vec<String>>,
    batch_numbers: Option<Vec<String>>,
    duration_min: Option<String>,
    duration_max: Option<String>,
    started_after: Option<chrono::DateTime<chrono::Utc>>,
    started_before: Option<chrono::DateTime<chrono::Utc>>,
    ended_after: Option<chrono::DateTime<chrono::Utc>>,
    ended_before: Option<chrono::DateTime<chrono::Utc>>,
    created_after: Option<chrono::DateTime<chrono::Utc>>,
    created_before: Option<chrono::DateTime<chrono::Utc>>,
    created_by_user_ids: Option<Vec<String>>,
    created_by_station_ids: Option<Vec<String>>,
    operated_by_ids: Option<Vec<String>>,
    limit: Option<i64>,
    cursor: Option<i64>,
    sort_by: Option<RunListSortBy>,
    sort_order: Option<ListSortOrder>,
}

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

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

    /// Set the `outcomes` field.
    pub fn outcomes(mut self, value: impl Into<Vec<Outcome>>) -> Self {
        self.outcomes = Some(value.into());
        self
    }

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

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

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

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

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

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

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

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

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

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

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

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

    /// Set the `created_after` field.
    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` field.
    pub fn created_before(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_before = Some(value.into());
        self
    }

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

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

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

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

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

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

    /// Set the `sort_order` field.
    ///
    /// Sort order direction.
    pub fn sort_order(mut self, value: impl Into<ListSortOrder>) -> Self {
        self.sort_order = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListRequest, String> {
        Ok(RunListRequest {
            search_query: self.search_query,
            ids: self.ids,
            outcomes: self.outcomes,
            procedure_ids: self.procedure_ids,
            procedure_versions: self.procedure_versions,
            serial_numbers: self.serial_numbers,
            part_numbers: self.part_numbers,
            revision_numbers: self.revision_numbers,
            batch_numbers: self.batch_numbers,
            duration_min: self.duration_min,
            duration_max: self.duration_max,
            started_after: self.started_after,
            started_before: self.started_before,
            ended_after: self.ended_after,
            ended_before: self.ended_before,
            created_after: self.created_after,
            created_before: self.created_before,
            created_by_user_ids: self.created_by_user_ids,
            created_by_station_ids: self.created_by_station_ids,
            operated_by_ids: self.operated_by_ids,
            limit: self.limit,
            cursor: self.cursor,
            sort_by: self.sort_by,
            sort_order: self.sort_order,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

impl RunListCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> RunListCreatedByUserBuilder {
        RunListCreatedByUserBuilder::default()
    }
}

/// Builder for [`RunListCreatedByUser`].
#[derive(Debug, Default)]
pub struct RunListCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl RunListCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListCreatedByUser, String> {
        Ok(RunListCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
            email: self.email,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListCreatedByStation {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListOperatedBy {
    /// Operator ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

impl RunListOperatedBy {
    /// Create a builder for this type.
    pub fn builder() -> RunListOperatedByBuilder {
        RunListOperatedByBuilder::default()
    }
}

/// Builder for [`RunListOperatedBy`].
#[derive(Debug, Default)]
pub struct RunListOperatedByBuilder {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl RunListOperatedByBuilder {
    /// Set the `id` field.
    ///
    /// Operator ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListOperatedBy, String> {
        Ok(RunListOperatedBy {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
            email: self.email,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListVersion {
    /// Procedure version ID.
    pub id: String,
    /// Version tag.
    pub tag: String,
}

/// Test procedure associated with this run.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListProcedure {
    /// Procedure ID.
    pub id: String,
    /// Procedure name.
    pub name: String,
    /// Version of the procedure used for this run.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<RunListVersion>,
}

impl RunListProcedure {
    /// Create a builder for this type.
    pub fn builder() -> RunListProcedureBuilder {
        RunListProcedureBuilder::default()
    }
}

/// Builder for [`RunListProcedure`].
#[derive(Debug, Default)]
pub struct RunListProcedureBuilder {
    id: Option<String>,
    name: Option<String>,
    version: Option<RunListVersion>,
}

impl RunListProcedureBuilder {
    /// Set the `id` field.
    ///
    /// Procedure ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `version` field.
    ///
    /// Version of the procedure used for this run.
    pub fn version(mut self, value: impl Into<RunListVersion>) -> Self {
        self.version = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListProcedure, String> {
        Ok(RunListProcedure {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            version: self.version,
        })
    }
}

/// Revision information for this unit.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListRevision {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
}

/// Part information with revision details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListPart {
    /// Part ID.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// Revision information for this unit.
    pub revision: RunListRevision,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListBatch {
    /// Batch ID.
    pub id: String,
    /// Batch number.
    pub number: String,
}

/// Unit under test information.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListUnit {
    /// Unit ID.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// Part information with revision details.
    pub part: RunListPart,
    /// Batch information for this unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub batch: NullableField<RunListBatch>,
}

impl RunListUnit {
    /// Create a builder for this type.
    pub fn builder() -> RunListUnitBuilder {
        RunListUnitBuilder::default()
    }
}

/// Builder for [`RunListUnit`].
#[derive(Debug, Default)]
pub struct RunListUnitBuilder {
    id: Option<String>,
    serial_number: Option<String>,
    part: Option<RunListPart>,
    batch: NullableField<RunListBatch>,
}

impl RunListUnitBuilder {
    /// Set the `id` field.
    ///
    /// Unit ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `part` field.
    ///
    /// Part information with revision details.
    pub fn part(mut self, value: impl Into<RunListPart>) -> Self {
        self.part = Some(value.into());
        self
    }

    /// Set the `batch` field.
    ///
    /// Batch information for this unit.
    pub fn batch(mut self, value: impl Into<RunListBatch>) -> Self {
        self.batch = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListUnit, String> {
        Ok(RunListUnit {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            part: self.part
                .ok_or_else(|| "missing required field: part".to_string())?,
            batch: self.batch,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListData {
    /// Unique identifier for the run.
    pub id: String,
    /// ISO 8601 timestamp when the run was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run execution started.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run execution ended.
    pub ended_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 duration of the run (computed from started_at and ended_at).
    pub duration: String,
    /// Final result of the run execution.
    pub outcome: Outcome,
    /// Additional notes or documentation about this test run.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub docstring: NullableField<String>,
    /// User whose API key was used to create this run. Only returned if `all` or `created_by` is included.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<RunListCreatedByUser>,
    /// Station whose API key was used to create this run. Only returned if `all` or `created_by` is included.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<RunListCreatedByStation>,
    /// User who operated this run. Only returned if `all` or `operated_by` is included.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operated_by: NullableField<RunListOperatedBy>,
    /// Test procedure associated with this run.
    pub procedure: RunListProcedure,
    /// Unit under test information.
    pub unit: RunListUnit,
}

impl RunListData {
    /// Create a builder for this type.
    pub fn builder() -> RunListDataBuilder {
        RunListDataBuilder::default()
    }
}

/// Builder for [`RunListData`].
#[derive(Debug, Default)]
pub struct RunListDataBuilder {
    id: Option<String>,
    created_at: Option<chrono::DateTime<chrono::Utc>>,
    started_at: Option<chrono::DateTime<chrono::Utc>>,
    ended_at: Option<chrono::DateTime<chrono::Utc>>,
    duration: Option<String>,
    outcome: Option<Outcome>,
    docstring: NullableField<String>,
    created_by_user: NullableField<RunListCreatedByUser>,
    created_by_station: NullableField<RunListCreatedByStation>,
    operated_by: NullableField<RunListOperatedBy>,
    procedure: Option<RunListProcedure>,
    unit: Option<RunListUnit>,
}

impl RunListDataBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the run.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `created_at` field.
    ///
    /// ISO 8601 timestamp when the run was created.
    pub fn created_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_at = Some(value.into());
        self
    }

    /// Set the `started_at` field.
    ///
    /// ISO 8601 timestamp when the run execution started.
    pub fn started_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.started_at = Some(value.into());
        self
    }

    /// Set the `ended_at` field.
    ///
    /// ISO 8601 timestamp when the run execution ended.
    pub fn ended_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.ended_at = Some(value.into());
        self
    }

    /// Set the `duration` field.
    ///
    /// ISO 8601 duration of the run (computed from started_at and ended_at).
    pub fn duration(mut self, value: impl Into<String>) -> Self {
        self.duration = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Final result of the run execution.
    pub fn outcome(mut self, value: impl Into<Outcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `docstring` field.
    ///
    /// Additional notes or documentation about this test run.
    pub fn docstring(mut self, value: impl Into<String>) -> Self {
        self.docstring = NullableField::Value(value.into());
        self
    }

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

    /// Set the `created_by_user` field.
    ///
    /// User whose API key was used to create this run. Only returned if `all` or `created_by` is included.
    pub fn created_by_user(mut self, value: impl Into<RunListCreatedByUser>) -> Self {
        self.created_by_user = NullableField::Value(value.into());
        self
    }

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

    /// Set the `created_by_station` field.
    ///
    /// Station whose API key was used to create this run. Only returned if `all` or `created_by` is included.
    pub fn created_by_station(mut self, value: impl Into<RunListCreatedByStation>) -> Self {
        self.created_by_station = NullableField::Value(value.into());
        self
    }

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

    /// Set the `operated_by` field.
    ///
    /// User who operated this run. Only returned if `all` or `operated_by` is included.
    pub fn operated_by(mut self, value: impl Into<RunListOperatedBy>) -> Self {
        self.operated_by = NullableField::Value(value.into());
        self
    }

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

    /// Set the `procedure` field.
    ///
    /// Test procedure associated with this run.
    pub fn procedure(mut self, value: impl Into<RunListProcedure>) -> Self {
        self.procedure = Some(value.into());
        self
    }

    /// Set the `unit` field.
    ///
    /// Unit under test information.
    pub fn unit(mut self, value: impl Into<RunListUnit>) -> Self {
        self.unit = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListData, String> {
        Ok(RunListData {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            created_at: self.created_at
                .ok_or_else(|| "missing required field: created_at".to_string())?,
            started_at: self.started_at
                .ok_or_else(|| "missing required field: started_at".to_string())?,
            ended_at: self.ended_at
                .ok_or_else(|| "missing required field: ended_at".to_string())?,
            duration: self.duration
                .ok_or_else(|| "missing required field: duration".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            docstring: self.docstring,
            created_by_user: self.created_by_user,
            created_by_station: self.created_by_station,
            operated_by: self.operated_by,
            procedure: self.procedure
                .ok_or_else(|| "missing required field: procedure".to_string())?,
            unit: self.unit
                .ok_or_else(|| "missing required field: unit".to_string())?,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListMeta {
    /// Whether there are more results available for pagination.
    pub has_more: bool,
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<i64>,
}

impl RunListMeta {
    /// Create a builder for this type.
    pub fn builder() -> RunListMetaBuilder {
        RunListMetaBuilder::default()
    }
}

/// Builder for [`RunListMeta`].
#[derive(Debug, Default)]
pub struct RunListMetaBuilder {
    has_more: Option<bool>,
    next_cursor: Option<i64>,
}

impl RunListMetaBuilder {
    /// Set the `has_more` field.
    ///
    /// Whether there are more results available for pagination.
    pub fn has_more(mut self, value: impl Into<bool>) -> Self {
        self.has_more = Some(value.into());
        self
    }

    /// Set the `next_cursor` field.
    ///
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    pub fn next_cursor(mut self, value: impl Into<i64>) -> Self {
        self.next_cursor = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunListMeta, String> {
        Ok(RunListMeta {
            has_more: self.has_more
                .ok_or_else(|| "missing required field: has_more".to_string())?,
            next_cursor: self.next_cursor,
        })
    }
}

/// Paginated list of test runs matching the filter criteria.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunListResponse {
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<RunListData>,
    pub meta: RunListMeta,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunDeleteRequest {
    /// Run IDs to delete.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub ids: Vec<String>,
}

impl RunDeleteRequest {
    /// Create a builder for this type.
    pub fn builder() -> RunDeleteRequestBuilder {
        RunDeleteRequestBuilder::default()
    }
}

/// Builder for [`RunDeleteRequest`].
#[derive(Debug, Default)]
pub struct RunDeleteRequestBuilder {
    ids: Option<Vec<String>>,
}

impl RunDeleteRequestBuilder {
    /// Set the `ids` field.
    ///
    /// Run IDs to delete.
    pub fn ids(mut self, value: impl Into<Vec<String>>) -> Self {
        self.ids = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunDeleteRequest, String> {
        Ok(RunDeleteRequest {
            ids: self.ids.unwrap_or_default(),
        })
    }
}

/// Response for successful run deletion
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunDeleteResponse {
    /// IDs of runs that were successfully deleted
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub id: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetRequest {
    /// ID of the run to retrieve.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

impl RunGetCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> RunGetCreatedByUserBuilder {
        RunGetCreatedByUserBuilder::default()
    }
}

/// Builder for [`RunGetCreatedByUser`].
#[derive(Debug, Default)]
pub struct RunGetCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl RunGetCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetCreatedByUser, String> {
        Ok(RunGetCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
            email: self.email,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetCreatedByStation {
    /// Station ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl RunGetCreatedByStation {
    /// Create a builder for this type.
    pub fn builder() -> RunGetCreatedByStationBuilder {
        RunGetCreatedByStationBuilder::default()
    }
}

/// Builder for [`RunGetCreatedByStation`].
#[derive(Debug, Default)]
pub struct RunGetCreatedByStationBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl RunGetCreatedByStationBuilder {
    /// Set the `id` field.
    ///
    /// Station ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetCreatedByStation, String> {
        Ok(RunGetCreatedByStation {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetOperatedBy {
    /// Operator ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub email: Option<String>,
}

impl RunGetOperatedBy {
    /// Create a builder for this type.
    pub fn builder() -> RunGetOperatedByBuilder {
        RunGetOperatedByBuilder::default()
    }
}

/// Builder for [`RunGetOperatedBy`].
#[derive(Debug, Default)]
pub struct RunGetOperatedByBuilder {
    id: Option<String>,
    name: Option<String>,
    email: Option<String>,
}

impl RunGetOperatedByBuilder {
    /// Set the `id` field.
    ///
    /// Operator ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetOperatedBy, String> {
        Ok(RunGetOperatedBy {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
            email: self.email,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetVersion {
    /// Procedure version ID.
    pub id: String,
    /// Version tag.
    pub tag: String,
}

/// Test procedure associated with this run.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetProcedure {
    /// Procedure ID.
    pub id: String,
    /// Procedure name.
    pub name: String,
    /// Version of the procedure used for this run.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub version: Option<RunGetVersion>,
}

impl RunGetProcedure {
    /// Create a builder for this type.
    pub fn builder() -> RunGetProcedureBuilder {
        RunGetProcedureBuilder::default()
    }
}

/// Builder for [`RunGetProcedure`].
#[derive(Debug, Default)]
pub struct RunGetProcedureBuilder {
    id: Option<String>,
    name: Option<String>,
    version: Option<RunGetVersion>,
}

impl RunGetProcedureBuilder {
    /// Set the `id` field.
    ///
    /// Procedure ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `version` field.
    ///
    /// Version of the procedure used for this run.
    pub fn version(mut self, value: impl Into<RunGetVersion>) -> Self {
        self.version = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetProcedure, String> {
        Ok(RunGetProcedure {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            version: self.version,
        })
    }
}

/// Revision information for this unit.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetRevision {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
}

/// Part information with revision details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetPart {
    /// Part ID.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// Revision information for this unit.
    pub revision: RunGetRevision,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetBatch {
    /// Batch ID.
    pub id: String,
    /// Batch number.
    pub number: String,
}

/// Unit under test information.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetUnit {
    /// Unit ID.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// Part information with revision details.
    pub part: RunGetPart,
    /// Batch information for this unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub batch: NullableField<RunGetBatch>,
}

impl RunGetUnit {
    /// Create a builder for this type.
    pub fn builder() -> RunGetUnitBuilder {
        RunGetUnitBuilder::default()
    }
}

/// Builder for [`RunGetUnit`].
#[derive(Debug, Default)]
pub struct RunGetUnitBuilder {
    id: Option<String>,
    serial_number: Option<String>,
    part: Option<RunGetPart>,
    batch: NullableField<RunGetBatch>,
}

impl RunGetUnitBuilder {
    /// Set the `id` field.
    ///
    /// Unit ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `part` field.
    ///
    /// Part information with revision details.
    pub fn part(mut self, value: impl Into<RunGetPart>) -> Self {
        self.part = Some(value.into());
        self
    }

    /// Set the `batch` field.
    ///
    /// Batch information for this unit.
    pub fn batch(mut self, value: impl Into<RunGetBatch>) -> Self {
        self.batch = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetUnit, String> {
        Ok(RunGetUnit {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            part: self.part
                .ok_or_else(|| "missing required field: part".to_string())?,
            batch: self.batch,
        })
    }
}

/// Validator result with outcome and comparison details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetValidators {
    /// Validation result: PASS, FAIL, or UNSET.
    pub outcome: ValidatorsOutcome,
    /// Comparison operator used for validation.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operator: Option<String>,
    /// Expected value for comparison. Type depends on measurement type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expected_value: Option<serde_json::Value>,
    /// Human-readable expression string for display.
    pub expression: String,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub is_decisive: Option<bool>,
    /// True if validator only has expression (no structured operator/expected_value).
    pub is_expression_only: bool,
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub analytics_expression: Option<String>,
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub has_custom_expression: bool,
}

impl RunGetValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunGetValidatorsBuilder {
        RunGetValidatorsBuilder::default()
    }
}

/// Builder for [`RunGetValidators`].
#[derive(Debug, Default)]
pub struct RunGetValidatorsBuilder {
    outcome: Option<ValidatorsOutcome>,
    operator: Option<String>,
    expected_value: Option<serde_json::Value>,
    expression: Option<String>,
    is_decisive: Option<bool>,
    is_expression_only: Option<bool>,
    analytics_expression: Option<String>,
    has_custom_expression: Option<bool>,
}

impl RunGetValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Validation result: PASS, FAIL, or UNSET.
    pub fn outcome(mut self, value: impl Into<ValidatorsOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on measurement type.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = Some(value.into());
        self
    }

    /// Set the `expression` field.
    ///
    /// Human-readable expression string for display.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = Some(value.into());
        self
    }

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = Some(value.into());
        self
    }

    /// Set the `is_expression_only` field.
    ///
    /// True if validator only has expression (no structured operator/expected_value).
    pub fn is_expression_only(mut self, value: impl Into<bool>) -> Self {
        self.is_expression_only = Some(value.into());
        self
    }

    /// Set the `analytics_expression` field.
    ///
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    pub fn analytics_expression(mut self, value: impl Into<String>) -> Self {
        self.analytics_expression = Some(value.into());
        self
    }

    /// Set the `has_custom_expression` field.
    ///
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub fn has_custom_expression(mut self, value: impl Into<bool>) -> Self {
        self.has_custom_expression = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetValidators, String> {
        Ok(RunGetValidators {
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression
                .ok_or_else(|| "missing required field: expression".to_string())?,
            is_decisive: self.is_decisive,
            is_expression_only: self.is_expression_only
                .ok_or_else(|| "missing required field: is_expression_only".to_string())?,
            analytics_expression: self.analytics_expression,
            has_custom_expression: self.has_custom_expression
                .ok_or_else(|| "missing required field: has_custom_expression".to_string())?,
        })
    }
}

/// Validator result with outcome and comparison details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetAggregationsValidators {
    /// Validation result: PASS, FAIL, or UNSET.
    pub outcome: ValidatorsOutcome,
    /// Comparison operator used for validation.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operator: Option<String>,
    /// Expected value for comparison. Type depends on measurement type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expected_value: Option<serde_json::Value>,
    /// Human-readable expression string for display.
    pub expression: String,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub is_decisive: Option<bool>,
    /// True if validator only has expression (no structured operator/expected_value).
    pub is_expression_only: bool,
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub analytics_expression: Option<String>,
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub has_custom_expression: bool,
}

impl RunGetAggregationsValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunGetAggregationsValidatorsBuilder {
        RunGetAggregationsValidatorsBuilder::default()
    }
}

/// Builder for [`RunGetAggregationsValidators`].
#[derive(Debug, Default)]
pub struct RunGetAggregationsValidatorsBuilder {
    outcome: Option<ValidatorsOutcome>,
    operator: Option<String>,
    expected_value: Option<serde_json::Value>,
    expression: Option<String>,
    is_decisive: Option<bool>,
    is_expression_only: Option<bool>,
    analytics_expression: Option<String>,
    has_custom_expression: Option<bool>,
}

impl RunGetAggregationsValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Validation result: PASS, FAIL, or UNSET.
    pub fn outcome(mut self, value: impl Into<ValidatorsOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on measurement type.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = Some(value.into());
        self
    }

    /// Set the `expression` field.
    ///
    /// Human-readable expression string for display.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = Some(value.into());
        self
    }

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = Some(value.into());
        self
    }

    /// Set the `is_expression_only` field.
    ///
    /// True if validator only has expression (no structured operator/expected_value).
    pub fn is_expression_only(mut self, value: impl Into<bool>) -> Self {
        self.is_expression_only = Some(value.into());
        self
    }

    /// Set the `analytics_expression` field.
    ///
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    pub fn analytics_expression(mut self, value: impl Into<String>) -> Self {
        self.analytics_expression = Some(value.into());
        self
    }

    /// Set the `has_custom_expression` field.
    ///
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub fn has_custom_expression(mut self, value: impl Into<bool>) -> Self {
        self.has_custom_expression = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetAggregationsValidators, String> {
        Ok(RunGetAggregationsValidators {
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression
                .ok_or_else(|| "missing required field: expression".to_string())?,
            is_decisive: self.is_decisive,
            is_expression_only: self.is_expression_only
                .ok_or_else(|| "missing required field: is_expression_only".to_string())?,
            analytics_expression: self.analytics_expression,
            has_custom_expression: self.has_custom_expression
                .ok_or_else(|| "missing required field: has_custom_expression".to_string())?,
        })
    }
}

/// Aggregation result with computed value and optional validators.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetAggregations {
    /// Unique identifier for the aggregation.
    pub id: String,
    /// Aggregation type (e.g., MIN, MAX, MEAN, RANGE, STD_DEV).
    #[serde(rename = "type")]
    pub r#type: String,
    /// Aggregation validation result: PASS, FAIL, UNSET, or null if no validators.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub outcome: Option<String>,
    /// Computed aggregation value. Type depends on aggregation type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub value: Option<serde_json::Value>,
    /// Unit of measurement for the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub unit: NullableField<String>,
    /// Validators applied to the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunGetAggregationsValidators>>,
}

impl RunGetAggregations {
    /// Create a builder for this type.
    pub fn builder() -> RunGetAggregationsBuilder {
        RunGetAggregationsBuilder::default()
    }
}

/// Builder for [`RunGetAggregations`].
#[derive(Debug, Default)]
pub struct RunGetAggregationsBuilder {
    id: Option<String>,
    r#type: Option<String>,
    outcome: Option<String>,
    value: Option<serde_json::Value>,
    unit: NullableField<String>,
    validators: NullableField<Vec<RunGetAggregationsValidators>>,
}

impl RunGetAggregationsBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the aggregation.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `type` field.
    ///
    /// Aggregation type (e.g., MIN, MAX, MEAN, RANGE, STD_DEV).
    pub fn r#type(mut self, value: impl Into<String>) -> Self {
        self.r#type = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Aggregation validation result: PASS, FAIL, UNSET, or null if no validators.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `value` field.
    ///
    /// Computed aggregation value. Type depends on aggregation type.
    pub fn value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.value = Some(value.into());
        self
    }

    /// Set the `unit` field.
    ///
    /// Unit of measurement for the aggregated value.
    pub fn unit(mut self, value: impl Into<String>) -> Self {
        self.unit = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators applied to the aggregated value.
    pub fn validators(mut self, value: impl Into<Vec<RunGetAggregationsValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetAggregations, String> {
        Ok(RunGetAggregations {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            r#type: self.r#type
                .ok_or_else(|| "missing required field: type".to_string())?,
            outcome: self.outcome,
            value: self.value,
            unit: self.unit,
            validators: self.validators,
        })
    }
}

/// Validator result with outcome and comparison details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetDataSeriesValidators {
    /// Validation result: PASS, FAIL, or UNSET.
    pub outcome: ValidatorsOutcome,
    /// Comparison operator used for validation.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operator: Option<String>,
    /// Expected value for comparison. Type depends on measurement type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expected_value: Option<serde_json::Value>,
    /// Human-readable expression string for display.
    pub expression: String,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub is_decisive: Option<bool>,
    /// True if validator only has expression (no structured operator/expected_value).
    pub is_expression_only: bool,
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub analytics_expression: Option<String>,
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub has_custom_expression: bool,
}

impl RunGetDataSeriesValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunGetDataSeriesValidatorsBuilder {
        RunGetDataSeriesValidatorsBuilder::default()
    }
}

/// Builder for [`RunGetDataSeriesValidators`].
#[derive(Debug, Default)]
pub struct RunGetDataSeriesValidatorsBuilder {
    outcome: Option<ValidatorsOutcome>,
    operator: Option<String>,
    expected_value: Option<serde_json::Value>,
    expression: Option<String>,
    is_decisive: Option<bool>,
    is_expression_only: Option<bool>,
    analytics_expression: Option<String>,
    has_custom_expression: Option<bool>,
}

impl RunGetDataSeriesValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Validation result: PASS, FAIL, or UNSET.
    pub fn outcome(mut self, value: impl Into<ValidatorsOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on measurement type.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = Some(value.into());
        self
    }

    /// Set the `expression` field.
    ///
    /// Human-readable expression string for display.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = Some(value.into());
        self
    }

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = Some(value.into());
        self
    }

    /// Set the `is_expression_only` field.
    ///
    /// True if validator only has expression (no structured operator/expected_value).
    pub fn is_expression_only(mut self, value: impl Into<bool>) -> Self {
        self.is_expression_only = Some(value.into());
        self
    }

    /// Set the `analytics_expression` field.
    ///
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    pub fn analytics_expression(mut self, value: impl Into<String>) -> Self {
        self.analytics_expression = Some(value.into());
        self
    }

    /// Set the `has_custom_expression` field.
    ///
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub fn has_custom_expression(mut self, value: impl Into<bool>) -> Self {
        self.has_custom_expression = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetDataSeriesValidators, String> {
        Ok(RunGetDataSeriesValidators {
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression
                .ok_or_else(|| "missing required field: expression".to_string())?,
            is_decisive: self.is_decisive,
            is_expression_only: self.is_expression_only
                .ok_or_else(|| "missing required field: is_expression_only".to_string())?,
            analytics_expression: self.analytics_expression,
            has_custom_expression: self.has_custom_expression
                .ok_or_else(|| "missing required field: has_custom_expression".to_string())?,
        })
    }
}

/// Validator result with outcome and comparison details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetDataSeriesAggregationsValidators {
    /// Validation result: PASS, FAIL, or UNSET.
    pub outcome: ValidatorsOutcome,
    /// Comparison operator used for validation.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub operator: Option<String>,
    /// Expected value for comparison. Type depends on measurement type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub expected_value: Option<serde_json::Value>,
    /// Human-readable expression string for display.
    pub expression: String,
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub is_decisive: Option<bool>,
    /// True if validator only has expression (no structured operator/expected_value).
    pub is_expression_only: bool,
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub analytics_expression: Option<String>,
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub has_custom_expression: bool,
}

impl RunGetDataSeriesAggregationsValidators {
    /// Create a builder for this type.
    pub fn builder() -> RunGetDataSeriesAggregationsValidatorsBuilder {
        RunGetDataSeriesAggregationsValidatorsBuilder::default()
    }
}

/// Builder for [`RunGetDataSeriesAggregationsValidators`].
#[derive(Debug, Default)]
pub struct RunGetDataSeriesAggregationsValidatorsBuilder {
    outcome: Option<ValidatorsOutcome>,
    operator: Option<String>,
    expected_value: Option<serde_json::Value>,
    expression: Option<String>,
    is_decisive: Option<bool>,
    is_expression_only: Option<bool>,
    analytics_expression: Option<String>,
    has_custom_expression: Option<bool>,
}

impl RunGetDataSeriesAggregationsValidatorsBuilder {
    /// Set the `outcome` field.
    ///
    /// Validation result: PASS, FAIL, or UNSET.
    pub fn outcome(mut self, value: impl Into<ValidatorsOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

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

    /// Set the `expected_value` field.
    ///
    /// Expected value for comparison. Type depends on measurement type.
    pub fn expected_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.expected_value = Some(value.into());
        self
    }

    /// Set the `expression` field.
    ///
    /// Human-readable expression string for display.
    pub fn expression(mut self, value: impl Into<String>) -> Self {
        self.expression = Some(value.into());
        self
    }

    /// Set the `is_decisive` field.
    ///
    /// Whether this validator is decisive (if it fails, measurement fails). False for marginal/warning validators.
    pub fn is_decisive(mut self, value: impl Into<bool>) -> Self {
        self.is_decisive = Some(value.into());
        self
    }

    /// Set the `is_expression_only` field.
    ///
    /// True if validator only has expression (no structured operator/expected_value).
    pub fn is_expression_only(mut self, value: impl Into<bool>) -> Self {
        self.is_expression_only = Some(value.into());
        self
    }

    /// Set the `analytics_expression` field.
    ///
    /// Synthetic expression from operator+expected_value for analytics tooltip. Null if expression-only.
    pub fn analytics_expression(mut self, value: impl Into<String>) -> Self {
        self.analytics_expression = Some(value.into());
        self
    }

    /// Set the `has_custom_expression` field.
    ///
    /// True if user provided a custom expression (shown in italic with analytics tooltip).
    pub fn has_custom_expression(mut self, value: impl Into<bool>) -> Self {
        self.has_custom_expression = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetDataSeriesAggregationsValidators, String> {
        Ok(RunGetDataSeriesAggregationsValidators {
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            operator: self.operator,
            expected_value: self.expected_value,
            expression: self.expression
                .ok_or_else(|| "missing required field: expression".to_string())?,
            is_decisive: self.is_decisive,
            is_expression_only: self.is_expression_only
                .ok_or_else(|| "missing required field: is_expression_only".to_string())?,
            analytics_expression: self.analytics_expression,
            has_custom_expression: self.has_custom_expression
                .ok_or_else(|| "missing required field: has_custom_expression".to_string())?,
        })
    }
}

/// Aggregation result with computed value and optional validators.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetDataSeriesAggregations {
    /// Unique identifier for the aggregation.
    pub id: String,
    /// Aggregation type (e.g., MIN, MAX, MEAN, RANGE, STD_DEV).
    #[serde(rename = "type")]
    pub r#type: String,
    /// Aggregation validation result: PASS, FAIL, UNSET, or null if no validators.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub outcome: Option<String>,
    /// Computed aggregation value. Type depends on aggregation type.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub value: Option<serde_json::Value>,
    /// Unit of measurement for the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub unit: NullableField<String>,
    /// Validators applied to the aggregated value.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunGetDataSeriesAggregationsValidators>>,
}

impl RunGetDataSeriesAggregations {
    /// Create a builder for this type.
    pub fn builder() -> RunGetDataSeriesAggregationsBuilder {
        RunGetDataSeriesAggregationsBuilder::default()
    }
}

/// Builder for [`RunGetDataSeriesAggregations`].
#[derive(Debug, Default)]
pub struct RunGetDataSeriesAggregationsBuilder {
    id: Option<String>,
    r#type: Option<String>,
    outcome: Option<String>,
    value: Option<serde_json::Value>,
    unit: NullableField<String>,
    validators: NullableField<Vec<RunGetDataSeriesAggregationsValidators>>,
}

impl RunGetDataSeriesAggregationsBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the aggregation.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `type` field.
    ///
    /// Aggregation type (e.g., MIN, MAX, MEAN, RANGE, STD_DEV).
    pub fn r#type(mut self, value: impl Into<String>) -> Self {
        self.r#type = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Aggregation validation result: PASS, FAIL, UNSET, or null if no validators.
    pub fn outcome(mut self, value: impl Into<String>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `value` field.
    ///
    /// Computed aggregation value. Type depends on aggregation type.
    pub fn value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.value = Some(value.into());
        self
    }

    /// Set the `unit` field.
    ///
    /// Unit of measurement for the aggregated value.
    pub fn unit(mut self, value: impl Into<String>) -> Self {
        self.unit = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators applied to the aggregated value.
    pub fn validators(mut self, value: impl Into<Vec<RunGetDataSeriesAggregationsValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetDataSeriesAggregations, String> {
        Ok(RunGetDataSeriesAggregations {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            r#type: self.r#type
                .ok_or_else(|| "missing required field: type".to_string())?,
            outcome: self.outcome,
            value: self.value,
            unit: self.unit,
            validators: self.validators,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetDataSeries {
    /// Array of numeric data points for this series.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<f64>,
    /// Unit for this data series.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub units: Option<String>,
    /// Name of this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub name: NullableField<String>,
    /// Description of this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub description: NullableField<String>,
    /// Validators for this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub validators: NullableField<Vec<RunGetDataSeriesValidators>>,
    /// Aggregations computed over this data series.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub aggregations: NullableField<Vec<RunGetDataSeriesAggregations>>,
}

impl RunGetDataSeries {
    /// Create a builder for this type.
    pub fn builder() -> RunGetDataSeriesBuilder {
        RunGetDataSeriesBuilder::default()
    }
}

/// Builder for [`RunGetDataSeries`].
#[derive(Debug, Default)]
pub struct RunGetDataSeriesBuilder {
    data: Option<Vec<f64>>,
    units: Option<String>,
    name: NullableField<String>,
    description: NullableField<String>,
    validators: NullableField<Vec<RunGetDataSeriesValidators>>,
    aggregations: NullableField<Vec<RunGetDataSeriesAggregations>>,
}

impl RunGetDataSeriesBuilder {
    /// Set the `data` field.
    ///
    /// Array of numeric data points for this series.
    pub fn data(mut self, value: impl Into<Vec<f64>>) -> Self {
        self.data = Some(value.into());
        self
    }

    /// Set the `units` field.
    ///
    /// Unit for this data series.
    pub fn units(mut self, value: impl Into<String>) -> Self {
        self.units = Some(value.into());
        self
    }

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

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

    /// Set the `description` field.
    ///
    /// Description of this data series.
    pub fn description(mut self, value: impl Into<String>) -> Self {
        self.description = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Validators for this data series.
    pub fn validators(mut self, value: impl Into<Vec<RunGetDataSeriesValidators>>) -> Self {
        self.validators = NullableField::Value(value.into());
        self
    }

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

    /// Set the `aggregations` field.
    ///
    /// Aggregations computed over this data series.
    pub fn aggregations(mut self, value: impl Into<Vec<RunGetDataSeriesAggregations>>) -> Self {
        self.aggregations = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetDataSeries, String> {
        Ok(RunGetDataSeries {
            data: self.data.unwrap_or_default(),
            units: self.units,
            name: self.name,
            description: self.description,
            validators: self.validators,
            aggregations: self.aggregations,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetMeasurements {
    /// Measurement ID.
    pub id: String,
    /// Measurement name.
    pub name: String,
    /// Measurement validation result.
    pub outcome: ValidatorsOutcome,
    /// Units of measurement. Not present for multi-dimensional measurements (units are per data series).
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub units: NullableField<String>,
    /// Structured validation rules with outcome and expected values.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub validators: Option<Vec<RunGetValidators>>,
    /// Aggregations computed over this measurement.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub aggregations: NullableField<Vec<RunGetAggregations>>,
    /// The actual measured value.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub measured_value: Option<serde_json::Value>,
    /// Multi-dimensional measurement data series.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub data_series: Option<Vec<RunGetDataSeries>>,
}

impl RunGetMeasurements {
    /// Create a builder for this type.
    pub fn builder() -> RunGetMeasurementsBuilder {
        RunGetMeasurementsBuilder::default()
    }
}

/// Builder for [`RunGetMeasurements`].
#[derive(Debug, Default)]
pub struct RunGetMeasurementsBuilder {
    id: Option<String>,
    name: Option<String>,
    outcome: Option<ValidatorsOutcome>,
    units: NullableField<String>,
    validators: Option<Vec<RunGetValidators>>,
    aggregations: NullableField<Vec<RunGetAggregations>>,
    measured_value: Option<serde_json::Value>,
    data_series: Option<Vec<RunGetDataSeries>>,
}

impl RunGetMeasurementsBuilder {
    /// Set the `id` field.
    ///
    /// Measurement ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `outcome` field.
    ///
    /// Measurement validation result.
    pub fn outcome(mut self, value: impl Into<ValidatorsOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `units` field.
    ///
    /// Units of measurement. Not present for multi-dimensional measurements (units are per data series).
    pub fn units(mut self, value: impl Into<String>) -> Self {
        self.units = NullableField::Value(value.into());
        self
    }

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

    /// Set the `validators` field.
    ///
    /// Structured validation rules with outcome and expected values.
    pub fn validators(mut self, value: impl Into<Vec<RunGetValidators>>) -> Self {
        self.validators = Some(value.into());
        self
    }

    /// Set the `aggregations` field.
    ///
    /// Aggregations computed over this measurement.
    pub fn aggregations(mut self, value: impl Into<Vec<RunGetAggregations>>) -> Self {
        self.aggregations = NullableField::Value(value.into());
        self
    }

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

    /// Set the `measured_value` field.
    ///
    /// The actual measured value.
    pub fn measured_value(mut self, value: impl Into<serde_json::Value>) -> Self {
        self.measured_value = Some(value.into());
        self
    }

    /// Set the `data_series` field.
    ///
    /// Multi-dimensional measurement data series.
    pub fn data_series(mut self, value: impl Into<Vec<RunGetDataSeries>>) -> Self {
        self.data_series = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetMeasurements, String> {
        Ok(RunGetMeasurements {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            units: self.units,
            validators: self.validators,
            aggregations: self.aggregations,
            measured_value: self.measured_value,
            data_series: self.data_series,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetPhases {
    /// Phase ID.
    pub id: String,
    /// Phase name.
    pub name: String,
    /// Phase execution result.
    pub outcome: PhasesOutcome,
    /// ISO 8601 timestamp when the phase started.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the phase ended.
    pub ended_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 duration of the phase (computed from started_at and ended_at).
    pub duration: String,
    /// Zero-based retry attempt index. 0 = first attempt, 1 = first retry, etc.
    pub retry_count: i64,
    /// True when the phase was marked as expected-to-fail by the test framework (pytest @pytest.mark.xfail).
    #[serde(default)]
    pub expected_to_fail: bool,
    /// Phase documentation string.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub docstring: NullableField<String>,
    /// Array of measurements taken during this phase.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub measurements: Vec<RunGetMeasurements>,
}

impl RunGetPhases {
    /// Create a builder for this type.
    pub fn builder() -> RunGetPhasesBuilder {
        RunGetPhasesBuilder::default()
    }
}

/// Builder for [`RunGetPhases`].
#[derive(Debug, Default)]
pub struct RunGetPhasesBuilder {
    id: Option<String>,
    name: Option<String>,
    outcome: Option<PhasesOutcome>,
    started_at: Option<chrono::DateTime<chrono::Utc>>,
    ended_at: Option<chrono::DateTime<chrono::Utc>>,
    duration: Option<String>,
    retry_count: Option<i64>,
    expected_to_fail: Option<bool>,
    docstring: NullableField<String>,
    measurements: Option<Vec<RunGetMeasurements>>,
}

impl RunGetPhasesBuilder {
    /// Set the `id` field.
    ///
    /// Phase ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `outcome` field.
    ///
    /// Phase execution result.
    pub fn outcome(mut self, value: impl Into<PhasesOutcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `started_at` field.
    ///
    /// ISO 8601 timestamp when the phase started.
    pub fn started_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.started_at = Some(value.into());
        self
    }

    /// Set the `ended_at` field.
    ///
    /// ISO 8601 timestamp when the phase ended.
    pub fn ended_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.ended_at = Some(value.into());
        self
    }

    /// Set the `duration` field.
    ///
    /// ISO 8601 duration of the phase (computed from started_at and ended_at).
    pub fn duration(mut self, value: impl Into<String>) -> Self {
        self.duration = Some(value.into());
        self
    }

    /// Set the `retry_count` field.
    ///
    /// Zero-based retry attempt index. 0 = first attempt, 1 = first retry, etc.
    pub fn retry_count(mut self, value: impl Into<i64>) -> Self {
        self.retry_count = Some(value.into());
        self
    }

    /// Set the `expected_to_fail` field.
    ///
    /// True when the phase was marked as expected-to-fail by the test framework (pytest @pytest.mark.xfail).
    pub fn expected_to_fail(mut self, value: impl Into<bool>) -> Self {
        self.expected_to_fail = Some(value.into());
        self
    }

    /// Set the `docstring` field.
    ///
    /// Phase documentation string.
    pub fn docstring(mut self, value: impl Into<String>) -> Self {
        self.docstring = NullableField::Value(value.into());
        self
    }

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

    /// Set the `measurements` field.
    ///
    /// Array of measurements taken during this phase.
    pub fn measurements(mut self, value: impl Into<Vec<RunGetMeasurements>>) -> Self {
        self.measurements = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetPhases, String> {
        Ok(RunGetPhases {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            started_at: self.started_at
                .ok_or_else(|| "missing required field: started_at".to_string())?,
            ended_at: self.ended_at
                .ok_or_else(|| "missing required field: ended_at".to_string())?,
            duration: self.duration
                .ok_or_else(|| "missing required field: duration".to_string())?,
            retry_count: self.retry_count
                .ok_or_else(|| "missing required field: retry_count".to_string())?,
            expected_to_fail: self.expected_to_fail.unwrap_or(false),
            docstring: self.docstring,
            measurements: self.measurements.unwrap_or_default(),
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetAttachments {
    /// Attachment ID.
    pub id: String,
    /// File name.
    pub name: String,
    /// File size in bytes.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub size: Option<f64>,
    /// MIME type of the file.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub content_type: Option<String>,
    /// Whether this attachment is a test report (from file import) or a regular attachment.
    pub is_report: bool,
    /// Presigned URL for downloading the file. This URL is temporary and will expire.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub download_url: NullableField<String>,
}

impl RunGetAttachments {
    /// Create a builder for this type.
    pub fn builder() -> RunGetAttachmentsBuilder {
        RunGetAttachmentsBuilder::default()
    }
}

/// Builder for [`RunGetAttachments`].
#[derive(Debug, Default)]
pub struct RunGetAttachmentsBuilder {
    id: Option<String>,
    name: Option<String>,
    size: Option<f64>,
    content_type: Option<String>,
    is_report: Option<bool>,
    download_url: NullableField<String>,
}

impl RunGetAttachmentsBuilder {
    /// Set the `id` field.
    ///
    /// Attachment ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `size` field.
    ///
    /// File size in bytes.
    pub fn size(mut self, value: impl Into<f64>) -> Self {
        self.size = Some(value.into());
        self
    }

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

    /// Set the `is_report` field.
    ///
    /// Whether this attachment is a test report (from file import) or a regular attachment.
    pub fn is_report(mut self, value: impl Into<bool>) -> Self {
        self.is_report = Some(value.into());
        self
    }

    /// Set the `download_url` field.
    ///
    /// Presigned URL for downloading the file. This URL is temporary and will expire.
    pub fn download_url(mut self, value: impl Into<String>) -> Self {
        self.download_url = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetAttachments, String> {
        Ok(RunGetAttachments {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            size: self.size,
            content_type: self.content_type,
            is_report: self.is_report
                .ok_or_else(|| "missing required field: is_report".to_string())?,
            download_url: self.download_url,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetLogs {
    pub id: String,
    pub level: Level,
    pub timestamp: chrono::DateTime<chrono::Utc>,
    pub message: String,
    pub source_file: String,
    pub line_number: i64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetSubUnits {
    /// Unit ID.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// Part number of the sub-unit.
    pub part_number: String,
    /// Part name of the sub-unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part_name: Option<String>,
}

impl RunGetSubUnits {
    /// Create a builder for this type.
    pub fn builder() -> RunGetSubUnitsBuilder {
        RunGetSubUnitsBuilder::default()
    }
}

/// Builder for [`RunGetSubUnits`].
#[derive(Debug, Default)]
pub struct RunGetSubUnitsBuilder {
    id: Option<String>,
    serial_number: Option<String>,
    part_number: Option<String>,
    part_name: Option<String>,
}

impl RunGetSubUnitsBuilder {
    /// Set the `id` field.
    ///
    /// Unit ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `part_number` field.
    ///
    /// Part number of the sub-unit.
    pub fn part_number(mut self, value: impl Into<String>) -> Self {
        self.part_number = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunGetSubUnits, String> {
        Ok(RunGetSubUnits {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            part_number: self.part_number
                .ok_or_else(|| "missing required field: part_number".to_string())?,
            part_name: self.part_name,
        })
    }
}

/// Single test run details.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunGetResponse {
    /// Unique identifier for the run.
    pub id: String,
    /// ISO 8601 timestamp when the run was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run execution started.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run execution ended.
    pub ended_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 duration of the run (computed from started_at and ended_at).
    pub duration: String,
    /// Final result of the run execution.
    pub outcome: Outcome,
    /// Additional notes or documentation about this test run.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub docstring: NullableField<String>,
    /// User whose API key was used to create this run. Only returned if `all` or `created_by` is included.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<RunGetCreatedByUser>,
    /// Station whose API key was used to create this run. Only returned if `all` or `created_by` is included.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<RunGetCreatedByStation>,
    /// User who operated this run. Only returned if `all` or `operated_by` is included.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub operated_by: NullableField<RunGetOperatedBy>,
    /// Test procedure associated with this run.
    pub procedure: RunGetProcedure,
    /// Unit under test information.
    pub unit: RunGetUnit,
    /// Array of execution phases in this run. Only returned if `all` or `phases` is included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub phases: Option<Vec<RunGetPhases>>,
    /// Files attached to this run, including both regular attachments and test reports. Only returned if `all` or `attachments` is included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<RunGetAttachments>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub logs: Option<Vec<RunGetLogs>>,
    /// Array of sub-units that had parent changes during this run. Only returned if `all` or `sub_units` is included.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sub_units: Option<Vec<RunGetSubUnits>>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct RunUpdateRequestBody {
    /// Array of upload IDs to attach to the run.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<String>>,
}

impl RunUpdateRequestBody {
    /// Create a builder for this type.
    pub fn builder() -> RunUpdateRequestBodyBuilder {
        RunUpdateRequestBodyBuilder::default()
    }
}

/// Builder for [`RunUpdateRequestBody`].
#[derive(Debug, Default)]
pub struct RunUpdateRequestBodyBuilder {
    attachments: Option<Vec<String>>,
}

impl RunUpdateRequestBodyBuilder {
    /// Set the `attachments` field.
    ///
    /// Array of upload IDs to attach to the run.
    pub fn attachments(mut self, value: impl Into<Vec<String>>) -> Self {
        self.attachments = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<RunUpdateRequestBody, String> {
        Ok(RunUpdateRequestBody {
            attachments: self.attachments,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunUpdateRequest {
    /// Unique identifier of the run to update.
    pub id: String,
    pub request_body: RunUpdateRequestBody,
}

/// Run attachments updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunUpdateResponse {
    /// Unique identifier of the updated run.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateAttachmentRequestBody {
    /// File name including extension (e.g. "report.pdf"). Used to determine content type and display name.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateAttachmentRequest {
    /// Unique identifier of the run to attach the file to.
    pub id: String,
    pub request_body: RunCreateAttachmentRequestBody,
}

/// Run attachment created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct RunCreateAttachmentResponse {
    /// Unique identifier of the created attachment. Use this to reference the attachment in subsequent API calls.
    pub id: String,
    /// Temporary pre-signed URL to upload the file directly to storage. Send a PUT request with the raw file bytes and appropriate Content-Type header. The URL expires after 60 seconds.
    pub upload_url: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttachmentInitializeRequest {
    /// File name including extension (e.g. "report.pdf")
    pub name: String,
}

/// Upload URL generated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttachmentInitializeResponse {
    /// ID of the created upload
    pub id: String,
    /// Pre-signed URL to upload the file directly to S3
    pub upload_url: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttachmentFinalizeRequest {
    /// ID of the upload to finalize
    pub id: String,
}

/// Upload metadata updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AttachmentFinalizeResponse {
    /// Signed URL for accessing the uploaded file
    pub url: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitCreateRequest {
    /// Unique serial number identifier for the unit. Must be unique within the organization.
    pub serial_number: String,
    /// Component part number that defines what type of unit this is. If the part does not exist, it will be created.
    pub part_number: String,
    /// Hardware revision identifier for the specific version of the part. If the revision does not exist, it will be created.
    pub revision_number: String,
}

/// Unit created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitCreateResponse {
    /// Unique identifier for the created unit.
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct UnitListRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub serial_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub batch_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure_ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub outcomes: Option<Vec<Outcome>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub started_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub started_before: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub latest_only: Option<bool>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub run_count_min: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub run_count_max: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_before: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_user_ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_station_ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub exclude_units_with_parent: Option<bool>,
    /// Maximum number of units to return.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cursor: Option<i64>,
    /// Field to sort results by. last_run_at sorts by most recent test run date. last_run_procedure sorts by procedure name of the last run.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_by: Option<UnitListSortBy>,
    /// Sort order direction.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_order: Option<ListSortOrder>,
}

impl UnitListRequest {
    /// Create a builder for this type.
    pub fn builder() -> UnitListRequestBuilder {
        UnitListRequestBuilder::default()
    }
}

/// Builder for [`UnitListRequest`].
#[derive(Debug, Default)]
pub struct UnitListRequestBuilder {
    search_query: Option<String>,
    ids: Option<Vec<String>>,
    serial_numbers: Option<Vec<String>>,
    part_numbers: Option<Vec<String>>,
    revision_numbers: Option<Vec<String>>,
    batch_numbers: Option<Vec<String>>,
    procedure_ids: Option<Vec<String>>,
    outcomes: Option<Vec<Outcome>>,
    started_after: Option<chrono::DateTime<chrono::Utc>>,
    started_before: Option<chrono::DateTime<chrono::Utc>>,
    latest_only: Option<bool>,
    run_count_min: Option<i64>,
    run_count_max: Option<i64>,
    created_after: Option<chrono::DateTime<chrono::Utc>>,
    created_before: Option<chrono::DateTime<chrono::Utc>>,
    created_by_user_ids: Option<Vec<String>>,
    created_by_station_ids: Option<Vec<String>>,
    exclude_units_with_parent: Option<bool>,
    limit: Option<i64>,
    cursor: Option<i64>,
    sort_by: Option<UnitListSortBy>,
    sort_order: Option<ListSortOrder>,
}

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

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

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

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

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

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

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

    /// Set the `outcomes` field.
    pub fn outcomes(mut self, value: impl Into<Vec<Outcome>>) -> Self {
        self.outcomes = Some(value.into());
        self
    }

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

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

    /// Set the `latest_only` field.
    pub fn latest_only(mut self, value: impl Into<bool>) -> Self {
        self.latest_only = Some(value.into());
        self
    }

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

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

    /// Set the `created_after` field.
    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` field.
    pub fn created_before(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_before = Some(value.into());
        self
    }

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

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

    /// Set the `exclude_units_with_parent` field.
    pub fn exclude_units_with_parent(mut self, value: impl Into<bool>) -> Self {
        self.exclude_units_with_parent = Some(value.into());
        self
    }

    /// Set the `limit` field.
    ///
    /// Maximum number of units to return.
    pub fn limit(mut self, value: impl Into<i64>) -> Self {
        self.limit = Some(value.into());
        self
    }

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

    /// Set the `sort_by` field.
    ///
    /// Field to sort results by. last_run_at sorts by most recent test run date. last_run_procedure sorts by procedure name of the last run.
    pub fn sort_by(mut self, value: impl Into<UnitListSortBy>) -> Self {
        self.sort_by = Some(value.into());
        self
    }

    /// Set the `sort_order` field.
    ///
    /// Sort order direction.
    pub fn sort_order(mut self, value: impl Into<ListSortOrder>) -> Self {
        self.sort_order = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitListRequest, String> {
        Ok(UnitListRequest {
            search_query: self.search_query,
            ids: self.ids,
            serial_numbers: self.serial_numbers,
            part_numbers: self.part_numbers,
            revision_numbers: self.revision_numbers,
            batch_numbers: self.batch_numbers,
            procedure_ids: self.procedure_ids,
            outcomes: self.outcomes,
            started_after: self.started_after,
            started_before: self.started_before,
            latest_only: self.latest_only,
            run_count_min: self.run_count_min,
            run_count_max: self.run_count_max,
            created_after: self.created_after,
            created_before: self.created_before,
            created_by_user_ids: self.created_by_user_ids,
            created_by_station_ids: self.created_by_station_ids,
            exclude_units_with_parent: self.exclude_units_with_parent,
            limit: self.limit,
            cursor: self.cursor,
            sort_by: self.sort_by,
            sort_order: self.sort_order,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListCreatedByUser {
    /// Unique identifier for the user.
    pub id: String,
    /// Display name of the user who created this unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl UnitListCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> UnitListCreatedByUserBuilder {
        UnitListCreatedByUserBuilder::default()
    }
}

/// Builder for [`UnitListCreatedByUser`].
#[derive(Debug, Default)]
pub struct UnitListCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl UnitListCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the user.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `name` field.
    ///
    /// Display name of the user who created this unit.
    pub fn name(mut self, value: impl Into<String>) -> Self {
        self.name = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitListCreatedByUser, String> {
        Ok(UnitListCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListCreatedByStation {
    /// Unique identifier for the station.
    pub id: String,
    /// Name of the station that created this unit.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListBatch {
    /// Unique identifier for the batch.
    pub id: String,
    /// Human-readable batch number.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListParent {
    /// Unique identifier for the parent unit.
    pub id: String,
    /// Serial number of the parent unit.
    pub serial_number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListChildren {
    /// Unique identifier for the child unit.
    pub id: String,
    /// Serial number of the child unit.
    pub serial_number: String,
}

/// Revision information for this part. Every unit must have a specific revision.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListRevision {
    /// Unique identifier for the revision.
    pub id: String,
    /// Revision number (e.g., version) of the part.
    pub number: String,
}

/// Part information with the specific revision this unit is built from.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListPart {
    /// Unique identifier for the part.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Human-readable part name.
    pub name: String,
    /// Revision information for this part. Every unit must have a specific revision.
    pub revision: UnitListRevision,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListProcedure {
    /// Unique identifier for the procedure.
    pub id: String,
    /// Name of the test procedure that was executed.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListLastRun {
    /// Unique identifier for the run.
    pub id: String,
    /// Final result of the test run execution.
    pub outcome: Outcome,
    /// ISO 8601 timestamp when the run execution started.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run execution completed. Null if still running.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub ended_at: Option<chrono::DateTime<chrono::Utc>>,
    /// Test procedure that was executed. Null if run had no associated procedure.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure: Option<UnitListProcedure>,
}

impl UnitListLastRun {
    /// Create a builder for this type.
    pub fn builder() -> UnitListLastRunBuilder {
        UnitListLastRunBuilder::default()
    }
}

/// Builder for [`UnitListLastRun`].
#[derive(Debug, Default)]
pub struct UnitListLastRunBuilder {
    id: Option<String>,
    outcome: Option<Outcome>,
    started_at: Option<chrono::DateTime<chrono::Utc>>,
    ended_at: Option<chrono::DateTime<chrono::Utc>>,
    procedure: Option<UnitListProcedure>,
}

impl UnitListLastRunBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the run.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `outcome` field.
    ///
    /// Final result of the test run execution.
    pub fn outcome(mut self, value: impl Into<Outcome>) -> Self {
        self.outcome = Some(value.into());
        self
    }

    /// Set the `started_at` field.
    ///
    /// ISO 8601 timestamp when the run execution started.
    pub fn started_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.started_at = Some(value.into());
        self
    }

    /// Set the `ended_at` field.
    ///
    /// ISO 8601 timestamp when the run execution completed. Null if still running.
    pub fn ended_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.ended_at = Some(value.into());
        self
    }

    /// Set the `procedure` field.
    ///
    /// Test procedure that was executed. Null if run had no associated procedure.
    pub fn procedure(mut self, value: impl Into<UnitListProcedure>) -> Self {
        self.procedure = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitListLastRun, String> {
        Ok(UnitListLastRun {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            outcome: self.outcome
                .ok_or_else(|| "missing required field: outcome".to_string())?,
            started_at: self.started_at
                .ok_or_else(|| "missing required field: started_at".to_string())?,
            ended_at: self.ended_at,
            procedure: self.procedure,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListData {
    /// Unique identifier for the unit.
    pub id: String,
    /// Human-readable serial number assigned to the unit.
    pub serial_number: String,
    /// ISO 8601 timestamp when the unit was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this unit. Null if created by a station or system.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<UnitListCreatedByUser>,
    /// Station that created this unit. Null if created by a user.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<UnitListCreatedByStation>,
    /// Production batch this unit belongs to. Null if not part of a batch.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub batch: NullableField<UnitListBatch>,
    /// Parent unit in the assembly hierarchy. Null if this is a top-level unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub parent: NullableField<UnitListParent>,
    /// Child units assembled into this unit. Limited to 10 results; use Get Unit endpoint for complete list.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub children: Vec<UnitListChildren>,
    /// Part information with the specific revision this unit is built from.
    pub part: UnitListPart,
    /// Most recent test run performed on this unit. Null if no runs have been executed.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub last_run: NullableField<UnitListLastRun>,
}

impl UnitListData {
    /// Create a builder for this type.
    pub fn builder() -> UnitListDataBuilder {
        UnitListDataBuilder::default()
    }
}

/// Builder for [`UnitListData`].
#[derive(Debug, Default)]
pub struct UnitListDataBuilder {
    id: Option<String>,
    serial_number: Option<String>,
    created_at: Option<chrono::DateTime<chrono::Utc>>,
    created_by_user: NullableField<UnitListCreatedByUser>,
    created_by_station: NullableField<UnitListCreatedByStation>,
    batch: NullableField<UnitListBatch>,
    parent: NullableField<UnitListParent>,
    children: Option<Vec<UnitListChildren>>,
    part: Option<UnitListPart>,
    last_run: NullableField<UnitListLastRun>,
}

impl UnitListDataBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier for the unit.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

    /// Set the `serial_number` field.
    ///
    /// Human-readable serial number assigned to the unit.
    pub fn serial_number(mut self, value: impl Into<String>) -> Self {
        self.serial_number = Some(value.into());
        self
    }

    /// Set the `created_at` field.
    ///
    /// ISO 8601 timestamp when the unit was created.
    pub fn created_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_at = Some(value.into());
        self
    }

    /// Set the `created_by_user` field.
    ///
    /// User who created this unit. Null if created by a station or system.
    pub fn created_by_user(mut self, value: impl Into<UnitListCreatedByUser>) -> Self {
        self.created_by_user = NullableField::Value(value.into());
        self
    }

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

    /// Set the `created_by_station` field.
    ///
    /// Station that created this unit. Null if created by a user.
    pub fn created_by_station(mut self, value: impl Into<UnitListCreatedByStation>) -> Self {
        self.created_by_station = NullableField::Value(value.into());
        self
    }

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

    /// Set the `batch` field.
    ///
    /// Production batch this unit belongs to. Null if not part of a batch.
    pub fn batch(mut self, value: impl Into<UnitListBatch>) -> Self {
        self.batch = NullableField::Value(value.into());
        self
    }

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

    /// Set the `parent` field.
    ///
    /// Parent unit in the assembly hierarchy. Null if this is a top-level unit.
    pub fn parent(mut self, value: impl Into<UnitListParent>) -> Self {
        self.parent = NullableField::Value(value.into());
        self
    }

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

    /// Set the `children` field.
    ///
    /// Child units assembled into this unit. Limited to 10 results; use Get Unit endpoint for complete list.
    pub fn children(mut self, value: impl Into<Vec<UnitListChildren>>) -> Self {
        self.children = Some(value.into());
        self
    }

    /// Set the `part` field.
    ///
    /// Part information with the specific revision this unit is built from.
    pub fn part(mut self, value: impl Into<UnitListPart>) -> Self {
        self.part = Some(value.into());
        self
    }

    /// Set the `last_run` field.
    ///
    /// Most recent test run performed on this unit. Null if no runs have been executed.
    pub fn last_run(mut self, value: impl Into<UnitListLastRun>) -> Self {
        self.last_run = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitListData, String> {
        Ok(UnitListData {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            created_at: self.created_at
                .ok_or_else(|| "missing required field: created_at".to_string())?,
            created_by_user: self.created_by_user,
            created_by_station: self.created_by_station,
            batch: self.batch,
            parent: self.parent,
            children: self.children.unwrap_or_default(),
            part: self.part
                .ok_or_else(|| "missing required field: part".to_string())?,
            last_run: self.last_run,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListMeta {
    /// Whether there are more results available for pagination.
    pub has_more: bool,
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<i64>,
}

impl UnitListMeta {
    /// Create a builder for this type.
    pub fn builder() -> UnitListMetaBuilder {
        UnitListMetaBuilder::default()
    }
}

/// Builder for [`UnitListMeta`].
#[derive(Debug, Default)]
pub struct UnitListMetaBuilder {
    has_more: Option<bool>,
    next_cursor: Option<i64>,
}

impl UnitListMetaBuilder {
    /// Set the `has_more` field.
    ///
    /// Whether there are more results available for pagination.
    pub fn has_more(mut self, value: impl Into<bool>) -> Self {
        self.has_more = Some(value.into());
        self
    }

    /// Set the `next_cursor` field.
    ///
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    pub fn next_cursor(mut self, value: impl Into<i64>) -> Self {
        self.next_cursor = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitListMeta, String> {
        Ok(UnitListMeta {
            has_more: self.has_more
                .ok_or_else(|| "missing required field: has_more".to_string())?,
            next_cursor: self.next_cursor,
        })
    }
}

/// Units retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitListResponse {
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<UnitListData>,
    pub meta: UnitListMeta,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitDeleteRequest {
    /// Array of unit serial numbers to delete.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub serial_numbers: Vec<String>,
}

impl UnitDeleteRequest {
    /// Create a builder for this type.
    pub fn builder() -> UnitDeleteRequestBuilder {
        UnitDeleteRequestBuilder::default()
    }
}

/// Builder for [`UnitDeleteRequest`].
#[derive(Debug, Default)]
pub struct UnitDeleteRequestBuilder {
    serial_numbers: Option<Vec<String>>,
}

impl UnitDeleteRequestBuilder {
    /// Set the `serial_numbers` field.
    ///
    /// Array of unit serial numbers to delete.
    pub fn serial_numbers(mut self, value: impl Into<Vec<String>>) -> Self {
        self.serial_numbers = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitDeleteRequest, String> {
        Ok(UnitDeleteRequest {
            serial_numbers: self.serial_numbers.unwrap_or_default(),
        })
    }
}

/// Response for successful unit deletion
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitDeleteResponse {
    /// IDs of units that were successfully deleted
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub id: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetRequest {
    /// Serial number of the unit to retrieve.
    pub serial_number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl UnitGetCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> UnitGetCreatedByUserBuilder {
        UnitGetCreatedByUserBuilder::default()
    }
}

/// Builder for [`UnitGetCreatedByUser`].
#[derive(Debug, Default)]
pub struct UnitGetCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl UnitGetCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitGetCreatedByUser, String> {
        Ok(UnitGetCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetCreatedByStation {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

/// Revision information for this unit.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetRevision {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
}

/// Part information with revision details for this unit. Every unit must have a part and revision.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetPart {
    /// Part ID.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// Revision information for this unit.
    pub revision: UnitGetRevision,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetBatch {
    /// Batch ID.
    pub id: String,
    /// Batch number.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetParentPartRevision {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetParentPart {
    /// Part ID.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// Part revision information.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision: Option<UnitGetParentPartRevision>,
}

impl UnitGetParentPart {
    /// Create a builder for this type.
    pub fn builder() -> UnitGetParentPartBuilder {
        UnitGetParentPartBuilder::default()
    }
}

/// Builder for [`UnitGetParentPart`].
#[derive(Debug, Default)]
pub struct UnitGetParentPartBuilder {
    id: Option<String>,
    number: Option<String>,
    name: Option<String>,
    revision: Option<UnitGetParentPartRevision>,
}

impl UnitGetParentPartBuilder {
    /// Set the `id` field.
    ///
    /// Part ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Set the `revision` field.
    ///
    /// Part revision information.
    pub fn revision(mut self, value: impl Into<UnitGetParentPartRevision>) -> Self {
        self.revision = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitGetParentPart, String> {
        Ok(UnitGetParentPart {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            number: self.number
                .ok_or_else(|| "missing required field: number".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            revision: self.revision,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetParent {
    /// Unit ID.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// Part information for the parent unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part: Option<UnitGetParentPart>,
}

impl UnitGetParent {
    /// Create a builder for this type.
    pub fn builder() -> UnitGetParentBuilder {
        UnitGetParentBuilder::default()
    }
}

/// Builder for [`UnitGetParent`].
#[derive(Debug, Default)]
pub struct UnitGetParentBuilder {
    id: Option<String>,
    serial_number: Option<String>,
    part: Option<UnitGetParentPart>,
}

impl UnitGetParentBuilder {
    /// Set the `id` field.
    ///
    /// Unit ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `part` field.
    ///
    /// Part information for the parent unit.
    pub fn part(mut self, value: impl Into<UnitGetParentPart>) -> Self {
        self.part = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitGetParent, String> {
        Ok(UnitGetParent {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            part: self.part,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetChildrenPartRevision {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetChildrenPart {
    /// Part ID.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// Part revision information.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision: Option<UnitGetChildrenPartRevision>,
}

impl UnitGetChildrenPart {
    /// Create a builder for this type.
    pub fn builder() -> UnitGetChildrenPartBuilder {
        UnitGetChildrenPartBuilder::default()
    }
}

/// Builder for [`UnitGetChildrenPart`].
#[derive(Debug, Default)]
pub struct UnitGetChildrenPartBuilder {
    id: Option<String>,
    number: Option<String>,
    name: Option<String>,
    revision: Option<UnitGetChildrenPartRevision>,
}

impl UnitGetChildrenPartBuilder {
    /// Set the `id` field.
    ///
    /// Part ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Set the `revision` field.
    ///
    /// Part revision information.
    pub fn revision(mut self, value: impl Into<UnitGetChildrenPartRevision>) -> Self {
        self.revision = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitGetChildrenPart, String> {
        Ok(UnitGetChildrenPart {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            number: self.number
                .ok_or_else(|| "missing required field: number".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            revision: self.revision,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetChildren {
    /// Unit ID.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// Part information for the child unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part: Option<UnitGetChildrenPart>,
}

impl UnitGetChildren {
    /// Create a builder for this type.
    pub fn builder() -> UnitGetChildrenBuilder {
        UnitGetChildrenBuilder::default()
    }
}

/// Builder for [`UnitGetChildren`].
#[derive(Debug, Default)]
pub struct UnitGetChildrenBuilder {
    id: Option<String>,
    serial_number: Option<String>,
    part: Option<UnitGetChildrenPart>,
}

impl UnitGetChildrenBuilder {
    /// Set the `id` field.
    ///
    /// Unit ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `part` field.
    ///
    /// Part information for the child unit.
    pub fn part(mut self, value: impl Into<UnitGetChildrenPart>) -> Self {
        self.part = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitGetChildren, String> {
        Ok(UnitGetChildren {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            part: self.part,
        })
    }
}

/// Procedure information.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetProcedure {
    /// Procedure ID.
    pub id: String,
    /// Procedure name.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetCreatedDuring {
    /// Run ID.
    pub id: String,
    /// ISO 8601 timestamp when the run was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run started.
    pub started_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 timestamp when the run ended.
    pub ended_at: chrono::DateTime<chrono::Utc>,
    /// ISO 8601 duration of the run (computed from started_at and ended_at).
    pub duration: String,
    /// Final result of the run execution.
    pub outcome: Outcome,
    /// Procedure information.
    pub procedure: UnitGetProcedure,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetAttachments {
    /// Attachment ID.
    pub id: String,
    /// File name.
    pub name: String,
    /// File size in bytes.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub size: Option<f64>,
    /// MIME type of the file.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub content_type: Option<String>,
    /// Presigned URL for downloading the file. This URL is temporary and will expire.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub download_url: Option<String>,
}

impl UnitGetAttachments {
    /// Create a builder for this type.
    pub fn builder() -> UnitGetAttachmentsBuilder {
        UnitGetAttachmentsBuilder::default()
    }
}

/// Builder for [`UnitGetAttachments`].
#[derive(Debug, Default)]
pub struct UnitGetAttachmentsBuilder {
    id: Option<String>,
    name: Option<String>,
    size: Option<f64>,
    content_type: Option<String>,
    download_url: Option<String>,
}

impl UnitGetAttachmentsBuilder {
    /// Set the `id` field.
    ///
    /// Attachment ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `size` field.
    ///
    /// File size in bytes.
    pub fn size(mut self, value: impl Into<f64>) -> Self {
        self.size = Some(value.into());
        self
    }

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

    /// Set the `download_url` field.
    ///
    /// Presigned URL for downloading the file. This URL is temporary and will expire.
    pub fn download_url(mut self, value: impl Into<String>) -> Self {
        self.download_url = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitGetAttachments, String> {
        Ok(UnitGetAttachments {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            size: self.size,
            content_type: self.content_type,
            download_url: self.download_url,
        })
    }
}

/// Units retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitGetResponse {
    /// Unique identifier for the unit.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// ISO 8601 timestamp when the unit was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<UnitGetCreatedByUser>,
    /// Station that created this unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<UnitGetCreatedByStation>,
    /// Part information with revision details for this unit. Every unit must have a part and revision.
    pub part: UnitGetPart,
    /// Batch information for this unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub batch: NullableField<UnitGetBatch>,
    /// Parent unit information with part details and processed images.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub parent: Option<UnitGetParent>,
    /// Child units with part details.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub children: Option<Vec<UnitGetChildren>>,
    /// Run that created this unit.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_during: NullableField<UnitGetCreatedDuring>,
    /// Files attached to this unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<UnitGetAttachments>>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct UnitUpdateRequestBody {
    /// New serial number for the unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub new_serial_number: Option<String>,
    /// New part number for the unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part_number: Option<String>,
    /// New revision number for the unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_number: Option<String>,
    /// New batch number for the unit. Set to null to remove batch.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub batch_number: NullableField<String>,
    /// Array of upload IDs to attach to the unit.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub attachments: Option<Vec<String>>,
}

impl UnitUpdateRequestBody {
    /// Create a builder for this type.
    pub fn builder() -> UnitUpdateRequestBodyBuilder {
        UnitUpdateRequestBodyBuilder::default()
    }
}

/// Builder for [`UnitUpdateRequestBody`].
#[derive(Debug, Default)]
pub struct UnitUpdateRequestBodyBuilder {
    new_serial_number: Option<String>,
    part_number: Option<String>,
    revision_number: Option<String>,
    batch_number: NullableField<String>,
    attachments: Option<Vec<String>>,
}

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

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

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

    /// Set the `batch_number` field.
    ///
    /// New batch number for the unit. Set to null to remove batch.
    pub fn batch_number(mut self, value: impl Into<String>) -> Self {
        self.batch_number = NullableField::Value(value.into());
        self
    }

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

    /// Set the `attachments` field.
    ///
    /// Array of upload IDs to attach to the unit.
    pub fn attachments(mut self, value: impl Into<Vec<String>>) -> Self {
        self.attachments = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitUpdateRequestBody, String> {
        Ok(UnitUpdateRequestBody {
            new_serial_number: self.new_serial_number,
            part_number: self.part_number,
            revision_number: self.revision_number,
            batch_number: self.batch_number,
            attachments: self.attachments,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitUpdateRequest {
    /// Serial number of the unit to update.
    pub serial_number: String,
    pub request_body: UnitUpdateRequestBody,
}

/// Unit updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitUpdateResponse {
    /// Unique identifier of the updated unit.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitAddChildRequestBody {
    /// Serial number of the sub-unit to add
    pub child_serial_number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitAddChildRequest {
    /// Serial number of the parent unit
    pub serial_number: String,
    pub request_body: UnitAddChildRequestBody,
}

/// Child unit added successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitAddChildResponse {
    /// ID of the child unit that was added
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitRemoveChildRequest {
    /// Serial number of the parent unit
    pub serial_number: String,
    /// Serial number of the sub-unit to remove
    pub child_serial_number: String,
}

/// Child unit removed successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitRemoveChildResponse {
    /// ID of the child unit that was removed
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitCreateAttachmentRequestBody {
    /// File name including extension (e.g. "calibration.pdf"). Used to determine content type and display name.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitCreateAttachmentRequest {
    /// Serial number of the unit to attach the file to. Matched case-insensitively.
    pub serial_number: String,
    pub request_body: UnitCreateAttachmentRequestBody,
}

/// Unit attachment created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitCreateAttachmentResponse {
    /// Unique identifier of the created attachment. Use this to reference the attachment in subsequent API calls.
    pub id: String,
    /// Temporary pre-signed URL to upload the file directly to storage. Send a PUT request with the raw file bytes and appropriate Content-Type header. The URL expires after 60 seconds.
    pub upload_url: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitDeleteAttachmentRequest {
    /// Serial number of the unit. Matched case-insensitively.
    pub serial_number: String,
    /// Attachment IDs to delete
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub ids: Vec<String>,
}

impl UnitDeleteAttachmentRequest {
    /// Create a builder for this type.
    pub fn builder() -> UnitDeleteAttachmentRequestBuilder {
        UnitDeleteAttachmentRequestBuilder::default()
    }
}

/// Builder for [`UnitDeleteAttachmentRequest`].
#[derive(Debug, Default)]
pub struct UnitDeleteAttachmentRequestBuilder {
    serial_number: Option<String>,
    ids: Option<Vec<String>>,
}

impl UnitDeleteAttachmentRequestBuilder {
    /// Set the `serial_number` field.
    ///
    /// Serial number of the unit. Matched case-insensitively.
    pub fn serial_number(mut self, value: impl Into<String>) -> Self {
        self.serial_number = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UnitDeleteAttachmentRequest, String> {
        Ok(UnitDeleteAttachmentRequest {
            serial_number: self.serial_number
                .ok_or_else(|| "missing required field: serial_number".to_string())?,
            ids: self.ids.unwrap_or_default(),
        })
    }
}

/// Unit attachments deleted successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UnitDeleteAttachmentResponse {
    /// IDs of attachments that were deleted
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub ids: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartCreateRequest {
    /// Unique identifier number for the part.
    pub number: String,
    /// Human-readable name for the part. If not provided, a default name will be used.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// Revision identifier for the part version. If not provided, default revision identifier will be used.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_number: Option<String>,
}

impl PartCreateRequest {
    /// Create a builder for this type.
    pub fn builder() -> PartCreateRequestBuilder {
        PartCreateRequestBuilder::default()
    }
}

/// Builder for [`PartCreateRequest`].
#[derive(Debug, Default)]
pub struct PartCreateRequestBuilder {
    number: Option<String>,
    name: Option<String>,
    revision_number: Option<String>,
}

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

    /// Set the `name` field.
    ///
    /// Human-readable name for the part. If not provided, a default name will be used.
    pub fn name(mut self, value: impl Into<String>) -> Self {
        self.name = Some(value.into());
        self
    }

    /// Set the `revision_number` field.
    ///
    /// Revision identifier for the part version. If not provided, default revision identifier will be used.
    pub fn revision_number(mut self, value: impl Into<String>) -> Self {
        self.revision_number = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartCreateRequest, String> {
        Ok(PartCreateRequest {
            number: self.number
                .ok_or_else(|| "missing required field: number".to_string())?,
            name: self.name,
            revision_number: self.revision_number,
        })
    }
}

/// Part created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartCreateResponse {
    /// Unique identifier of the created part.
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct PartListRequest {
    /// Maximum number of parts to return in a single page.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cursor: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure_ids: Option<Vec<String>>,
    /// Field to sort results by.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_by: Option<PartListSortBy>,
    /// Sort order direction.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_order: Option<ListSortOrder>,
}

impl PartListRequest {
    /// Create a builder for this type.
    pub fn builder() -> PartListRequestBuilder {
        PartListRequestBuilder::default()
    }
}

/// Builder for [`PartListRequest`].
#[derive(Debug, Default)]
pub struct PartListRequestBuilder {
    limit: Option<i64>,
    cursor: Option<i64>,
    search_query: Option<String>,
    procedure_ids: Option<Vec<String>>,
    sort_by: Option<PartListSortBy>,
    sort_order: Option<ListSortOrder>,
}

impl PartListRequestBuilder {
    /// Set the `limit` field.
    ///
    /// Maximum number of parts to return in a single page.
    pub fn limit(mut self, value: impl Into<i64>) -> Self {
        self.limit = Some(value.into());
        self
    }

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

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

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

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

    /// Set the `sort_order` field.
    ///
    /// Sort order direction.
    pub fn sort_order(mut self, value: impl Into<ListSortOrder>) -> Self {
        self.sort_order = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartListRequest, String> {
        Ok(PartListRequest {
            limit: self.limit,
            cursor: self.cursor,
            search_query: self.search_query,
            procedure_ids: self.procedure_ids,
            sort_by: self.sort_by,
            sort_order: self.sort_order,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartListRevisions {
    /// Unique identifier of the revision.
    pub id: String,
    /// Revision number.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartListData {
    /// Unique database identifier of the part.
    pub id: String,
    /// Unique part number identifier.
    pub number: String,
    /// Human-readable name of the part.
    pub name: String,
    /// Time at which the part was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// List of revisions for this part.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub revisions: Vec<PartListRevisions>,
}

impl PartListData {
    /// Create a builder for this type.
    pub fn builder() -> PartListDataBuilder {
        PartListDataBuilder::default()
    }
}

/// Builder for [`PartListData`].
#[derive(Debug, Default)]
pub struct PartListDataBuilder {
    id: Option<String>,
    number: Option<String>,
    name: Option<String>,
    created_at: Option<chrono::DateTime<chrono::Utc>>,
    revisions: Option<Vec<PartListRevisions>>,
}

impl PartListDataBuilder {
    /// Set the `id` field.
    ///
    /// Unique database identifier of the part.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

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

    /// Set the `created_at` field.
    ///
    /// Time at which the part was created.
    pub fn created_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_at = Some(value.into());
        self
    }

    /// Set the `revisions` field.
    ///
    /// List of revisions for this part.
    pub fn revisions(mut self, value: impl Into<Vec<PartListRevisions>>) -> Self {
        self.revisions = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartListData, String> {
        Ok(PartListData {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            number: self.number
                .ok_or_else(|| "missing required field: number".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            created_at: self.created_at
                .ok_or_else(|| "missing required field: created_at".to_string())?,
            revisions: self.revisions.unwrap_or_default(),
        })
    }
}

/// Pagination metadata.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartListMeta {
    /// Whether there are more results available for pagination.
    pub has_more: bool,
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<i64>,
}

impl PartListMeta {
    /// Create a builder for this type.
    pub fn builder() -> PartListMetaBuilder {
        PartListMetaBuilder::default()
    }
}

/// Builder for [`PartListMeta`].
#[derive(Debug, Default)]
pub struct PartListMetaBuilder {
    has_more: Option<bool>,
    next_cursor: Option<i64>,
}

impl PartListMetaBuilder {
    /// Set the `has_more` field.
    ///
    /// Whether there are more results available for pagination.
    pub fn has_more(mut self, value: impl Into<bool>) -> Self {
        self.has_more = Some(value.into());
        self
    }

    /// Set the `next_cursor` field.
    ///
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available.
    pub fn next_cursor(mut self, value: impl Into<i64>) -> Self {
        self.next_cursor = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartListMeta, String> {
        Ok(PartListMeta {
            has_more: self.has_more
                .ok_or_else(|| "missing required field: has_more".to_string())?,
            next_cursor: self.next_cursor,
        })
    }
}

/// Parts retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartListResponse {
    /// List of parts matching the search criteria.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<PartListData>,
    /// Pagination metadata.
    pub meta: PartListMeta,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRequest {
    /// Part number of the part to retrieve.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl PartGetCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> PartGetCreatedByUserBuilder {
        PartGetCreatedByUserBuilder::default()
    }
}

/// Builder for [`PartGetCreatedByUser`].
#[derive(Debug, Default)]
pub struct PartGetCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl PartGetCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartGetCreatedByUser, String> {
        Ok(PartGetCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetCreatedByStation {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisions {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
    /// ISO 8601 timestamp when the revision was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
}

/// Part retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetResponse {
    /// Unique identifier for the part.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// ISO 8601 timestamp when the part was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this part.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<PartGetCreatedByUser>,
    /// Station that created this part.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<PartGetCreatedByStation>,
    /// List of revisions for this part.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub revisions: Vec<PartGetRevisions>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct PartUpdateRequestBody {
    /// New unique identifier number for the part.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub new_number: Option<String>,
    /// New human-readable name for the part.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl PartUpdateRequestBody {
    /// Create a builder for this type.
    pub fn builder() -> PartUpdateRequestBodyBuilder {
        PartUpdateRequestBodyBuilder::default()
    }
}

/// Builder for [`PartUpdateRequestBody`].
#[derive(Debug, Default)]
pub struct PartUpdateRequestBodyBuilder {
    new_number: Option<String>,
    name: Option<String>,
}

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartUpdateRequestBody, String> {
        Ok(PartUpdateRequestBody {
            new_number: self.new_number,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartUpdateRequest {
    /// Part number of the part to update.
    pub number: String,
    pub request_body: PartUpdateRequestBody,
}

/// Part updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartUpdateResponse {
    /// Unique database identifier of the updated part.
    pub id: String,
    /// Unique part number identifier.
    pub number: String,
    /// Human-readable name of the part.
    pub name: String,
    /// ISO 8601 timestamp when the part was updated.
    pub updated_at: chrono::DateTime<chrono::Utc>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartDeleteRequest {
    /// Part number to delete.
    pub number: String,
}

/// Part deleted successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartDeleteResponse {
    /// Unique identifier of the deleted part.
    pub id: String,
    /// IDs of all revisions that were deleted with the part.
    #[serde(rename = "deletedRevisionIds")]
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub deleted_revision_ids: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisionRequest {
    /// Part number that the revision belongs to.
    pub part_number: String,
    /// Revision number to retrieve.
    pub revision_number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisionCreatedByUser {
    /// Unique identifier of the user.
    pub id: String,
    /// Name of the user who created the revision.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl PartGetRevisionCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> PartGetRevisionCreatedByUserBuilder {
        PartGetRevisionCreatedByUserBuilder::default()
    }
}

/// Builder for [`PartGetRevisionCreatedByUser`].
#[derive(Debug, Default)]
pub struct PartGetRevisionCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl PartGetRevisionCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// Unique identifier of the user.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartGetRevisionCreatedByUser, String> {
        Ok(PartGetRevisionCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisionCreatedByStation {
    /// Unique identifier of the station.
    pub id: String,
    /// Name of the station.
    pub name: String,
}

/// Part associated with this revision.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisionPart {
    /// Unique identifier of the part.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Name of the part.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisionUnits {
    /// Unique identifier of the unit.
    pub id: String,
    /// Serial number of the unit.
    pub serial_number: String,
}

/// Revision retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartGetRevisionResponse {
    /// Unique identifier of the revision.
    pub id: String,
    /// Revision number.
    pub number: String,
    /// ISO 8601 timestamp when the revision was created.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_at: Option<chrono::DateTime<chrono::Utc>>,
    /// User who created the revision.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_user: Option<PartGetRevisionCreatedByUser>,
    /// Station that created the revision.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_by_station: Option<PartGetRevisionCreatedByStation>,
    /// Part associated with this revision.
    pub part: PartGetRevisionPart,
    /// List of units created with this revision.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub units: Vec<PartGetRevisionUnits>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct PartUpdateRevisionRequestBody {
    /// New revision number to set.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub number: Option<String>,
    /// Upload ID for the revision image, or empty string to remove image
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub image_id: Option<String>,
}

impl PartUpdateRevisionRequestBody {
    /// Create a builder for this type.
    pub fn builder() -> PartUpdateRevisionRequestBodyBuilder {
        PartUpdateRevisionRequestBodyBuilder::default()
    }
}

/// Builder for [`PartUpdateRevisionRequestBody`].
#[derive(Debug, Default)]
pub struct PartUpdateRevisionRequestBodyBuilder {
    number: Option<String>,
    image_id: Option<String>,
}

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

    /// Set the `image_id` field.
    ///
    /// Upload ID for the revision 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
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<PartUpdateRevisionRequestBody, String> {
        Ok(PartUpdateRevisionRequestBody {
            number: self.number,
            image_id: self.image_id,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartUpdateRevisionRequest {
    /// Part number that the revision belongs to.
    pub part_number: String,
    /// Current revision number to update.
    pub revision_number: String,
    pub request_body: PartUpdateRevisionRequestBody,
}

/// Revision updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartUpdateRevisionResponse {
    /// Unique identifier of the updated revision.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartDeleteRevisionRequest {
    /// Part number that the revision belongs to.
    pub part_number: String,
    /// Revision number to delete.
    pub revision_number: String,
}

/// Revision deleted successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartDeleteRevisionResponse {
    /// Unique identifier of the deleted revision.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartCreateRevisionRequestBody {
    /// Revision number (e.g., version number or code).
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartCreateRevisionRequest {
    /// Part number to create a revision for.
    pub part_number: String,
    pub request_body: PartCreateRevisionRequestBody,
}

/// Revision created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct PartCreateRevisionResponse {
    /// Unique identifier of the created revision.
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetRequest {
    /// Number of the batch to retrieve.
    pub number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl BatchGetCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> BatchGetCreatedByUserBuilder {
        BatchGetCreatedByUserBuilder::default()
    }
}

/// Builder for [`BatchGetCreatedByUser`].
#[derive(Debug, Default)]
pub struct BatchGetCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl BatchGetCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<BatchGetCreatedByUser, String> {
        Ok(BatchGetCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetCreatedByStation {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

/// Revision information for this unit.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetRevision {
    /// Revision ID.
    pub id: String,
    /// Revision number.
    pub number: String,
}

/// Part information with revision details for this unit.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetPart {
    /// Part ID.
    pub id: String,
    /// Part number.
    pub number: String,
    /// Part name.
    pub name: String,
    /// Revision information for this unit.
    pub revision: BatchGetRevision,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetUnits {
    /// Unit ID.
    pub id: String,
    /// Unit serial number.
    pub serial_number: String,
    /// ISO 8601 timestamp when the unit was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Part information with revision details for this unit.
    pub part: BatchGetPart,
}

/// Batch retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchGetResponse {
    /// Unique identifier for the batch.
    pub id: String,
    /// Batch number.
    pub number: String,
    /// ISO 8601 timestamp when the batch was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this batch.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<BatchGetCreatedByUser>,
    /// Station that created this batch.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<BatchGetCreatedByStation>,
    /// Array of units in this batch. Empty array if no units.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub units: Vec<BatchGetUnits>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchDeleteRequest {
    pub number: String,
}

/// Response for successful batch deletion
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchDeleteResponse {
    /// IDs of successfully deleted batches
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub id: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchUpdateRequestBody {
    /// New batch number.
    pub new_number: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchUpdateRequest {
    /// Current batch number to update.
    pub number: String,
    pub request_body: BatchUpdateRequestBody,
}

/// Batch updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchUpdateResponse {
    /// Unique identifier of the updated batch.
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct BatchListRequest {
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub ids: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_after: Option<chrono::DateTime<chrono::Utc>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub created_before: Option<chrono::DateTime<chrono::Utc>>,
    /// Maximum number of batches to return. Use `cursor` to fetch additional results.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cursor: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub part_numbers: Option<Vec<String>>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_numbers: Option<Vec<String>>,
    /// Field to sort results by.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_by: Option<BatchListSortBy>,
    /// Sort order direction.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub sort_order: Option<ListSortOrder>,
}

impl BatchListRequest {
    /// Create a builder for this type.
    pub fn builder() -> BatchListRequestBuilder {
        BatchListRequestBuilder::default()
    }
}

/// Builder for [`BatchListRequest`].
#[derive(Debug, Default)]
pub struct BatchListRequestBuilder {
    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>,
}

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

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

    /// Set the `created_after` field.
    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` field.
    pub fn created_before(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_before = Some(value.into());
        self
    }

    /// Set the `limit` field.
    ///
    /// 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` field.
    pub fn cursor(mut self, value: impl Into<i64>) -> Self {
        self.cursor = Some(value.into());
        self
    }

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

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

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

    /// Set the `sort_by` field.
    ///
    /// 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` field.
    ///
    /// Sort order direction.
    pub fn sort_order(mut self, value: impl Into<ListSortOrder>) -> Self {
        self.sort_order = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<BatchListRequest, String> {
        Ok(BatchListRequest {
            ids: self.ids,
            numbers: self.numbers,
            created_after: self.created_after,
            created_before: self.created_before,
            limit: self.limit,
            cursor: self.cursor,
            search_query: self.search_query,
            part_numbers: self.part_numbers,
            revision_numbers: self.revision_numbers,
            sort_by: self.sort_by,
            sort_order: self.sort_order,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchListCreatedByUser {
    /// User ID.
    pub id: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
}

impl BatchListCreatedByUser {
    /// Create a builder for this type.
    pub fn builder() -> BatchListCreatedByUserBuilder {
        BatchListCreatedByUserBuilder::default()
    }
}

/// Builder for [`BatchListCreatedByUser`].
#[derive(Debug, Default)]
pub struct BatchListCreatedByUserBuilder {
    id: Option<String>,
    name: Option<String>,
}

impl BatchListCreatedByUserBuilder {
    /// Set the `id` field.
    ///
    /// User ID.
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<BatchListCreatedByUser, String> {
        Ok(BatchListCreatedByUser {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchListCreatedByStation {
    /// Station ID.
    pub id: String,
    /// Station name.
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchListData {
    /// Unique identifier for the batch.
    pub id: String,
    /// Batch number.
    pub number: String,
    /// ISO timestamp when the batch was created.
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// User who created this batch.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_user: NullableField<BatchListCreatedByUser>,
    /// Station that created this batch.
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub created_by_station: NullableField<BatchListCreatedByStation>,
    /// Total number of units in this batch.
    pub unit_count: i64,
}

impl BatchListData {
    /// Create a builder for this type.
    pub fn builder() -> BatchListDataBuilder {
        BatchListDataBuilder::default()
    }
}

/// Builder for [`BatchListData`].
#[derive(Debug, Default)]
pub struct BatchListDataBuilder {
    id: Option<String>,
    number: Option<String>,
    created_at: Option<chrono::DateTime<chrono::Utc>>,
    created_by_user: NullableField<BatchListCreatedByUser>,
    created_by_station: NullableField<BatchListCreatedByStation>,
    unit_count: Option<i64>,
}

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

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

    /// Set the `created_at` field.
    ///
    /// ISO timestamp when the batch was created.
    pub fn created_at(mut self, value: impl Into<chrono::DateTime<chrono::Utc>>) -> Self {
        self.created_at = Some(value.into());
        self
    }

    /// Set the `created_by_user` field.
    ///
    /// User who created this batch.
    pub fn created_by_user(mut self, value: impl Into<BatchListCreatedByUser>) -> Self {
        self.created_by_user = NullableField::Value(value.into());
        self
    }

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

    /// Set the `created_by_station` field.
    ///
    /// Station that created this batch.
    pub fn created_by_station(mut self, value: impl Into<BatchListCreatedByStation>) -> Self {
        self.created_by_station = NullableField::Value(value.into());
        self
    }

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

    /// Set the `unit_count` field.
    ///
    /// Total number of units in this batch.
    pub fn unit_count(mut self, value: impl Into<i64>) -> Self {
        self.unit_count = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<BatchListData, String> {
        Ok(BatchListData {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            number: self.number
                .ok_or_else(|| "missing required field: number".to_string())?,
            created_at: self.created_at
                .ok_or_else(|| "missing required field: created_at".to_string())?,
            created_by_user: self.created_by_user,
            created_by_station: self.created_by_station,
            unit_count: self.unit_count
                .ok_or_else(|| "missing required field: unit_count".to_string())?,
        })
    }
}

/// Pagination metadata.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchListMeta {
    /// Whether there are more results available.
    pub has_more: bool,
    /// Cursor for fetching the next page of results.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<i64>,
}

impl BatchListMeta {
    /// Create a builder for this type.
    pub fn builder() -> BatchListMetaBuilder {
        BatchListMetaBuilder::default()
    }
}

/// Builder for [`BatchListMeta`].
#[derive(Debug, Default)]
pub struct BatchListMetaBuilder {
    has_more: Option<bool>,
    next_cursor: Option<i64>,
}

impl BatchListMetaBuilder {
    /// Set the `has_more` field.
    ///
    /// Whether there are more results available.
    pub fn has_more(mut self, value: impl Into<bool>) -> Self {
        self.has_more = Some(value.into());
        self
    }

    /// Set the `next_cursor` field.
    ///
    /// Cursor for fetching the next page of results.
    pub fn next_cursor(mut self, value: impl Into<i64>) -> Self {
        self.next_cursor = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<BatchListMeta, String> {
        Ok(BatchListMeta {
            has_more: self.has_more
                .ok_or_else(|| "missing required field: has_more".to_string())?,
            next_cursor: self.next_cursor,
        })
    }
}

/// Batches retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchListResponse {
    /// Array of batches matching the query.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<BatchListData>,
    /// Pagination metadata.
    pub meta: BatchListMeta,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchCreateRequest {
    /// The batch number identifier
    pub number: String,
}

/// Batch created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct BatchCreateResponse {
    /// Unique identifier for the created batch
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationCreateRequest {
    /// Name of the station
    pub name: String,
    /// Optional procedure ID to link the station to
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure_id: Option<String>,
}

impl StationCreateRequest {
    /// Create a builder for this type.
    pub fn builder() -> StationCreateRequestBuilder {
        StationCreateRequestBuilder::default()
    }
}

/// Builder for [`StationCreateRequest`].
#[derive(Debug, Default)]
pub struct StationCreateRequestBuilder {
    name: Option<String>,
    procedure_id: Option<String>,
}

impl StationCreateRequestBuilder {
    /// 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
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationCreateRequest, String> {
        Ok(StationCreateRequest {
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            procedure_id: self.procedure_id,
        })
    }
}

/// Station created successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationCreateResponse {
    /// Unique identifier of the created station
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct StationListRequest {
    /// Number of stations to return per page
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub limit: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub cursor: Option<i64>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub search_query: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub procedure_ids: Option<Vec<String>>,
}

impl StationListRequest {
    /// Create a builder for this type.
    pub fn builder() -> StationListRequestBuilder {
        StationListRequestBuilder::default()
    }
}

/// Builder for [`StationListRequest`].
#[derive(Debug, Default)]
pub struct StationListRequestBuilder {
    limit: Option<i64>,
    cursor: Option<i64>,
    search_query: Option<String>,
    procedure_ids: Option<Vec<String>>,
}

impl StationListRequestBuilder {
    /// Set the `limit` field.
    ///
    /// 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` field.
    pub fn cursor(mut self, value: impl Into<i64>) -> Self {
        self.cursor = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationListRequest, String> {
        Ok(StationListRequest {
            limit: self.limit,
            cursor: self.cursor,
            search_query: self.search_query,
            procedure_ids: self.procedure_ids,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationListProcedures {
    /// Procedure ID
    pub id: String,
    /// Procedure name
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationListTeam {
    /// Team ID
    pub id: String,
    /// Team name
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationListData {
    /// Unique identifier of the station
    pub id: String,
    /// Name of the station
    pub name: String,
    /// Procedures linked to this station
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub procedures: Vec<StationListProcedures>,
    /// Total number of procedures linked to this station
    pub procedures_count: f64,
    /// Team this station belongs to
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub team: Option<StationListTeam>,
}

impl StationListData {
    /// Create a builder for this type.
    pub fn builder() -> StationListDataBuilder {
        StationListDataBuilder::default()
    }
}

/// Builder for [`StationListData`].
#[derive(Debug, Default)]
pub struct StationListDataBuilder {
    id: Option<String>,
    name: Option<String>,
    procedures: Option<Vec<StationListProcedures>>,
    procedures_count: Option<f64>,
    team: Option<StationListTeam>,
}

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

    /// 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 `procedures` field.
    ///
    /// Procedures linked to this station
    pub fn procedures(mut self, value: impl Into<Vec<StationListProcedures>>) -> Self {
        self.procedures = Some(value.into());
        self
    }

    /// Set the `procedures_count` field.
    ///
    /// Total number of procedures linked to this station
    pub fn procedures_count(mut self, value: impl Into<f64>) -> Self {
        self.procedures_count = Some(value.into());
        self
    }

    /// Set the `team` field.
    ///
    /// Team this station belongs to
    pub fn team(mut self, value: impl Into<StationListTeam>) -> Self {
        self.team = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationListData, String> {
        Ok(StationListData {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            procedures: self.procedures.unwrap_or_default(),
            procedures_count: self.procedures_count
                .ok_or_else(|| "missing required field: procedures_count".to_string())?,
            team: self.team,
        })
    }
}

/// Pagination metadata
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationListMeta {
    /// Whether there are more results available for pagination
    pub has_more: bool,
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub next_cursor: Option<i64>,
}

impl StationListMeta {
    /// Create a builder for this type.
    pub fn builder() -> StationListMetaBuilder {
        StationListMetaBuilder::default()
    }
}

/// Builder for [`StationListMeta`].
#[derive(Debug, Default)]
pub struct StationListMetaBuilder {
    has_more: Option<bool>,
    next_cursor: Option<i64>,
}

impl StationListMetaBuilder {
    /// Set the `has_more` field.
    ///
    /// Whether there are more results available for pagination
    pub fn has_more(mut self, value: impl Into<bool>) -> Self {
        self.has_more = Some(value.into());
        self
    }

    /// Set the `next_cursor` field.
    ///
    /// Cursor value to fetch the next page of results. Use this value as the cursor parameter in the next request. Null if no more results available
    pub fn next_cursor(mut self, value: impl Into<i64>) -> Self {
        self.next_cursor = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationListMeta, String> {
        Ok(StationListMeta {
            has_more: self.has_more
                .ok_or_else(|| "missing required field: has_more".to_string())?,
            next_cursor: self.next_cursor,
        })
    }
}

/// Stations retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationListResponse {
    /// List of stations matching the search criteria
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub data: Vec<StationListData>,
    /// Pagination metadata
    pub meta: StationListMeta,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCurrentCommit {
    /// Git commit SHA
    pub sha: String,
    /// Git commit message
    pub message: String,
    /// Git branch name
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub branch: Option<String>,
}

impl StationGetCurrentCommit {
    /// Create a builder for this type.
    pub fn builder() -> StationGetCurrentCommitBuilder {
        StationGetCurrentCommitBuilder::default()
    }
}

/// Builder for [`StationGetCurrentCommit`].
#[derive(Debug, Default)]
pub struct StationGetCurrentCommitBuilder {
    sha: Option<String>,
    message: Option<String>,
    branch: Option<String>,
}

impl StationGetCurrentCommitBuilder {
    /// Set the `sha` field.
    ///
    /// Git commit SHA
    pub fn sha(mut self, value: impl Into<String>) -> Self {
        self.sha = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetCurrentCommit, String> {
        Ok(StationGetCurrentCommit {
            sha: self.sha
                .ok_or_else(|| "missing required field: sha".to_string())?,
            message: self.message
                .ok_or_else(|| "missing required field: message".to_string())?,
            branch: self.branch,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCurrentRepository {
    /// Repository owner
    pub owner: String,
    /// Repository name
    pub name: String,
    /// Git provider
    pub provider: Provider,
    /// GitLab project ID (only for GitLab repos)
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub gitlab_project_id: Option<f64>,
}

impl StationGetCurrentRepository {
    /// Create a builder for this type.
    pub fn builder() -> StationGetCurrentRepositoryBuilder {
        StationGetCurrentRepositoryBuilder::default()
    }
}

/// Builder for [`StationGetCurrentRepository`].
#[derive(Debug, Default)]
pub struct StationGetCurrentRepositoryBuilder {
    owner: Option<String>,
    name: Option<String>,
    provider: Option<Provider>,
    gitlab_project_id: Option<f64>,
}

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

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

    /// Set the `provider` field.
    ///
    /// Git provider
    pub fn provider(mut self, value: impl Into<Provider>) -> Self {
        self.provider = Some(value.into());
        self
    }

    /// Set the `gitlab_project_id` field.
    ///
    /// GitLab project ID (only for GitLab repos)
    pub fn gitlab_project_id(mut self, value: impl Into<f64>) -> Self {
        self.gitlab_project_id = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetCurrentRepository, String> {
        Ok(StationGetCurrentRepository {
            owner: self.owner
                .ok_or_else(|| "missing required field: owner".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            provider: self.provider
                .ok_or_else(|| "missing required field: provider".to_string())?,
            gitlab_project_id: self.gitlab_project_id,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCurrentDeployment {
    /// When the procedure was deployed
    pub deployed_at: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub commit: Option<StationGetCurrentCommit>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub repository: Option<StationGetCurrentRepository>,
}

impl StationGetCurrentDeployment {
    /// Create a builder for this type.
    pub fn builder() -> StationGetCurrentDeploymentBuilder {
        StationGetCurrentDeploymentBuilder::default()
    }
}

/// Builder for [`StationGetCurrentDeployment`].
#[derive(Debug, Default)]
pub struct StationGetCurrentDeploymentBuilder {
    deployed_at: Option<String>,
    commit: Option<StationGetCurrentCommit>,
    repository: Option<StationGetCurrentRepository>,
}

impl StationGetCurrentDeploymentBuilder {
    /// Set the `deployed_at` field.
    ///
    /// When the procedure was deployed
    pub fn deployed_at(mut self, value: impl Into<String>) -> Self {
        self.deployed_at = Some(value.into());
        self
    }

    /// Set the `commit` field.
    pub fn commit(mut self, value: impl Into<StationGetCurrentCommit>) -> Self {
        self.commit = Some(value.into());
        self
    }

    /// Set the `repository` field.
    pub fn repository(mut self, value: impl Into<StationGetCurrentRepository>) -> Self {
        self.repository = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetCurrentDeployment, String> {
        Ok(StationGetCurrentDeployment {
            deployed_at: self.deployed_at
                .ok_or_else(|| "missing required field: deployed_at".to_string())?,
            commit: self.commit,
            repository: self.repository,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCurrentProcedures {
    /// Procedure ID
    pub id: String,
    /// Procedure name
    pub name: String,
    /// Number of runs created by this station in the last 7 days
    pub runs_count: f64,
    /// Deployment information for this procedure on this station
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub deployment: NullableField<StationGetCurrentDeployment>,
}

impl StationGetCurrentProcedures {
    /// Create a builder for this type.
    pub fn builder() -> StationGetCurrentProceduresBuilder {
        StationGetCurrentProceduresBuilder::default()
    }
}

/// Builder for [`StationGetCurrentProcedures`].
#[derive(Debug, Default)]
pub struct StationGetCurrentProceduresBuilder {
    id: Option<String>,
    name: Option<String>,
    runs_count: Option<f64>,
    deployment: NullableField<StationGetCurrentDeployment>,
}

impl StationGetCurrentProceduresBuilder {
    /// Set the `id` field.
    ///
    /// Procedure ID
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `runs_count` field.
    ///
    /// Number of runs created by this station in the last 7 days
    pub fn runs_count(mut self, value: impl Into<f64>) -> Self {
        self.runs_count = Some(value.into());
        self
    }

    /// Set the `deployment` field.
    ///
    /// Deployment information for this procedure on this station
    pub fn deployment(mut self, value: impl Into<StationGetCurrentDeployment>) -> Self {
        self.deployment = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetCurrentProcedures, String> {
        Ok(StationGetCurrentProcedures {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            runs_count: self.runs_count
                .ok_or_else(|| "missing required field: runs_count".to_string())?,
            deployment: self.deployment,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCurrentTeam {
    pub id: String,
    pub name: String,
}

/// Current station retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCurrentResponse {
    /// Unique identifier of the station
    pub id: String,
    /// Name of the station
    pub name: String,
    /// API key prefix for the station (full key only shown on creation)
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub api_key: Option<String>,
    /// Procedures linked to this station with recent run counts
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub procedures: Vec<StationGetCurrentProcedures>,
    /// Slug of the organization this station belongs to
    pub organization_slug: String,
    /// Team this station is assigned to
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub team: Option<StationGetCurrentTeam>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetRequest {
    /// Unique identifier of the station to retrieve
    pub id: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetCommit {
    /// Git commit SHA
    pub sha: String,
    /// Git commit message
    pub message: String,
    /// Git branch name
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub branch: Option<String>,
}

impl StationGetCommit {
    /// Create a builder for this type.
    pub fn builder() -> StationGetCommitBuilder {
        StationGetCommitBuilder::default()
    }
}

/// Builder for [`StationGetCommit`].
#[derive(Debug, Default)]
pub struct StationGetCommitBuilder {
    sha: Option<String>,
    message: Option<String>,
    branch: Option<String>,
}

impl StationGetCommitBuilder {
    /// Set the `sha` field.
    ///
    /// Git commit SHA
    pub fn sha(mut self, value: impl Into<String>) -> Self {
        self.sha = Some(value.into());
        self
    }

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

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetCommit, String> {
        Ok(StationGetCommit {
            sha: self.sha
                .ok_or_else(|| "missing required field: sha".to_string())?,
            message: self.message
                .ok_or_else(|| "missing required field: message".to_string())?,
            branch: self.branch,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetRepository {
    /// Repository owner
    pub owner: String,
    /// Repository name
    pub name: String,
    /// Git provider
    pub provider: Provider,
    /// GitLab project ID (only for GitLab repos)
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub gitlab_project_id: Option<f64>,
}

impl StationGetRepository {
    /// Create a builder for this type.
    pub fn builder() -> StationGetRepositoryBuilder {
        StationGetRepositoryBuilder::default()
    }
}

/// Builder for [`StationGetRepository`].
#[derive(Debug, Default)]
pub struct StationGetRepositoryBuilder {
    owner: Option<String>,
    name: Option<String>,
    provider: Option<Provider>,
    gitlab_project_id: Option<f64>,
}

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

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

    /// Set the `provider` field.
    ///
    /// Git provider
    pub fn provider(mut self, value: impl Into<Provider>) -> Self {
        self.provider = Some(value.into());
        self
    }

    /// Set the `gitlab_project_id` field.
    ///
    /// GitLab project ID (only for GitLab repos)
    pub fn gitlab_project_id(mut self, value: impl Into<f64>) -> Self {
        self.gitlab_project_id = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetRepository, String> {
        Ok(StationGetRepository {
            owner: self.owner
                .ok_or_else(|| "missing required field: owner".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            provider: self.provider
                .ok_or_else(|| "missing required field: provider".to_string())?,
            gitlab_project_id: self.gitlab_project_id,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetDeployment {
    /// When the procedure was deployed
    pub deployed_at: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub commit: Option<StationGetCommit>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub repository: Option<StationGetRepository>,
}

impl StationGetDeployment {
    /// Create a builder for this type.
    pub fn builder() -> StationGetDeploymentBuilder {
        StationGetDeploymentBuilder::default()
    }
}

/// Builder for [`StationGetDeployment`].
#[derive(Debug, Default)]
pub struct StationGetDeploymentBuilder {
    deployed_at: Option<String>,
    commit: Option<StationGetCommit>,
    repository: Option<StationGetRepository>,
}

impl StationGetDeploymentBuilder {
    /// Set the `deployed_at` field.
    ///
    /// When the procedure was deployed
    pub fn deployed_at(mut self, value: impl Into<String>) -> Self {
        self.deployed_at = Some(value.into());
        self
    }

    /// Set the `commit` field.
    pub fn commit(mut self, value: impl Into<StationGetCommit>) -> Self {
        self.commit = Some(value.into());
        self
    }

    /// Set the `repository` field.
    pub fn repository(mut self, value: impl Into<StationGetRepository>) -> Self {
        self.repository = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetDeployment, String> {
        Ok(StationGetDeployment {
            deployed_at: self.deployed_at
                .ok_or_else(|| "missing required field: deployed_at".to_string())?,
            commit: self.commit,
            repository: self.repository,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetProcedures {
    /// Procedure ID
    pub id: String,
    /// Procedure name
    pub name: String,
    /// Number of runs created by this station in the last 7 days
    pub runs_count: f64,
    /// Deployment information for this procedure on this station
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub deployment: NullableField<StationGetDeployment>,
}

impl StationGetProcedures {
    /// Create a builder for this type.
    pub fn builder() -> StationGetProceduresBuilder {
        StationGetProceduresBuilder::default()
    }
}

/// Builder for [`StationGetProcedures`].
#[derive(Debug, Default)]
pub struct StationGetProceduresBuilder {
    id: Option<String>,
    name: Option<String>,
    runs_count: Option<f64>,
    deployment: NullableField<StationGetDeployment>,
}

impl StationGetProceduresBuilder {
    /// Set the `id` field.
    ///
    /// Procedure ID
    pub fn id(mut self, value: impl Into<String>) -> Self {
        self.id = Some(value.into());
        self
    }

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

    /// Set the `runs_count` field.
    ///
    /// Number of runs created by this station in the last 7 days
    pub fn runs_count(mut self, value: impl Into<f64>) -> Self {
        self.runs_count = Some(value.into());
        self
    }

    /// Set the `deployment` field.
    ///
    /// Deployment information for this procedure on this station
    pub fn deployment(mut self, value: impl Into<StationGetDeployment>) -> Self {
        self.deployment = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationGetProcedures, String> {
        Ok(StationGetProcedures {
            id: self.id
                .ok_or_else(|| "missing required field: id".to_string())?,
            name: self.name
                .ok_or_else(|| "missing required field: name".to_string())?,
            runs_count: self.runs_count
                .ok_or_else(|| "missing required field: runs_count".to_string())?,
            deployment: self.deployment,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetTeam {
    pub id: String,
    pub name: String,
}

/// Station retrieved successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationGetResponse {
    /// Unique identifier of the station
    pub id: String,
    /// Name of the station
    pub name: String,
    /// API key prefix for the station (full key only shown on creation)
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub api_key: Option<String>,
    /// Procedures linked to this station with recent run counts
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub procedures: Vec<StationGetProcedures>,
    /// Slug of the organization this station belongs to
    pub organization_slug: String,
    /// Team this station is assigned to
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub team: Option<StationGetTeam>,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct StationUpdateRequestBody {
    /// New name for the station
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// Upload ID for the station image, or empty string to remove image
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub image_id: Option<String>,
    /// Team ID to assign this station to, or null to unassign
    #[serde(default, skip_serializing_if = "nullable_is_absent")]
    pub team_id: NullableField<String>,
}

impl StationUpdateRequestBody {
    /// Create a builder for this type.
    pub fn builder() -> StationUpdateRequestBodyBuilder {
        StationUpdateRequestBodyBuilder::default()
    }
}

/// Builder for [`StationUpdateRequestBody`].
#[derive(Debug, Default)]
pub struct StationUpdateRequestBodyBuilder {
    name: Option<String>,
    image_id: Option<String>,
    team_id: NullableField<String>,
}

impl StationUpdateRequestBodyBuilder {
    /// 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 = NullableField::Value(value.into());
        self
    }

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

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<StationUpdateRequestBody, String> {
        Ok(StationUpdateRequestBody {
            name: self.name,
            image_id: self.image_id,
            team_id: self.team_id,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationUpdateRequest {
    /// Unique identifier of the station to update
    pub id: String,
    pub request_body: StationUpdateRequestBody,
}

/// Station updated successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationUpdateResponse {
    /// Unique identifier of the updated station
    pub id: String,
    /// Name of the station
    pub name: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationRemoveRequest {
    /// Unique identifier of the station to remove
    pub id: String,
}

/// Station removed successfully
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct StationRemoveResponse {
    /// Unique identifier of the removed station
    pub id: String,
}

#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
pub struct UserListRequest {
    /// If true, returns only the current authenticated user
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub current: Option<bool>,
}

impl UserListRequest {
    /// Create a builder for this type.
    pub fn builder() -> UserListRequestBuilder {
        UserListRequestBuilder::default()
    }
}

/// Builder for [`UserListRequest`].
#[derive(Debug, Default)]
pub struct UserListRequestBuilder {
    current: Option<bool>,
}

impl UserListRequestBuilder {
    /// Set the `current` field.
    ///
    /// If true, returns only the current authenticated user
    pub fn current(mut self, value: impl Into<bool>) -> Self {
        self.current = Some(value.into());
        self
    }

    /// Build the struct. Returns an error message if required fields are missing.
    pub fn build(self) -> std::result::Result<UserListRequest, String> {
        Ok(UserListRequest {
            current: self.current,
        })
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct UserListResponse {
    /// Unique identifier for the user.
    pub id: String,
    /// Email address of the user.
    pub email: String,
    /// Display name of the user.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,
    /// Profile image URL for the user.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub image: Option<String>,
    /// Whether the user is banned.
    pub banned: bool,
}

