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

from pydantic import BaseModel, Field
from typing_extensions import Required

from .base import NotchPayResponse
from .channels import NotchPayChannels

__all__ = [
    "NotchPayTransfer",
    "NotchPayTransferCreate",
    "NotchPayTransferResponse",
    "NotchPayBeneficiaryData",
    "NotchPayTransferStatus",
    "NotchPayBulkTransfer",
    "NotchPayBulkTransferCreate",
    "NotchPayBulkTransferResponse",
    "NotchPayBulkTransferItem",
]

NotchPayTransferStatus = Literal["pending", "processing", "complete", "failed", "canceled"]


class NotchPayTransfer(BaseModel):
    """Model representing a NotchPay transfer.

    Attributes:
        id: Unique transfer identifier.
        reference: Custom transfer reference.
        amount: Transfer amount.
        currency: Currency code.
        status: Transfer status.
        beneficiary: Beneficiary identifier.
        channel: Payment channel used.
        description: Transfer description.
        metadata: Additional metadata.
        created_at: Transfer creation date.
        completed_at: Transfer completion date.
    """

    id: str = Field(..., description="Unique transfer identifier")
    reference: Optional[str] = Field(None, description="Custom reference")
    amount: float = Field(..., description="Transfer amount")
    currency: str = Field(..., description="Currency code")
    status: NotchPayTransferStatus = Field(..., description="Transfer status")
    beneficiary: str = Field(..., description="Beneficiary identifier")
    channel: NotchPayChannels = Field(..., description="Payment channel used")
    description: Optional[str] = Field(None, description="Transfer description")
    metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata")
    created_at: datetime = Field(..., description="Creation date")
    completed_at: Optional[datetime] = Field(None, description="Completion date")


class NotchPayBeneficiaryData(TypedDict, total=False):
    """Beneficiary data for creating a transfer without an existing beneficiary."""

    name: Required[str]
    """Beneficiary's full name."""

    phone: Required[str]
    """Beneficiary's phone number."""

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

    account_number: Optional[str]
    """Bank account number."""

    bank_code: Optional[str]
    """Bank code."""

    country: Optional[str]
    """ISO two-letter country code."""


class NotchPayTransferCreate(TypedDict, total=False):
    """Model for creating a transfer.

    Attributes:
        amount: Transfer amount (required).
        currency: Currency code (required).
        beneficiary: Existing beneficiary ID.
        beneficiary_data: Beneficiary data if no ID provided.
        channel: Payment channel to use (required).
        description: Transfer description.
        reference: Custom unique reference.
        metadata: Additional metadata.
    """

    amount: Required[float]
    """Transfer amount in smallest currency unit."""

    currency: Required[str]
    """ISO three-letter currency code (e.g., XAF)."""

    beneficiary: Optional[str]
    """Existing beneficiary ID (required if beneficiary_data is not provided)."""

    beneficiary_data: Optional[NotchPayBeneficiaryData]
    """Beneficiary details (required if beneficiary is not provided)."""

    channel: Required[NotchPayChannels]
    """Payment channel to use for the transfer."""

    description: Optional[str]
    """Transfer description."""

    reference: Optional[str]
    """Unique reference for the transfer."""

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


class NotchPayTransferResponse(NotchPayResponse):
    """Transfer detail response."""

    transfer: NotchPayTransfer = Field(..., description="Transfer details")


class NotchPayBulkTransferItem(TypedDict, total=False):
    """Transfer item for a bulk transfer."""

    amount: Required[float]
    """Transfer amount."""

    beneficiary: Optional[str]
    """Existing beneficiary ID."""

    beneficiary_data: Optional[NotchPayBeneficiaryData]
    """Beneficiary details if no ID provided."""

    channel: Required[NotchPayChannels]
    """Payment channel to use."""

    reference: Optional[str]
    """Unique reference for this transfer."""

    description: Optional[str]
    """Description of this transfer."""


class NotchPayBulkTransferCreate(TypedDict, total=False):
    """Model for creating a bulk transfer.

    Attributes:
        currency: Currency code for all transfers (required).
        transfers: List of transfers to perform (required).
        description: Bulk transfer description.
    """

    currency: Required[str]
    """ISO three-letter currency code for all transfers."""

    transfers: Required[List[NotchPayBulkTransferItem]]
    """List of transfers to perform."""

    description: Optional[str]
    """Bulk transfer description."""


class NotchPayBulkTransfer(BaseModel):
    """Model representing a bulk transfer.

    Attributes:
        id: Unique identifier for the bulk transfer.
        description: Bulk transfer description.
        currency: Currency code.
        total_amount: Total amount of all transfers.
        total_transfers: Total number of transfers.
        created_at: Creation date.
        transfers: List of individual transfers.
    """

    id: str = Field(..., description="Unique identifier for the bulk transfer")
    description: Optional[str] = Field(None, description="Bulk transfer description")
    currency: str = Field(..., description="Currency code")
    total_amount: float = Field(..., description="Total amount of all transfers")
    total_transfers: int = Field(..., description="Total number of transfers")
    created_at: datetime = Field(..., description="Creation date")
    transfers: List[NotchPayTransfer] = Field(..., description="List of individual transfers")


class NotchPayBulkTransferResponse(NotchPayResponse):
    """Bulk transfer detail response."""

    bulk_transfer: NotchPayBulkTransfer = Field(..., description="Bulk transfer details")
