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

from __future__ import annotations
from ascend_sdk import utils
from ascend_sdk.types import (
    BaseModel,
    Nullable,
    OptionalNullable,
    UNSET,
    UNSET_SENTINEL,
)
from ascend_sdk.utils import validate_open_enum
from datetime import datetime
from enum import Enum
from pydantic import model_serializer
from pydantic.functional_validators import PlainValidator
from typing import Any, Dict, Optional
from typing_extensions import Annotated, NotRequired, TypedDict


class BankRelationshipType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The bank account type."""

    TYPE_UNSPECIFIED = "TYPE_UNSPECIFIED"
    CHECKING = "CHECKING"
    SAVINGS = "SAVINGS"


class BankAccountTypedDict(TypedDict):
    r"""The bank account for the relationship. This field must be set on create requests **except** when using the `PLAID_TOKEN` verification method. In which case, the bank account will be retrieved by the service based on the `plaid_processor_token`."""

    account_number: NotRequired[str]
    r"""The bank account number. This value will be masked in responses."""
    owner: NotRequired[str]
    r"""The name of the bank account owner."""
    routing_number: NotRequired[str]
    r"""The bank routing number (either ABA or BIC)."""
    type: NotRequired[BankRelationshipType]
    r"""The bank account type."""


class BankAccount(BaseModel):
    r"""The bank account for the relationship. This field must be set on create requests **except** when using the `PLAID_TOKEN` verification method. In which case, the bank account will be retrieved by the service based on the `plaid_processor_token`."""

    account_number: Optional[str] = None
    r"""The bank account number. This value will be masked in responses."""

    owner: Optional[str] = None
    r"""The name of the bank account owner."""

    routing_number: Optional[str] = None
    r"""The bank routing number (either ABA or BIC)."""

    type: Annotated[
        Optional[BankRelationshipType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The bank account type."""


class BankRelationshipStateState(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The high level state of the bank relationship."""

    STATE_UNSPECIFIED = "STATE_UNSPECIFIED"
    PENDING = "PENDING"
    APPROVED = "APPROVED"
    CANCELED = "CANCELED"
    REJECTED = "REJECTED"


class BankRelationshipStateTypedDict(TypedDict):
    r"""The state of the bank relationship."""

    actor: NotRequired[str]
    r"""The user or service that triggered the state update."""
    metadata: NotRequired[Nullable[Dict[str, Any]]]
    r"""Additional metadata relating to the bank relationship state. Included data will depend on the state. Examples:
    - rejection reasons are included when the state is `REJECTED`
    - comment and reason are included when the state is `CANCELED`
    """
    state: NotRequired[BankRelationshipStateState]
    r"""The high level state of the bank relationship."""
    update_time: NotRequired[Nullable[datetime]]
    r"""The time of the state update."""


class BankRelationshipState(BaseModel):
    r"""The state of the bank relationship."""

    actor: Optional[str] = None
    r"""The user or service that triggered the state update."""

    metadata: OptionalNullable[Dict[str, Any]] = UNSET
    r"""Additional metadata relating to the bank relationship state. Included data will depend on the state. Examples:
    - rejection reasons are included when the state is `REJECTED`
    - comment and reason are included when the state is `CANCELED`
    """

    state: Annotated[
        Optional[BankRelationshipStateState], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The high level state of the bank relationship."""

    update_time: OptionalNullable[datetime] = UNSET
    r"""The time of the state update."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["actor", "metadata", "state", "update_time"]
        nullable_fields = ["metadata", "update_time"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in 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 BankRelationshipVerificationMethod(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The verification method of the bank relationship."""

    VERIFICATION_METHOD_UNSPECIFIED = "VERIFICATION_METHOD_UNSPECIFIED"
    MICRO_DEPOSIT = "MICRO_DEPOSIT"
    YODLEE = "YODLEE"
    QUOVO = "QUOVO"
    GIACT = "GIACT"
    SYNAPSE = "SYNAPSE"
    SOPHTRON = "SOPHTRON"
    USE_EXISTING = "USE_EXISTING"
    INTERNAL_BANK = "INTERNAL_BANK"
    MX = "MX"
    FISERV = "FISERV"
    PLAID_TOKEN = "PLAID_TOKEN"


class BankRelationshipTypedDict(TypedDict):
    r"""A relationship between a bank account and an Apex account."""

    bank_account: NotRequired[Nullable[BankAccountTypedDict]]
    r"""The bank account for the relationship. This field must be set on create requests **except** when using the `PLAID_TOKEN` verification method. In which case, the bank account will be retrieved by the service based on the `plaid_processor_token`."""
    create_time: NotRequired[Nullable[datetime]]
    r"""Creation time of the bank relationship."""
    name: NotRequired[str]
    r"""The resource name of the bank relationship."""
    nickname: NotRequired[str]
    r"""The nickname of the bank relationship."""
    plaid_processor_token: NotRequired[str]
    r"""A processor token from Plaid (vendor). Required if using `PLAID_TOKEN` verification method."""
    state: NotRequired[Nullable[BankRelationshipStateTypedDict]]
    r"""The state of the bank relationship."""
    verification_method: NotRequired[BankRelationshipVerificationMethod]
    r"""The verification method of the bank relationship."""


class BankRelationship(BaseModel):
    r"""A relationship between a bank account and an Apex account."""

    bank_account: OptionalNullable[BankAccount] = UNSET
    r"""The bank account for the relationship. This field must be set on create requests **except** when using the `PLAID_TOKEN` verification method. In which case, the bank account will be retrieved by the service based on the `plaid_processor_token`."""

    create_time: OptionalNullable[datetime] = UNSET
    r"""Creation time of the bank relationship."""

    name: Optional[str] = None
    r"""The resource name of the bank relationship."""

    nickname: Optional[str] = None
    r"""The nickname of the bank relationship."""

    plaid_processor_token: Optional[str] = None
    r"""A processor token from Plaid (vendor). Required if using `PLAID_TOKEN` verification method."""

    state: OptionalNullable[BankRelationshipState] = UNSET
    r"""The state of the bank relationship."""

    verification_method: Annotated[
        Optional[BankRelationshipVerificationMethod],
        PlainValidator(validate_open_enum(False)),
    ] = None
    r"""The verification method of the bank relationship."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "bank_account",
            "create_time",
            "name",
            "nickname",
            "plaid_processor_token",
            "state",
            "verification_method",
        ]
        nullable_fields = ["bank_account", "create_time", "state"]
        null_default_fields = []

        serialized = handler(self)

        m = {}

        for n, f in 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
