"""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 AmountTypedDict(TypedDict):
    r"""The amount to deposit in USD."""

    value: NotRequired[str]
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class Amount(BaseModel):
    r"""The amount to deposit in USD."""

    value: Optional[str] = None
    r"""The decimal value, as a string; Refer to [Google’s Decimal type protocol buffer](https://github.com/googleapis/googleapis/blob/40203ca1880849480bbff7b8715491060bbccdf1/google/type/decimal.proto#L33) for details"""


class AchDepositType(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The type of retirement contribution."""

    TYPE_UNSPECIFIED = "TYPE_UNSPECIFIED"
    REGULAR = "REGULAR"
    EMPLOYEE = "EMPLOYEE"
    EMPLOYER = "EMPLOYER"
    RECHARACTERIZATION = "RECHARACTERIZATION"
    ROLLOVER_60_DAY = "ROLLOVER_60_DAY"
    ROLLOVER_DIRECT = "ROLLOVER_DIRECT"
    TRANSFER = "TRANSFER"
    TRUSTEE_FEE = "TRUSTEE_FEE"
    CONVERSION = "CONVERSION"
    REPAYMENT = "REPAYMENT"


class RetirementContributionTypedDict(TypedDict):
    r"""The retirement contribution details."""

    tax_year: NotRequired[int]
    r"""Tax year for which the contribution is applied. Current year is always valid; prior year is only valid before tax deadline. Must be in \"YYYY\" format."""
    type: NotRequired[AchDepositType]
    r"""The type of retirement contribution."""


class RetirementContribution(BaseModel):
    r"""The retirement contribution details."""

    tax_year: Optional[int] = None
    r"""Tax year for which the contribution is applied. Current year is always valid; prior year is only valid before tax deadline. Must be in \"YYYY\" format."""

    type: Annotated[
        Optional[AchDepositType], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The type of retirement contribution."""


class AchDepositStateState(str, Enum, metaclass=utils.OpenEnumMeta):
    r"""The high level state of a transfer, one of:
    - `PROCESSING` - The transfer is being processed and will be posted if successful.
    - `PENDING_REVIEW` - The transfer is pending review and will continue processing if approved.
    - `POSTED` - The transfer has been posted to the ledger and will be completed at the end of the processing window if not canceled first.
    - `COMPLETED` - The transfer has been batched and completed.
    - `REJECTED` - The transfer was rejected.
    - `CANCELED` - The transfer was canceled.
    - `RETURNED` - The transfer was returned.
    - `POSTPONED` - The transfer is postponed and will resume processing during the next processing window.
    """

    STATE_UNSPECIFIED = "STATE_UNSPECIFIED"
    PROCESSING = "PROCESSING"
    PENDING_REVIEW = "PENDING_REVIEW"
    POSTED = "POSTED"
    COMPLETED = "COMPLETED"
    REJECTED = "REJECTED"
    CANCELED = "CANCELED"
    RETURNED = "RETURNED"
    POSTPONED = "POSTPONED"


class AchDepositStateTypedDict(TypedDict):
    r"""The current state of the ACH deposit."""

    actor: NotRequired[str]
    r"""The user or service that triggered the state update."""
    message: NotRequired[str]
    r"""Additional description of the transfer state."""
    metadata: NotRequired[Nullable[Dict[str, Any]]]
    r"""Additional metadata relating to the transfer state. Included data depends on the state, e.g.:
    - Rejection reasons are included when the `state` is `REJECTED`
    - Reason and comment are included when `state` is `CANCELED`
    """
    state: NotRequired[AchDepositStateState]
    r"""The high level state of a transfer, one of:
    - `PROCESSING` - The transfer is being processed and will be posted if successful.
    - `PENDING_REVIEW` - The transfer is pending review and will continue processing if approved.
    - `POSTED` - The transfer has been posted to the ledger and will be completed at the end of the processing window if not canceled first.
    - `COMPLETED` - The transfer has been batched and completed.
    - `REJECTED` - The transfer was rejected.
    - `CANCELED` - The transfer was canceled.
    - `RETURNED` - The transfer was returned.
    - `POSTPONED` - The transfer is postponed and will resume processing during the next processing window.
    """
    update_time: NotRequired[Nullable[datetime]]
    r"""The time of the state update."""


class AchDepositState(BaseModel):
    r"""The current state of the ACH deposit."""

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

    message: Optional[str] = None
    r"""Additional description of the transfer state."""

    metadata: OptionalNullable[Dict[str, Any]] = UNSET
    r"""Additional metadata relating to the transfer state. Included data depends on the state, e.g.:
    - Rejection reasons are included when the `state` is `REJECTED`
    - Reason and comment are included when `state` is `CANCELED`
    """

    state: Annotated[
        Optional[AchDepositStateState], PlainValidator(validate_open_enum(False))
    ] = None
    r"""The high level state of a transfer, one of:
    - `PROCESSING` - The transfer is being processed and will be posted if successful.
    - `PENDING_REVIEW` - The transfer is pending review and will continue processing if approved.
    - `POSTED` - The transfer has been posted to the ledger and will be completed at the end of the processing window if not canceled first.
    - `COMPLETED` - The transfer has been batched and completed.
    - `REJECTED` - The transfer was rejected.
    - `CANCELED` - The transfer was canceled.
    - `RETURNED` - The transfer was returned.
    - `POSTPONED` - The transfer is postponed and will resume processing during the next processing window.
    """

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

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = ["actor", "message", "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 AchDepositTypedDict(TypedDict):
    r"""A deposit transfer using the ACH mechanism."""

    amount: NotRequired[Nullable[AmountTypedDict]]
    r"""The amount to deposit in USD."""
    bank_relationship: NotRequired[str]
    r"""The bank relationship to be used for the ACH deposit."""
    client_transfer_id: NotRequired[str]
    r"""The external identifier supplied by the API caller. Each request must have a unique pairing of `client_transfer_id` and `account`."""
    memo: NotRequired[str]
    r"""The memo that will appear on the customer's bank statement."""
    name: NotRequired[str]
    r"""The resource name of the ACH deposit."""
    retirement_contribution: NotRequired[Nullable[RetirementContributionTypedDict]]
    r"""The retirement contribution details."""
    state: NotRequired[Nullable[AchDepositStateTypedDict]]
    r"""The current state of the ACH deposit."""


class AchDeposit(BaseModel):
    r"""A deposit transfer using the ACH mechanism."""

    amount: OptionalNullable[Amount] = UNSET
    r"""The amount to deposit in USD."""

    bank_relationship: Optional[str] = None
    r"""The bank relationship to be used for the ACH deposit."""

    client_transfer_id: Optional[str] = None
    r"""The external identifier supplied by the API caller. Each request must have a unique pairing of `client_transfer_id` and `account`."""

    memo: Optional[str] = None
    r"""The memo that will appear on the customer's bank statement."""

    name: Optional[str] = None
    r"""The resource name of the ACH deposit."""

    retirement_contribution: OptionalNullable[RetirementContribution] = UNSET
    r"""The retirement contribution details."""

    state: OptionalNullable[AchDepositState] = UNSET
    r"""The current state of the ACH deposit."""

    @model_serializer(mode="wrap")
    def serialize_model(self, handler):
        optional_fields = [
            "amount",
            "bank_relationship",
            "client_transfer_id",
            "memo",
            "name",
            "retirement_contribution",
            "state",
        ]
        nullable_fields = ["amount", "retirement_contribution", "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
