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

from __future__ import annotations
import pydantic
from pydantic import model_serializer
from pydantic.functional_validators import AfterValidator
from train_travel.types import BaseModel, UNSET_SENTINEL
from train_travel.utils import validate_const
from typing import Literal, Optional, Union
from typing_extensions import Annotated, NotRequired, TypeAliasType, TypedDict


Currency = Literal[
    "bam",
    "bgn",
    "chf",
    "eur",
    "gbp",
    "nok",
    "sek",
    "try",
]
r"""Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase."""


AccountType = Literal[
    "individual",
    "company",
]
r"""The type of entity that holds the account. This can be either `individual` or `company`."""


class BankAccountTypedDict(TypedDict):
    r"""A bank account to take payment from. Must be able to make payments in the currency specified in the payment."""

    name: str
    number: str
    r"""The account number for the bank account, in string form. Must be a current account."""
    account_type: AccountType
    r"""The type of entity that holds the account. This can be either `individual` or `company`."""
    bank_name: str
    r"""The name of the bank associated with the routing number."""
    country: str
    r"""Two-letter country code (ISO 3166-1 alpha-2)."""
    object: Literal["bank_account"]
    sort_code: NotRequired[str]
    r"""The sort code for the bank account, in string form. Must be a six-digit number."""


class BankAccount(BaseModel):
    r"""A bank account to take payment from. Must be able to make payments in the currency specified in the payment."""

    name: str

    number: str
    r"""The account number for the bank account, in string form. Must be a current account."""

    account_type: AccountType
    r"""The type of entity that holds the account. This can be either `individual` or `company`."""

    bank_name: str
    r"""The name of the bank associated with the routing number."""

    country: str
    r"""Two-letter country code (ISO 3166-1 alpha-2)."""

    object: Annotated[
        Annotated[
            Optional[Literal["bank_account"]],
            AfterValidator(validate_const("bank_account")),
        ],
        pydantic.Field(alias="object"),
    ] = "bank_account"

    sort_code: Optional[str] = None
    r"""The sort code for the bank account, in string form. Must be a six-digit number."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["object", "sort_code"])
        serialized = handler(self)
        m = {}

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

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

        return m


class CardTypedDict(TypedDict):
    r"""A card (debit or credit) to take payment from."""

    name: str
    r"""Cardholder's full name as it appears on the card."""
    number: str
    r"""The card number, as a string without any separators. On read all but the last four digits will be masked for security."""
    cvc: str
    r"""Card security code, 3 or 4 digits usually found on the back of the card."""
    exp_month: int
    r"""Two-digit number representing the card's expiration month."""
    exp_year: int
    r"""Four-digit number representing the card's expiration year."""
    address_country: str
    object: Literal["card"]
    address_line1: NotRequired[str]
    address_line2: NotRequired[str]
    address_city: NotRequired[str]
    address_post_code: NotRequired[str]


class Card(BaseModel):
    r"""A card (debit or credit) to take payment from."""

    name: str
    r"""Cardholder's full name as it appears on the card."""

    number: str
    r"""The card number, as a string without any separators. On read all but the last four digits will be masked for security."""

    cvc: str
    r"""Card security code, 3 or 4 digits usually found on the back of the card."""

    exp_month: int
    r"""Two-digit number representing the card's expiration month."""

    exp_year: int
    r"""Four-digit number representing the card's expiration year."""

    address_country: str

    object: Annotated[
        Annotated[Optional[Literal["card"]], AfterValidator(validate_const("card"))],
        pydantic.Field(alias="object"),
    ] = "card"

    address_line1: Optional[str] = None

    address_line2: Optional[str] = None

    address_city: Optional[str] = None

    address_post_code: Optional[str] = None

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(
            [
                "object",
                "address_line1",
                "address_line2",
                "address_city",
                "address_post_code",
            ]
        )
        serialized = handler(self)
        m = {}

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

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

        return m


SourceTypedDict = TypeAliasType(
    "SourceTypedDict", Union[BankAccountTypedDict, CardTypedDict]
)
r"""The payment source to take the payment from. This can be a card or a bank account. Some of these properties will be hidden on read to protect PII leaking."""


Source = TypeAliasType("Source", Union[BankAccount, Card])
r"""The payment source to take the payment from. This can be a card or a bank account. Some of these properties will be hidden on read to protect PII leaking."""


class BookingPaymentTypedDict(TypedDict):
    r"""A payment for a booking."""

    amount: NotRequired[float]
    r"""Amount intended to be collected by this payment. A positive decimal figure describing the amount to be collected."""
    currency: NotRequired[Currency]
    r"""Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase."""
    source: NotRequired[SourceTypedDict]
    r"""The payment source to take the payment from. This can be a card or a bank account. Some of these properties will be hidden on read to protect PII leaking."""


class BookingPayment(BaseModel):
    r"""A payment for a booking."""

    amount: Optional[float] = None
    r"""Amount intended to be collected by this payment. A positive decimal figure describing the amount to be collected."""

    currency: Optional[Currency] = None
    r"""Three-letter [ISO currency code](https://www.iso.org/iso-4217-currency-codes.html), in lowercase."""

    source: Optional[Source] = None
    r"""The payment source to take the payment from. This can be a card or a bank account. Some of these properties will be hidden on read to protect PII leaking."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = set(["amount", "currency", "source"])
        serialized = handler(self)
        m = {}

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

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

        return m


try:
    BankAccount.model_rebuild()
except NameError:
    pass
try:
    Card.model_rebuild()
except NameError:
    pass
