"""
Pydantic schemas for TripTalley API.
Defines request/response models for all API endpoints.
"""

from datetime import date, datetime
from decimal import Decimal
from typing import List, Optional
from pydantic import BaseModel, Field, field_validator


# ============ Common Models ============

class CurrencyAmount(BaseModel):
    """Amount in a specific currency."""
    amount: Decimal = Field(..., example=10.50)
    currency: str = Field(..., pattern=r'^[A-Z]{3}$', example='USD')
    
    @field_validator('currency')
    @classmethod
    def uppercase_currency(cls, v):
        return v.upper()


class Timestamped(BaseModel):
    """Base model with timestamps."""
    created_at: datetime
    updated_at: datetime


class Paginated(BaseModel):
    """Pagination metadata."""
    page: int = 1
    page_size: int = 50
    total: int = 0
    total_pages: int = 0


# ============ User Models ============

class UserCreate(BaseModel):
    """Request to create a new user."""
    email: str = Field(..., example='alice@example.com')
    password: str = Field(..., min_length=8, example='SecurePass123!')
    display_name: str = Field(..., example='Alice Smith')
    home_currency: str = Field(default='USD', pattern=r'^[A-Z]{3}$')


class UserUpdate(BaseModel):
    """Request to update user profile."""
    display_name: Optional[str] = Field(default=None, example='Alice Johnson')
    home_currency: Optional[str] = Field(default=None, pattern=r'^[A-Z]{3}$')


class UserResponse(BaseModel):
    """User profile response."""
    id: int
    email: str
    display_name: str
    home_currency: str
    created_at: datetime


class UserListResponse(Paginated):
    """Paginated user list response."""
    data: List[UserResponse]


# ============ Group Models ============

class GroupCreate(BaseModel):
    """Request to create a group."""
    name: str = Field(..., example='Budget Bros')
    description: Optional[str] = Field(default=None, example='Travel group for 2024')


class GroupUpdate(BaseModel):
    """Request to update group."""
    name: Optional[str] = None
    description: Optional[str] = None


class GroupResponse(BaseModel):
    """Group response."""
    id: int
    name: str
    description: Optional[str]
    created_at: datetime


class GroupListResponse(Paginated):
    """Paginated group list response."""
    data: List[GroupResponse]


# ============ Trip Models ============

class TripCreate(BaseModel):
    """Request to create a trip."""
    group_id: Optional[int] = None
    name: str = Field(..., example='European Tour 2024')
    description: Optional[str] = None
    start_date: date = Field(..., example='2024-06-01')
    end_date: date = Field(..., example='2024-06-15')
    settlement_currency: str = Field(default='EUR', pattern=r'^[A-Z]{3}$')


class TripUpdate(BaseModel):
    """Request to update trip."""
    name: Optional[str] = None
    description: Optional[str] = None
    start_date: Optional[date] = None
    end_date: Optional[date] = None
    settlement_currency: Optional[str] = Field(default=None, pattern=r'^[A-Z]{3}$')


class TripResponse(BaseModel):
    """Trip response."""
    id: int
    group_id: Optional[int]
    name: str
    description: Optional[str]
    start_date: date
    end_date: date
    settlement_currency: str
    created_at: datetime


class TripListResponse(Paginated):
    """Paginated trip list response."""
    data: List[TripResponse]


class TripInviteCreate(BaseModel):
    """Request to create a trip invite."""
    expires_in_days: int = Field(default=7, ge=1, le=365)


class TripInviteResponse(BaseModel):
    """Trip invite response with signed link."""
    id: int
    trip_id: int
    token: str  # UUID for the invite
    expires_at: datetime
    invite_url: str  # Full URL for sharing


# ============ Expense Models ============

class ExpenseParticipantInput(BaseModel):
    """Participant in an expense split."""
    user_id: int
    share_minor: int = Field(..., example=5000)


class ExpenseCreate(BaseModel):
    """Request to create an expense."""
    trip_id: int
    payer_id: int
    original_amount_minor: int = Field(..., example=10000)  # e.g., 10000 = $100.00
    original_currency: str = Field(..., pattern=r'^[A-Z]{3}$', example='EUR')
    spent_on: date = Field(..., example='2024-06-05')
    category: Optional[str] = Field(default=None, example='Food')
    description: Optional[str] = Field(default=None, example='Dinner at trattoria')
    participants: List[ExpenseParticipantInput] = Field(
        ..., 
        description='Participants and their shares in original currency'
    )
    
    @field_validator('original_currency')
    @classmethod
    def uppercase_currency(cls, v):
        return v.upper()


class ExpenseUpdate(BaseModel):
    """Request to update an expense."""
    payer_id: Optional[int] = None
    original_amount_minor: Optional[int] = None
    original_currency: Optional[str] = Field(default=None, pattern=r'^[A-Z]{3}$')
    spent_on: Optional[date] = None
    category: Optional[str] = None
    description: Optional[str] = None
    participants: Optional[List[ExpenseParticipantInput]] = None


class ExpenseParticipantResponse(BaseModel):
    """Participant in an expense."""
    user_id: int
    share_minor: int
    share_decimal: Decimal  # For display


class ExpenseResponse(BaseModel):
    """Expense response."""
    id: int
    trip_id: int
    payer_id: int
    original_amount_minor: int
    original_currency: str
    amount_decimal: Decimal  # For display
    spent_on: date
    category: Optional[str]
    description: Optional[str]
    participants: List[ExpenseParticipantResponse]
    created_at: datetime


class ExpenseListResponse(Paginated):
    """Paginated expense list response."""
    data: List[ExpenseResponse]


# ============ Split Models ============

class SplitEqualInput(BaseModel):
    """Equal split input."""
    participant_ids: List[int] = Field(..., example=[1, 2, 3])


class SplitPercentageInput(BaseModel):
    """Percentage split input."""
    participants: List[dict] = Field(
        ..., 
        example=[{'user_id': 1, 'weight': 5000}, {'user_id': 2, 'weight': 3000}]
    )


class SplitCustomInput(BaseModel):
    """Custom split input."""
    participants: List[dict] = Field(
        ..., 
        example=[{'user_id': 1, 'amount': 4000}, {'user_id': 2, 'amount': 3000}]
    )


class SplitResult(BaseModel):
    """Split result for one participant."""
    user_id: int
    share_minor: int
    share_decimal: Decimal


class SplitResponse(BaseModel):
    """Split calculation response."""
    total_minor: int
    total_decimal: Decimal
    currency: str
    splits: List[SplitResult]


# ============ Settlement Models ============

class PaymentInput(BaseModel):
    """Payment/transfer input."""
    from_user_id: int
    to_user_id: int
    amount_minor: int
    currency: str
    reference: Optional[str] = None


class PaymentResponse(BaseModel):
    """Payment response."""
    id: int
    trip_id: int
    from_user_id: int
    to_user_id: int
    amount_minor: int
    currency: str
    amount_decimal: Decimal
    status: str
    reference: Optional[str]
    created_at: datetime
    completed_at: Optional[datetime]


class SettlementBalance(BaseModel):
    """User balance in a trip."""
    user_id: int
    balance_minor: int
    balance_decimal: Decimal
    currency: str
    is_creditor: bool  # True if they are owed money
    is_debtor: bool    # True if they owe money


class SettlementResponse(BaseModel):
    """Settlement calculation response."""
    trip_id: int
    settlement_currency: str
    balances: List[SettlementBalance]
    payments: List[PaymentResponse]


# ============ FX Models ============

class FXRateResponse(BaseModel):
    """FX rate response."""
    from_currency: str
    to_currency: str
    rate: Decimal
    date: date
    source: str


class FXConvertInput(BaseModel):
    """FX conversion input."""
    amount_minor: int
    from_currency: str
    to_currency: str
    on_date: date


class FXConvertResponse(BaseModel):
    """FX conversion output."""
    from_currency: str
    to_currency: str
    from_amount_minor: int
    from_amount_decimal: Decimal
    to_amount_minor: int
    to_amount_decimal: Decimal
    rate: Decimal
    date: date


# ============ Sync Models ============

class SyncRequest(BaseModel):
    """Client sync request."""
    client_uuid: str = Field(..., description='Unique client identifier')
    last_sync_at: Optional[datetime] = None
    sync_all: bool = False


class SyncResponse(BaseModel):
    """Server sync response."""
    client_uuid: str
    last_sync_at: datetime
    changes: dict  # Changes since last sync


# ============ Auth Models ============

class TokenResponse(BaseModel):
    """Authentication token response."""
    access_token: str
    token_type: str = 'bearer'
    expires_in: int = 3600  # seconds


class TokenPayload(BaseModel):
    """Token payload for verification."""
    user_id: int
    email: str
    exp: datetime