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

from __future__ import annotations
from .amountdecimalupdate import AmountDecimalUpdate, AmountDecimalUpdateTypedDict
from .createinvoicelineitemsupdate import (
    CreateInvoiceLineItemsUpdate,
    CreateInvoiceLineItemsUpdateTypedDict,
)
from .invoicestatus import InvoiceStatus
from datetime import datetime
from moovio_sdk.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
import pydantic
from pydantic import model_serializer
from typing import Optional
from typing_extensions import Annotated, NotRequired, TypedDict


class UpdateInvoiceTypedDict(TypedDict):
    description: NotRequired[str]
    line_items: NotRequired[CreateInvoiceLineItemsUpdateTypedDict]
    r"""A collection of line items for an invoice."""
    invoice_date: NotRequired[Nullable[datetime]]
    due_date: NotRequired[Nullable[datetime]]
    status: NotRequired[InvoiceStatus]
    r"""The status can be updated to one of the following values under specific conditions:
    - `canceled`: Can only be set if the current status is `draft`, `unpaid`, or `overdue`. Canceling an invoice
    indicates the invoice is no longer expected to be paid (e.g., the charge was waived or terms changed).
    Canceled invoices still appear in list results by default and remain part of the invoice history.
    To completely discard an invoice created by mistake, use the delete endpoint instead.
    - `unpaid`: Can only be set if the current status is `draft`. Setting the status to `unpaid` finalizes the invoice and sends an email with a payment link to the customer.
    """
    tax_amount: NotRequired[AmountDecimalUpdateTypedDict]


class UpdateInvoice(BaseModel):
    description: Optional[str] = None

    line_items: Annotated[
        Optional[CreateInvoiceLineItemsUpdate], pydantic.Field(alias="lineItems")
    ] = None
    r"""A collection of line items for an invoice."""

    invoice_date: Annotated[
        OptionalNullable[datetime], pydantic.Field(alias="invoiceDate")
    ] = UNSET

    due_date: Annotated[OptionalNullable[datetime], pydantic.Field(alias="dueDate")] = (
        UNSET
    )

    status: Optional[InvoiceStatus] = None
    r"""The status can be updated to one of the following values under specific conditions:
    - `canceled`: Can only be set if the current status is `draft`, `unpaid`, or `overdue`. Canceling an invoice
    indicates the invoice is no longer expected to be paid (e.g., the charge was waived or terms changed).
    Canceled invoices still appear in list results by default and remain part of the invoice history.
    To completely discard an invoice created by mistake, use the delete endpoint instead.
    - `unpaid`: Can only be set if the current status is `draft`. Setting the status to `unpaid` finalizes the invoice and sends an email with a payment link to the customer.
    """

    tax_amount: Annotated[
        Optional[AmountDecimalUpdate], pydantic.Field(alias="taxAmount")
    ] = None

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "description",
                "lineItems",
                "invoiceDate",
                "dueDate",
                "status",
                "taxAmount",
            ]
        )
        nullable_fields = set(["invoiceDate", "dueDate"])
        serialized = handler(self)
        m = {}

        for n, f in type(self).model_fields.items():
            k = f.alias or n
            val = serialized.get(k, serialized.get(n))
            is_nullable_and_explicitly_set = (
                k in nullable_fields
                and (self.__pydantic_fields_set__.intersection({n}))  # pylint: disable=no-member
            )

            if val != UNSET_SENTINEL:
                if (
                    val is not None
                    or k not in optional_fields
                    or is_nullable_and_explicitly_set
                ):
                    m[k] = val

        return m


try:
    UpdateInvoice.model_rebuild()
except NameError:
    pass
