"""
Payment Models
Wallet, transactions, payments, and withdrawal requests
"""
import enum
from datetime import datetime
from typing import Optional, List
from sqlalchemy import (
    String, Integer, Float, Enum, Text, DateTime,
    ForeignKey, Index, JSON, Boolean
)
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.base import BaseModel


class PaymentMethod(str, enum.Enum):
    """Available payment methods"""
    CASH = "cash"
    WALLET = "wallet"
    CARD = "card"
    UPI = "upi"
    NET_BANKING = "net_banking"


class TransactionType(str, enum.Enum):
    """Transaction type enumeration"""
    WALLET_TOPUP = "wallet_topup"
    RIDE_PAYMENT = "ride_payment"
    RIDE_REFUND = "ride_refund"
    DRIVER_PAYOUT = "driver_payout"
    COMMISSION = "commission"
    PROMO_CREDIT = "promo_credit"
    WITHDRAWAL = "withdrawal"
    CANCELLATION_FEE = "cancellation_fee"
    ADJUSTMENT = "adjustment"


class TransactionStatus(str, enum.Enum):
    """Transaction status"""
    PENDING = "pending"
    PROCESSING = "processing"
    COMPLETED = "completed"
    FAILED = "failed"
    REFUNDED = "refunded"
    CANCELLED = "cancelled"


class WithdrawalStatus(str, enum.Enum):
    """Withdrawal request status"""
    PENDING = "pending"
    APPROVED = "approved"
    PROCESSING = "processing"
    COMPLETED = "completed"
    REJECTED = "rejected"
    CANCELLED = "cancelled"


class Wallet(BaseModel):
    """
    User wallet for in-app balance management.
    Supports both passengers and drivers.
    """
    __tablename__ = "wallets"
    
    user_id: Mapped[int] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        unique=True,
        nullable=False,
        index=True
    )
    
    # Balance (in cents/paise)
    balance: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    pending_balance: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    lifetime_credits: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    lifetime_debits: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    
    # Currency
    currency: Mapped[str] = mapped_column(String(3), default="USD", nullable=False)
    
    # Status
    is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
    
    # Relationships
    user: Mapped["User"] = relationship(
        "User",
        back_populates="wallet"
    )
    transactions: Mapped[List["Transaction"]] = relationship(
        "Transaction",
        back_populates="wallet",
        lazy="dynamic"
    )
    
    @property
    def available_balance(self) -> int:
        """Get available balance (total - pending)"""
        return self.balance - self.pending_balance


class Transaction(BaseModel):
    """
    Financial transaction record.
    Tracks all money movements in the system.
    """
    __tablename__ = "transactions"
    
    # Transaction ID (unique reference)
    transaction_ref: Mapped[str] = mapped_column(
        String(50),
        unique=True,
        nullable=False,
        index=True
    )
    
    # Wallet reference
    wallet_id: Mapped[int] = mapped_column(
        ForeignKey("wallets.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    
    # Related ride (if applicable)
    ride_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("rides.id", ondelete="SET NULL"),
        nullable=True,
        index=True
    )
    
    # Transaction details
    transaction_type: Mapped[TransactionType] = mapped_column(
        Enum(TransactionType),
        nullable=False,
        index=True
    )
    amount: Mapped[int] = mapped_column(Integer, nullable=False)  # In cents
    fee: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    net_amount: Mapped[int] = mapped_column(Integer, nullable=False)
    
    # Balance tracking
    balance_before: Mapped[int] = mapped_column(Integer, nullable=False)
    balance_after: Mapped[int] = mapped_column(Integer, nullable=False)
    
    # Status
    status: Mapped[TransactionStatus] = mapped_column(
        Enum(TransactionStatus),
        default=TransactionStatus.PENDING,
        nullable=False,
        index=True
    )
    
    # Payment gateway details
    payment_gateway: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    gateway_transaction_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    gateway_response: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    
    # Description
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    
    # Extra Data
    extra_data: Mapped[Optional[dict]] = mapped_column(JSON, nullable=True)
    
    # Relationships
    wallet: Mapped["Wallet"] = relationship(
        "Wallet",
        back_populates="transactions"
    )
    
    # Indexes
    __table_args__ = (
        Index('idx_transaction_wallet_type', 'wallet_id', 'transaction_type'),
        Index('idx_transaction_status_date', 'status', 'created_at'),
    )


class Payment(BaseModel):
    """
    Ride payment record.
    Links ride to payment transaction.
    """
    __tablename__ = "payments"
    
    ride_id: Mapped[int] = mapped_column(
        ForeignKey("rides.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    
    passenger_id: Mapped[int] = mapped_column(
        ForeignKey("users.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    
    driver_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("drivers.id", ondelete="SET NULL"),
        nullable=True,
        index=True
    )
    
    # Amount breakdown (in cents)
    subtotal: Mapped[int] = mapped_column(Integer, nullable=False)
    discount: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    tax: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    total: Mapped[int] = mapped_column(Integer, nullable=False)
    
    # Commission
    commission_rate: Mapped[float] = mapped_column(Float, default=15.0, nullable=False)
    commission_amount: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    driver_amount: Mapped[int] = mapped_column(Integer, nullable=False)
    
    # Payment method
    payment_method: Mapped[PaymentMethod] = mapped_column(
        Enum(PaymentMethod),
        default=PaymentMethod.CASH,
        nullable=False
    )
    
    # Status
    status: Mapped[TransactionStatus] = mapped_column(
        Enum(TransactionStatus),
        default=TransactionStatus.PENDING,
        nullable=False,
        index=True
    )
    
    # Transaction reference
    transaction_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("transactions.id", ondelete="SET NULL"),
        nullable=True
    )
    
    # Gateway details
    gateway_payment_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    
    # Timestamps
    paid_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    
    # Indexes
    __table_args__ = (
        Index('idx_payment_ride', 'ride_id'),
        Index('idx_payment_status', 'status'),
    )

    # Relationships
    ride: Mapped["Ride"] = relationship("Ride", foreign_keys=[ride_id], lazy="selectin")
    passenger: Mapped["User"] = relationship("User", foreign_keys=[passenger_id], lazy="selectin")
    driver: Mapped[Optional["Driver"]] = relationship("Driver", foreign_keys=[driver_id], lazy="selectin")


class WithdrawalRequest(BaseModel):
    """
    Driver withdrawal/payout request.
    Tracks driver requests to withdraw earnings.
    """
    __tablename__ = "withdrawal_requests"
    
    driver_id: Mapped[int] = mapped_column(
        ForeignKey("drivers.id", ondelete="CASCADE"),
        nullable=False,
        index=True
    )
    
    # Amount
    amount: Mapped[int] = mapped_column(Integer, nullable=False)  # In cents
    fee: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
    net_amount: Mapped[int] = mapped_column(Integer, nullable=False)
    
    # Bank details (snapshot at time of request)
    bank_name: Mapped[str] = mapped_column(String(255), nullable=False)
    bank_account_number: Mapped[str] = mapped_column(String(255), nullable=False)
    bank_routing_number: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    bank_account_holder: Mapped[str] = mapped_column(String(255), nullable=False)
    
    # Status
    status: Mapped[WithdrawalStatus] = mapped_column(
        Enum(WithdrawalStatus),
        default=WithdrawalStatus.PENDING,
        nullable=False,
        index=True
    )
    
    # Admin processing
    processed_by: Mapped[Optional[int]] = mapped_column(
        ForeignKey("users.id", ondelete="SET NULL"),
        nullable=True
    )
    processed_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True)
    rejection_reason: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    
    # Transaction reference
    transaction_id: Mapped[Optional[int]] = mapped_column(
        ForeignKey("transactions.id", ondelete="SET NULL"),
        nullable=True
    )
    
    # External transfer details
    transfer_reference: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    
    # Notes
    notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    
    # Indexes
    __table_args__ = (
        Index('idx_withdrawal_driver_status', 'driver_id', 'status'),
        Index('idx_withdrawal_status_date', 'status', 'created_at'),
    )


# Import for type hints
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from app.models.user import User
    from app.models.ride import Ride
    from app.models.driver import Driver
