from datetime import datetime
from typing import Optional, TypedDict, Literal, Dict, Any

from pydantic import BaseModel, Field
from typing_extensions import Required

from .base import NotchPayResponse
from .channels import NotchPayChannels

__all__ = [
    "NotchPayBeneficiary",
    "NotchPayBeneficiaryCreate",
    "NotchPayBeneficiaryUpdate",
    "NotchPayBeneficiaryResponse",
]


class NotchPayBeneficiary(BaseModel):
    """Model representing a NotchPay beneficiary.

    Attributes:
        id: Unique beneficiary identifier.
        name: Beneficiary's full name.
        email: Beneficiary's email address.
        phone: Beneficiary's phone number.
        account_number: Bank account number.
        bank_code: Bank code.
        country: ISO two-letter country code.
        currency: ISO three-letter currency code.
        type: Beneficiary type (mobile_money, bank_account, cash_pickup).
        metadata: Custom metadata.
        sandbox: Sandbox environment indicator (1) or live (0).
        payment_method: Associated payment method.
        created_at: Beneficiary creation date.
        updated_at: Last update date.
    """

    id: str = Field(..., description="Unique beneficiary identifier")
    name: str = Field(..., description="Beneficiary's full name")
    email: Optional[str] = Field(None, description="Email address")
    phone: Optional[str] = Field(None, description="Phone number")
    account_number: Optional[str] = Field(None, description="Bank account number")
    bank_code: Optional[str] = Field(None, description="Bank code")
    country: str = Field(..., description="ISO country code")
    currency: Optional[str] = Field(None, description="ISO currency code")
    type: Optional[Literal["mobile_money", "bank_account", "cash_pickup"]] = Field(None,
                                                                                   description="Beneficiary type")
    metadata: Optional[Dict[str, Any]] = Field(None, description="Custom metadata")
    sandbox: Optional[bool] = Field(None, description="Environment indicator")
    payment_method: Optional[str] = Field(None, description="Payment method")
    created_at: Optional[datetime] = Field(None, description="Creation date")
    updated_at: Optional[datetime] = Field(None, description="Update date")


class NotchPayBeneficiaryCreate(TypedDict, total=False):
    """Model for creating a beneficiary.

    Attributes:
        name: Beneficiary's full name (required).
        email: Email address.
        phone: Phone number (required for mobile_money).
        account_number: Account number (required for bank_account). Can also be the beneficiary's phone number
        bank_code: Bank code (required for bank_account).
        country: ISO two-letter country code (required).
        currency: ISO three-letter currency code (required).
        type: Beneficiary type.
        channel: Beneficiary channel (required).
        metadata: Custom metadata.
    """

    name: str
    """Beneficiary's full name (required)."""

    email: Optional[str]
    """Beneficiary's email address."""

    phone: Optional[str]
    """Beneficiary's phone number (required for mobile_money)."""

    account_number: Optional[str]
    """Beneficiary's account number (required for bank_account). Can also be the beneficiary's phone number"""

    bank_code: Optional[str]
    """Bank code (required for bank_account)."""

    country: str
    """ISO two-letter country code (required)."""

    currency: str
    """ISO three-letter currency code (required)."""

    type: Literal["mobile_money", "bank_account", "cash_pickup"]
    """Beneficiary type: mobile_money, bank_account or cash_pickup."""

    channel: Required[NotchPayChannels]
    """Beneficiary channel (required)."""

    metadata: Optional[Dict[str, Any]]
    """Additional data to attach to the beneficiary."""


class NotchPayBeneficiaryUpdate(TypedDict, total=False):
    """Model for updating a beneficiary.

    Note: The country, currency and type fields cannot be modified.
    """

    name: Optional[str]

    email: Optional[str]

    phone: Optional[str]

    account_number: Optional[str]

    bank_code: Optional[str]

    metadata: Optional[Dict[str, Any]]


class NotchPayBeneficiaryResponse(NotchPayResponse):
    """Beneficiary detail response."""

    beneficiary: NotchPayBeneficiary = Field(..., description="Beneficiary details")
