from pydantic import BaseModel, ConfigDict, Field, field_validator
from typing import Optional
from datetime import datetime
from enum import Enum
from decimal import Decimal


class TransactionTypeEnum(str, Enum):
    SALE = "Sale"
    PURCHASE = "Purchase"
    REFUND = "Refund"
    PAYOUT = "Payout"
    PLATFORM_FEE = "Platform Fee"
    ADJUSTMENT = "Adjustment"


class TransactionStatusEnum(str, Enum):
    PENDING = "Pending"
    COMPLETED = "Completed"
    FAILED = "Failed"
    CANCELLED = "Cancelled"


class TransactionBase(BaseModel):
    user_id: str
    order_id: Optional[str] = None
    transaction_type: TransactionTypeEnum
    amount: Decimal
    currency: str = "USD"
    status: TransactionStatusEnum
    description: Optional[str] = None
    reference_id: Optional[str] = None

    @field_validator("amount")
    @classmethod
    def validate_amount(cls, v: Decimal) -> Decimal:
        if v <= 0:
            raise ValueError("Transaction amount must be positive")
        return v

    @field_validator("currency")
    @classmethod
    def validate_currency(cls, v: str) -> str:
        if len(v) != 3:
            raise ValueError("Currency code must be 3 characters")
        return v.upper()


class TransactionCreate(TransactionBase):
    pass


class TransactionUpdate(BaseModel):
    user_id: Optional[str] = None
    order_id: Optional[str] = None
    transaction_type: Optional[TransactionTypeEnum] = None
    amount: Optional[Decimal] = None
    currency: Optional[str] = None
    status: Optional[TransactionStatusEnum] = None
    description: Optional[str] = None
    reference_id: Optional[str] = None

    @field_validator("amount")
    @classmethod
    def validate_amount(cls, v: Optional[Decimal]) -> Optional[Decimal]:
        if v is not None and v <= 0:
            raise ValueError("Transaction amount must be positive")
        return v

    @field_validator("currency")
    @classmethod
    def validate_currency(cls, v: Optional[str]) -> Optional[str]:
        if v is not None:
            if len(v) != 3:
                raise ValueError("Currency code must be 3 characters")
            return v.upper()
        return v


class TransactionResponse(TransactionBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)