# app/schemas/expense.py
from pydantic import BaseModel, ConfigDict, validator
from typing import List, Optional
from decimal import Decimal
from datetime import datetime

# Assuming SplitTypeEnum is accessible here, e.g., from app.models or app.core.enums
# For now, let's redefine it or import it if models.py is parsable by Pydantic directly
# If it's from app.models, you might need to make app.models.SplitTypeEnum Pydantic-compatible or map it.
# For simplicity during schema definition, I'll redefine a string enum here.
# In a real setup, ensure this aligns with the SQLAlchemy enum in models.py.
from app.models import SplitTypeEnum # Try importing directly

# --- ExpenseSplit Schemas ---
class ExpenseSplitBase(BaseModel):
    user_id: int
    owed_amount: Decimal
    share_percentage: Optional[Decimal] = None
    share_units: Optional[int] = None

class ExpenseSplitCreate(ExpenseSplitBase):
    pass # All fields from base are needed for creation

class ExpenseSplitPublic(ExpenseSplitBase):
    id: int
    expense_id: int
    # user: Optional[UserPublic] # If we want to nest user details
    created_at: datetime
    updated_at: datetime
    model_config = ConfigDict(from_attributes=True)

# --- Expense Schemas ---
class ExpenseBase(BaseModel):
    description: str
    total_amount: Decimal
    currency: Optional[str] = "USD"
    expense_date: Optional[datetime] = None
    split_type: SplitTypeEnum
    list_id: Optional[int] = None
    group_id: Optional[int] = None # Should be present if list_id is not, and vice-versa
    item_id: Optional[int] = None
    paid_by_user_id: int

class ExpenseCreate(ExpenseBase):
    # For EQUAL split, splits are generated. For others, they might be provided.
    # This logic will be in the CRUD: if split_type is EXACT_AMOUNTS, PERCENTAGE, SHARES,
    # then 'splits_in' should be provided.
    splits_in: Optional[List[ExpenseSplitCreate]] = None 

    @validator('total_amount')
    def total_amount_must_be_positive(cls, v):
        if v <= Decimal('0'):
            raise ValueError('Total amount must be positive')
        return v

    # Basic validation: if list_id is None, group_id must be provided.
    # More complex cross-field validation might be needed.
    @validator('group_id', always=True)
    def check_list_or_group_id(cls, v, values):
        if values.get('list_id') is None and v is None:
            raise ValueError('Either list_id or group_id must be provided for an expense')
        return v

class ExpenseUpdate(BaseModel):
    description: Optional[str] = None
    total_amount: Optional[Decimal] = None
    currency: Optional[str] = None
    expense_date: Optional[datetime] = None
    split_type: Optional[SplitTypeEnum] = None
    list_id: Optional[int] = None
    group_id: Optional[int] = None
    item_id: Optional[int] = None
    # paid_by_user_id is usually not updatable directly to maintain integrity.
    # Updating splits would be a more complex operation, potentially a separate endpoint or careful logic.
    version: int # For optimistic locking

class ExpensePublic(ExpenseBase):
    id: int
    created_at: datetime
    updated_at: datetime
    version: int
    splits: List[ExpenseSplitPublic] = []
    # paid_by_user: Optional[UserPublic] # If nesting user details
    # list: Optional[ListPublic] # If nesting list details
    # group: Optional[GroupPublic] # If nesting group details
    # item: Optional[ItemPublic] # If nesting item details
    model_config = ConfigDict(from_attributes=True)

# --- Settlement Schemas ---
class SettlementBase(BaseModel):
    group_id: int
    paid_by_user_id: int
    paid_to_user_id: int
    amount: Decimal
    settlement_date: Optional[datetime] = None
    description: Optional[str] = None

class SettlementCreate(SettlementBase):
    @validator('amount')
    def amount_must_be_positive(cls, v):
        if v <= Decimal('0'):
            raise ValueError('Settlement amount must be positive')
        return v

    @validator('paid_to_user_id')
    def payer_and_payee_must_be_different(cls, v, values):
        if 'paid_by_user_id' in values and v == values['paid_by_user_id']:
            raise ValueError('Payer and payee cannot be the same user')
        return v

class SettlementUpdate(BaseModel):
    amount: Optional[Decimal] = None
    settlement_date: Optional[datetime] = None
    description: Optional[str] = None
    # group_id, paid_by_user_id, paid_to_user_id are typically not updatable.
    version: int # For optimistic locking

class SettlementPublic(SettlementBase):
    id: int
    created_at: datetime
    updated_at: datetime
    # payer: Optional[UserPublic]
    # payee: Optional[UserPublic]
    # group: Optional[GroupPublic]
    model_config = ConfigDict(from_attributes=True)

# Placeholder for nested schemas (e.g., UserPublic) if needed
# from app.schemas.user import UserPublic
# from app.schemas.list import ListPublic
# from app.schemas.group import GroupPublic
# from app.schemas.item import ItemPublic