"""Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT."""

from __future__ import annotations
from datetime import datetime
from pydantic import model_serializer
from tofupilot.v2.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
from tofupilot.v2.utils import FieldMetadata, QueryParamMetadata
from typing import List, Literal, Optional
from typing_extensions import Annotated, NotRequired, TypedDict


UnitListSortBy = Literal["serial_number", "created_at"]
r"""Field to sort results by."""

UnitListSortOrder = Literal["asc", "desc"]
r"""Sort order direction."""


class UnitListRequestTypedDict(TypedDict):
    search_query: NotRequired[str]
    ids: NotRequired[List[str]]
    serial_numbers: NotRequired[List[str]]
    part_numbers: NotRequired[List[str]]
    revision_numbers: NotRequired[List[str]]
    batch_numbers: NotRequired[List[str]]
    created_after: NotRequired[datetime]
    created_before: NotRequired[datetime]
    created_by_user_ids: NotRequired[List[str]]
    created_by_station_ids: NotRequired[List[str]]
    exclude_units_with_parent: NotRequired[bool]
    limit: NotRequired[int]
    cursor: NotRequired[int]
    sort_by: NotRequired[UnitListSortBy]
    r"""Field to sort results by."""
    sort_order: NotRequired[UnitListSortOrder]
    r"""Sort order direction."""


class UnitListRequest(BaseModel):
    search_query: Annotated[
        Optional[str],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    ids: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    serial_numbers: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    part_numbers: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    revision_numbers: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    batch_numbers: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    created_after: Annotated[
        Optional[datetime],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    created_before: Annotated[
        Optional[datetime],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    created_by_user_ids: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    created_by_station_ids: Annotated[
        Optional[List[str]],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    exclude_units_with_parent: Annotated[
        Optional[bool],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = False

    limit: Annotated[
        Optional[int],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = 50

    cursor: Annotated[
        Optional[int],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = None

    sort_by: Annotated[
        Optional[UnitListSortBy],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = "created_at"
    r"""Field to sort results by."""

    sort_order: Annotated[
        Optional[UnitListSortOrder],
        FieldMetadata(query=QueryParamMetadata(style="form", explode=True)),
    ] = "desc"
    r"""Sort order direction."""


class UnitListCreatedByUserTypedDict(TypedDict):
    r"""User who created this unit. Null if created by a station or system."""

    id: str
    r"""Unique identifier for the user."""
    name: Nullable[str]
    r"""Display name of the user who created this unit."""
    image: Nullable[str]
    r"""Profile image URL for the user."""


class UnitListCreatedByUser(BaseModel):
    r"""User who created this unit. Null if created by a station or system."""

    id: str
    r"""Unique identifier for the user."""

    name: Nullable[str]
    r"""Display name of the user who created this unit."""

    image: Nullable[str]
    r"""Profile image URL for the user."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = []
        nullable_fields = ["name", "image"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class UnitListCreatedByStationTypedDict(TypedDict):
    r"""Station that created this unit. Null if created by a user."""

    id: str
    r"""Unique identifier for the station."""
    name: str
    r"""Name of the station that created this unit."""
    image: Nullable[str]
    r"""Station image URL."""


class UnitListCreatedByStation(BaseModel):
    r"""Station that created this unit. Null if created by a user."""

    id: str
    r"""Unique identifier for the station."""

    name: str
    r"""Name of the station that created this unit."""

    image: Nullable[str]
    r"""Station image URL."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = []
        nullable_fields = ["image"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class UnitListBatchTypedDict(TypedDict):
    r"""Production batch this unit belongs to. Null if not part of a batch."""

    id: str
    r"""Unique identifier for the batch."""
    number: str
    r"""Human-readable batch number."""


class UnitListBatch(BaseModel):
    r"""Production batch this unit belongs to. Null if not part of a batch."""

    id: str
    r"""Unique identifier for the batch."""

    number: str
    r"""Human-readable batch number."""


class UnitListParentTypedDict(TypedDict):
    r"""Parent unit in the assembly hierarchy. Null if this is a top-level unit."""

    id: str
    r"""Unique identifier for the parent unit."""
    serial_number: str
    r"""Serial number of the parent unit."""


class UnitListParent(BaseModel):
    r"""Parent unit in the assembly hierarchy. Null if this is a top-level unit."""

    id: str
    r"""Unique identifier for the parent unit."""

    serial_number: str
    r"""Serial number of the parent unit."""


class UnitListChildTypedDict(TypedDict):
    id: str
    r"""Unique identifier for the child unit."""
    serial_number: str
    r"""Serial number of the child unit."""


class UnitListChild(BaseModel):
    id: str
    r"""Unique identifier for the child unit."""

    serial_number: str
    r"""Serial number of the child unit."""


class UnitListRevisionTypedDict(TypedDict):
    r"""Revision information for this part. Every unit must have a specific revision."""

    id: str
    r"""Unique identifier for the revision."""
    number: str
    r"""Revision number (e.g., version) of the part."""
    image: Nullable[str]
    r"""Image URL showing the revision design or documentation."""


class UnitListRevision(BaseModel):
    r"""Revision information for this part. Every unit must have a specific revision."""

    id: str
    r"""Unique identifier for the revision."""

    number: str
    r"""Revision number (e.g., version) of the part."""

    image: Nullable[str]
    r"""Image URL showing the revision design or documentation."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = []
        nullable_fields = ["image"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class UnitListPartTypedDict(TypedDict):
    r"""Part information with the specific revision this unit is built from."""

    id: str
    r"""Unique identifier for the part."""
    number: str
    r"""Part number."""
    name: str
    r"""Human-readable part name."""
    revision: UnitListRevisionTypedDict
    r"""Revision information for this part. Every unit must have a specific revision."""


class UnitListPart(BaseModel):
    r"""Part information with the specific revision this unit is built from."""

    id: str
    r"""Unique identifier for the part."""

    number: str
    r"""Part number."""

    name: str
    r"""Human-readable part name."""

    revision: UnitListRevision
    r"""Revision information for this part. Every unit must have a specific revision."""


UnitListOutcome = Literal["PASS", "FAIL", "ERROR", "TIMEOUT", "ABORTED"]
r"""Final result of the test run execution."""


class UnitListProcedureTypedDict(TypedDict):
    r"""Test procedure that was executed. Null if run had no associated procedure."""

    id: str
    r"""Unique identifier for the procedure."""
    name: str
    r"""Name of the test procedure that was executed."""


class UnitListProcedure(BaseModel):
    r"""Test procedure that was executed. Null if run had no associated procedure."""

    id: str
    r"""Unique identifier for the procedure."""

    name: str
    r"""Name of the test procedure that was executed."""


class LastRunTypedDict(TypedDict):
    r"""Most recent test run performed on this unit. Null if no runs have been executed."""

    id: str
    r"""Unique identifier for the run."""
    outcome: UnitListOutcome
    r"""Final result of the test run execution."""
    started_at: datetime
    r"""ISO 8601 timestamp when the run execution started."""
    ended_at: Nullable[datetime]
    r"""ISO 8601 timestamp when the run execution completed. Null if still running."""
    procedure: Nullable[UnitListProcedureTypedDict]
    r"""Test procedure that was executed. Null if run had no associated procedure."""


class LastRun(BaseModel):
    r"""Most recent test run performed on this unit. Null if no runs have been executed."""

    id: str
    r"""Unique identifier for the run."""

    outcome: UnitListOutcome
    r"""Final result of the test run execution."""

    started_at: datetime
    r"""ISO 8601 timestamp when the run execution started."""

    ended_at: Nullable[datetime]
    r"""ISO 8601 timestamp when the run execution completed. Null if still running."""

    procedure: Nullable[UnitListProcedure]
    r"""Test procedure that was executed. Null if run had no associated procedure."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = []
        nullable_fields = ["ended_at", "procedure"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class UnitListDataTypedDict(TypedDict):
    id: str
    r"""Unique identifier for the unit."""
    serial_number: str
    r"""Human-readable serial number assigned to the unit."""
    created_at: datetime
    r"""ISO 8601 timestamp when the unit was created."""
    children: List[UnitListChildTypedDict]
    r"""Array of child units assembled into this unit. Empty array if no children."""
    part: UnitListPartTypedDict
    r"""Part information with the specific revision this unit is built from."""
    created_by_user: NotRequired[Nullable[UnitListCreatedByUserTypedDict]]
    r"""User who created this unit. Null if created by a station or system."""
    created_by_station: NotRequired[Nullable[UnitListCreatedByStationTypedDict]]
    r"""Station that created this unit. Null if created by a user."""
    batch: NotRequired[Nullable[UnitListBatchTypedDict]]
    r"""Production batch this unit belongs to. Null if not part of a batch."""
    parent: NotRequired[Nullable[UnitListParentTypedDict]]
    r"""Parent unit in the assembly hierarchy. Null if this is a top-level unit."""
    last_run: NotRequired[Nullable[LastRunTypedDict]]
    r"""Most recent test run performed on this unit. Null if no runs have been executed."""


class UnitListData(BaseModel):
    id: str
    r"""Unique identifier for the unit."""

    serial_number: str
    r"""Human-readable serial number assigned to the unit."""

    created_at: datetime
    r"""ISO 8601 timestamp when the unit was created."""

    children: List[UnitListChild]
    r"""Array of child units assembled into this unit. Empty array if no children."""

    part: UnitListPart
    r"""Part information with the specific revision this unit is built from."""

    created_by_user: OptionalNullable[UnitListCreatedByUser] = UNSET
    r"""User who created this unit. Null if created by a station or system."""

    created_by_station: OptionalNullable[UnitListCreatedByStation] = UNSET
    r"""Station that created this unit. Null if created by a user."""

    batch: OptionalNullable[UnitListBatch] = UNSET
    r"""Production batch this unit belongs to. Null if not part of a batch."""

    parent: OptionalNullable[UnitListParent] = UNSET
    r"""Parent unit in the assembly hierarchy. Null if this is a top-level unit."""

    last_run: OptionalNullable[LastRun] = UNSET
    r"""Most recent test run performed on this unit. Null if no runs have been executed."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "created_by_user",
            "created_by_station",
            "batch",
            "parent",
            "last_run",
        ]
        nullable_fields = [
            "created_by_user",
            "created_by_station",
            "batch",
            "parent",
            "last_run",
        ]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class UnitListMetaTypedDict(TypedDict):
    has_more: bool
    r"""Whether there are more results available for pagination."""
    next_cursor: Nullable[int]
    r"""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."""


class UnitListMeta(BaseModel):
    has_more: bool
    r"""Whether there are more results available for pagination."""

    next_cursor: Nullable[int]
    r"""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."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = []
        nullable_fields = ["next_cursor"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k)
            serialized.pop(k, None)

            optional_nullable = k in optional_fields and k in nullable_fields
            is_set = (
                self.__pydantic_fields_set__.intersection({n})
                or k in null_default_fields
            )  # pylint: disable=no-member

            if val is not None and val != UNSET_SENTINEL:
                m[k] = val
            elif val != UNSET_SENTINEL and (
                not k in optional_fields or (optional_nullable and is_set)
            ):
                m[k] = val

        return m


class UnitListResponseTypedDict(TypedDict):
    r"""Units retrieved successfully"""

    data: List[UnitListDataTypedDict]
    meta: UnitListMetaTypedDict


class UnitListResponse(BaseModel):
    r"""Units retrieved successfully"""

    data: List[UnitListData]

    meta: UnitListMeta
