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

from __future__ import annotations
from datetime import datetime
from paygentic_sdk.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
    UnrecognizedStr,
)
import pydantic
from pydantic import model_serializer
from typing import Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypedDict


LineItemType = Union[
    Literal[
        "fee",
        "metered",
        "manual",
    ],
    UnrecognizedStr,
]
r"""The type of line item"""


LineItemStatus = Union[
    Literal[
        "pending",
        "invoiced",
    ],
    UnrecognizedStr,
]
r"""Whether this item is pending or already on an invoice"""


LineItemPaymentTerm = Union[
    Literal[
        "in_advance",
        "in_arrears",
    ],
    UnrecognizedStr,
]
r"""Payment term for fee items. Null for metered/manual lines"""


class LineItemTypedDict(TypedDict):
    id: str
    r"""The line item ID"""
    subscription_id: str
    r"""The subscription this line item belongs to"""
    type: LineItemType
    r"""The type of line item"""
    status: LineItemStatus
    r"""Whether this item is pending or already on an invoice"""
    display_name: str
    r"""Human-readable label shown on the invoice"""
    currency: str
    r"""ISO 4217 currency code (e.g., USD)"""
    period_start: datetime
    r"""Start of the billing period (inclusive)"""
    period_end: datetime
    r"""End of the billing period (exclusive)"""
    invoice_at: datetime
    r"""When this line item should be collected into an invoice"""
    unit_price: str
    r"""Price per unit in invoice currency"""
    created_at: datetime
    r"""When the line item was created"""
    updated_at: datetime
    r"""When the line item was last updated"""
    price_id: NotRequired[Nullable[str]]
    r"""The price ID associated with this line item"""
    invoice_id: NotRequired[Nullable[str]]
    r"""The invoice ID if this item has been invoiced"""
    description: NotRequired[Nullable[str]]
    r"""Optional longer description"""
    calculated_at: NotRequired[Nullable[datetime]]
    r"""When metered quantity was last computed"""
    quantity: NotRequired[Nullable[str]]
    r"""Units sold. Null for metered lines until invoice close"""
    metered_quantity: NotRequired[Nullable[str]]
    r"""Raw metered usage. Null for fee/manual lines"""
    payment_term: NotRequired[Nullable[LineItemPaymentTerm]]
    r"""Payment term for fee items. Null for metered/manual lines"""
    subtotal: NotRequired[str]
    r"""quantity x unitPrice, before discounts and taxes. Defaults to '0.00' when not yet calculated"""
    taxes_total: NotRequired[Nullable[str]]
    r"""Total tax amount for this line item in decimal format. Null until invoice calculation is complete"""
    total: NotRequired[str]
    r"""Final total after discounts and taxes. Defaults to '0.00' when not yet calculated"""
    estimated_metered_quantity: NotRequired[Nullable[str]]
    r"""Real-time estimated metered usage quantity. Only present for type=metered items during an active billing period. Null for fee/manual items or when estimation is unavailable."""
    estimated_subtotal: NotRequired[Nullable[str]]
    r"""Real-time estimated subtotal based on current metered usage. Only present for type=metered items during an active billing period. Null for fee/manual items or when estimation is unavailable."""


class LineItem(BaseModel):
    id: str
    r"""The line item ID"""

    subscription_id: Annotated[str, pydantic.Field(alias="subscriptionId")]
    r"""The subscription this line item belongs to"""

    type: LineItemType
    r"""The type of line item"""

    status: LineItemStatus
    r"""Whether this item is pending or already on an invoice"""

    display_name: Annotated[str, pydantic.Field(alias="displayName")]
    r"""Human-readable label shown on the invoice"""

    currency: str
    r"""ISO 4217 currency code (e.g., USD)"""

    period_start: Annotated[datetime, pydantic.Field(alias="periodStart")]
    r"""Start of the billing period (inclusive)"""

    period_end: Annotated[datetime, pydantic.Field(alias="periodEnd")]
    r"""End of the billing period (exclusive)"""

    invoice_at: Annotated[datetime, pydantic.Field(alias="invoiceAt")]
    r"""When this line item should be collected into an invoice"""

    unit_price: Annotated[str, pydantic.Field(alias="unitPrice")]
    r"""Price per unit in invoice currency"""

    created_at: Annotated[datetime, pydantic.Field(alias="createdAt")]
    r"""When the line item was created"""

    updated_at: Annotated[datetime, pydantic.Field(alias="updatedAt")]
    r"""When the line item was last updated"""

    price_id: Annotated[OptionalNullable[str], pydantic.Field(alias="priceId")] = UNSET
    r"""The price ID associated with this line item"""

    invoice_id: Annotated[OptionalNullable[str], pydantic.Field(alias="invoiceId")] = (
        UNSET
    )
    r"""The invoice ID if this item has been invoiced"""

    description: OptionalNullable[str] = UNSET
    r"""Optional longer description"""

    calculated_at: Annotated[
        OptionalNullable[datetime], pydantic.Field(alias="calculatedAt")
    ] = UNSET
    r"""When metered quantity was last computed"""

    quantity: OptionalNullable[str] = UNSET
    r"""Units sold. Null for metered lines until invoice close"""

    metered_quantity: Annotated[
        OptionalNullable[str], pydantic.Field(alias="meteredQuantity")
    ] = UNSET
    r"""Raw metered usage. Null for fee/manual lines"""

    payment_term: Annotated[
        OptionalNullable[LineItemPaymentTerm], pydantic.Field(alias="paymentTerm")
    ] = UNSET
    r"""Payment term for fee items. Null for metered/manual lines"""

    subtotal: Optional[str] = None
    r"""quantity x unitPrice, before discounts and taxes. Defaults to '0.00' when not yet calculated"""

    taxes_total: Annotated[
        OptionalNullable[str], pydantic.Field(alias="taxesTotal")
    ] = UNSET
    r"""Total tax amount for this line item in decimal format. Null until invoice calculation is complete"""

    total: Optional[str] = None
    r"""Final total after discounts and taxes. Defaults to '0.00' when not yet calculated"""

    estimated_metered_quantity: Annotated[
        OptionalNullable[str], pydantic.Field(alias="estimatedMeteredQuantity")
    ] = UNSET
    r"""Real-time estimated metered usage quantity. Only present for type=metered items during an active billing period. Null for fee/manual items or when estimation is unavailable."""

    estimated_subtotal: Annotated[
        OptionalNullable[str], pydantic.Field(alias="estimatedSubtotal")
    ] = UNSET
    r"""Real-time estimated subtotal based on current metered usage. Only present for type=metered items during an active billing period. Null for fee/manual items or when estimation is unavailable."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "priceId",
                "invoiceId",
                "description",
                "calculatedAt",
                "quantity",
                "meteredQuantity",
                "paymentTerm",
                "subtotal",
                "taxesTotal",
                "total",
                "estimatedMeteredQuantity",
                "estimatedSubtotal",
            ]
        )
        nullable_fields = set(
            [
                "priceId",
                "invoiceId",
                "description",
                "calculatedAt",
                "quantity",
                "meteredQuantity",
                "paymentTerm",
                "taxesTotal",
                "estimatedMeteredQuantity",
                "estimatedSubtotal",
            ]
        )
        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:
    LineItem.model_rebuild()
except NameError:
    pass
