"""Models for OxaPay Merchant API."""

from enum import Enum

from pydantic import BaseModel, Field

from .base import OrderDirection, PaginatedResponse, ResultResponse, SortField
from .common import (
    AddressMixin,
    AmountCurrencyMixin,
    DataResponse,
    PaymentDetailsMixin,
    TrackIdMixin,
)


# Common enums
class PaymentType(str, Enum):
    """Payment type enum."""

    INVOICE = "Invoice"
    WHITE_LABEL = "White-Label"
    STATIC_WALLET = "Static Wallet"


class PaymentStatus(str, Enum):
    """Payment status enum."""

    NEW = "new"
    WAITING = "waiting"
    CONFIRMING = "confirming"
    PAID = "paid"
    EXPIRED = "expired"
    FAILED = "failed"
    REJECTED = "rejected"


# Invoice creation
class CreateInvoiceRequest(BaseModel):
    """Request model for creating an invoice."""

    amount: float = Field(..., description="The amount for the payment")
    currency: str | None = Field(
        None,
        description="Invoice currency",
    )
    life_time: int | None = Field(
        None,
        ge=15,
        description="Expiration time in minutes (min 15)",
    )
    fee_paid_by_payer: int | None = Field(
        None,
        description="Fee paid by payer (1) or merchant (0)",
    )
    under_paid_cover: float | None = Field(
        None,
        ge=0,
        le=60,
        description="Acceptable inaccuracy (0-60%)",
    )
    email: str | None = Field(None, description="Payer's email")
    description: str | None = Field(None, description="Order description")
    callback_url: str | None = Field(
        None,
        description="Callback URL",
    )
    return_url: str | None = Field(
        None,
        description="Return URL",
    )
    order_id: str | None = Field(
        None,
        description="Order ID",
    )
    to_currency: str | None = Field(
        None,
        description="Target currency for payment",
    )
    auto_withdrawal: bool | None = Field(
        None,
        description="Enable auto withdrawal",
    )
    mixed_payment: bool | None = Field(
        None,
        description="Allow mixed payments",
    )
    sandbox: bool | None = Field(
        None,
        description="Enable sandbox mode",
    )


class InvoiceData(BaseModel):
    """Data model for invoice response.

    Note: Sandbox mode returns minimal fields (track_id, payment_url, expired_at, date).
    Production mode may return additional fields (amount, currency, address, etc.).
    """

    # Always returned fields
    track_id: str = Field(
        ..., description="Payment track ID", validation_alias="track_id"
    )
    payment_url: str = Field(
        ..., description="Payment URL", validation_alias="payment_url"
    )
    expired_at: int = Field(
        ..., description="Expiration timestamp", validation_alias="expired_at"
    )
    date: int = Field(..., description="Creation timestamp")

    # Optional fields (may be returned in production mode)
    address: str | None = Field(None, description="Payment address")
    amount: float | None = Field(None, description="Invoice amount")
    currency: str | None = Field(None, description="Invoice currency")
    pay_amount: float | None = Field(
        None,
        description="Payment amount",
        validation_alias="pay_amount",
    )
    pay_currency: str | None = Field(
        None,
        description="Payment currency",
        validation_alias="pay_currency",
    )
    network: str | None = Field(None, description="Blockchain network")
    rate: float | None = Field(None, description="Exchange rate")
    qr_code: str | None = Field(None, description="QR code", validation_alias="qr_code")


class CreateInvoiceResponse(DataResponse[InvoiceData]):
    """Response model for invoice creation."""


# White-label payment
class CreateWhiteLabelRequest(BaseModel):
    """Request model for creating a white-label payment."""

    amount: float = Field(..., description="The amount for the payment")
    pay_currency: str = Field(
        ...,
        description="Specific currency for payment",
    )
    currency: str | None = Field(
        None,
        description="Invoice currency",
    )
    network: str | None = Field(
        None,
        description="Blockchain network for the payment",
    )
    email: str | None = Field(None, description="Payer's email address")
    order_id: str | None = Field(
        None,
        description="Unique order ID",
    )
    description: str | None = Field(None, description="Additional information")
    callback_url: str | None = Field(
        None,
        description="Callback notification URL",
    )
    return_url: str | None = Field(
        None,
        description="Redirect URL",
    )
    under_paid_cover: float | None = Field(
        None,
        ge=0,
        le=60,
        description="Acceptable inaccuracy (0-60%)",
    )
    fee_paid_by_payer: int | None = Field(
        None,
        description="Fee paid by payer (1) or merchant (0)",
    )
    life_time: int | None = Field(
        None,
        ge=15,
        description="Expiration time in minutes",
    )
    auto_withdrawal: bool | None = Field(
        None,
        description="Enable auto withdrawal",
    )
    sandbox: bool | None = Field(
        None,
        description="Enable sandbox mode",
    )


class WhiteLabelData(
    TrackIdMixin,
    AmountCurrencyMixin,
    PaymentDetailsMixin,
    AddressMixin,
    BaseModel,
):
    """Data model for white-label response."""

    rate: float = Field(..., description="Exchange rate")
    expired_at: str = Field(
        ..., description="Expiration time", validation_alias="expiredAt"
    )
    created_at: str = Field(
        ..., description="Creation time", validation_alias="createdAt"
    )
    qr_code: str = Field(..., description="QR code", validation_alias="QRCode")
    pay_link: str = Field(..., description="Payment link", validation_alias="payLink")


class CreateWhiteLabelResponse(DataResponse[WhiteLabelData]):
    """Response model for white-label payment creation."""


# Static wallet
class CreateStaticWalletRequest(BaseModel):
    """Request model for creating a static wallet."""

    currency: str = Field(..., description="Currency for the static address")
    network: str | None = Field(None, description="Blockchain network")
    callback_url: str | None = Field(
        None,
        description="URL for payment notifications",
    )
    email: str | None = Field(None, description="Email address")
    order_id: str | None = Field(
        None,
        description="Order ID",
    )
    description: str | None = Field(None, description="Description")
    auto_withdrawal: bool | None = Field(
        None,
        description="Enable auto withdrawal",
    )
    sandbox: bool | None = Field(
        None,
        description="Enable sandbox mode",
    )


class StaticWalletData(AddressMixin, BaseModel):
    """Data model for static wallet response."""

    qr_code: str = Field(..., description="QR code", validation_alias="QRCode")
    date: str = Field(..., description="Creation date")
    network: str = Field(..., description="Network")
    currency: str = Field(..., description="Currency")


class CreateStaticWalletResponse(DataResponse[StaticWalletData]):
    """Response model for static wallet creation."""


class RevokeStaticWalletRequest(BaseModel):
    """Request model for revoking a static wallet."""

    address: str = Field(..., description="Address of the static wallet to revoke")


class RevokeStaticWalletResponse(ResultResponse):
    """Response model for static wallet revocation."""


class StaticWallet(AddressMixin, BaseModel):
    """Model for static wallet information."""

    currency: str = Field(..., description="Currency")
    network: str = Field(..., description="Blockchain network")
    callback_url: str | None = Field(
        None,
        description="Callback URL",
        validation_alias="callbackUrl",
    )
    auto_withdrawal: bool = Field(
        ...,
        description="Auto withdrawal status",
        validation_alias="autoWithdrawal",
    )
    date: str = Field(..., description="Creation timestamp")
    status: str = Field(..., description="Status")


class StaticWalletListRequest(BaseModel):
    """Request model for listing static wallets."""

    page: int | None = Field(1, ge=1, description="Page number")
    size: int | None = Field(10, ge=1, le=200, description="Records per page")


class StaticWalletListResponse(PaginatedResponse[StaticWallet]):
    """Response model for listing static wallets."""


# Payment information
class PaymentInfoRequest(BaseModel):
    """Request model for getting payment information."""

    track_id: str = Field(
        ...,
        description="Unique identifier of the payment session",
    )


class PaymentData(
    TrackIdMixin,
    AmountCurrencyMixin,
    PaymentDetailsMixin,
    AddressMixin,
    BaseModel,
):
    """Data model for payment information."""

    # Note: PaymentDetailsMixin has pay_amount, pay_currency, network.
    # PaymentData also has fee, status, tx_hash, etc.

    fee: float = Field(..., description="Fee amount")
    status: str = Field(..., description="Payment status")
    tx_hash: str | None = Field(None, description="Transaction hash")
    description: str | None = Field(None, description="Description")
    internal: bool = Field(..., description="Internal transaction flag")
    memo: str | None = Field(None, description="Memo")
    date: str = Field(..., description="Date timestamp")
    type: str | None = Field(None, description="Payment type")


class PaymentInfoResponse(DataResponse[PaymentData]):
    """Response model for payment information."""


# Payment history
class PaymentHistoryRequest(BaseModel):
    """Request model for getting payment history."""

    status: str | None = Field(None, description="Filter by status")
    type: str | None = Field(None, description="Filter by payment type")
    currency: str | None = Field(None, description="Filter by currency")
    network: str | None = Field(None, description="Filter by network")
    from_amount: float | None = Field(None, description="Min amount")
    to_amount: float | None = Field(None, description="Max amount")
    from_date: int | None = Field(None, description="Start date (unix)")
    to_date: int | None = Field(None, description="End date (unix)")
    sort_by: SortField | None = Field(
        SortField.CREATE_DATE,
        description="Sort field",
    )
    sort_type: OrderDirection | None = Field(
        OrderDirection.DESC,
        description="Sort direction",
    )
    size: int | None = Field(10, ge=1, le=200, description="Page size")
    page: int | None = Field(1, ge=1, description="Page number")


class PaymentHistoryResponse(PaginatedResponse[PaymentData]):
    """Response model for payment history."""


# Accepted coins
class AcceptedCoinsRequest(BaseModel):
    """Request model for getting accepted coins."""


class AcceptedCoin(BaseModel):
    """Model for accepted coin."""

    symbol: str = Field(..., description="Currency symbol")
    network: str = Field(..., description="Network")
    min_amount: float = Field(..., description="Minimum amount")
    max_amount: float = Field(..., description="Maximum amount")


class AcceptedCoinsResponse(DataResponse[list[AcceptedCoin]]):
    """Response model for accepted coins."""
