from pydantic import BaseModel, ConfigDict, validator, Field
from typing import List, Optional
from decimal import Decimal
from datetime import datetime
from app.models import SplitTypeEnum, ExpenseSplitStatusEnum, ExpenseOverallStatusEnum, RecurrenceTypeEnum
from app.schemas.user import UserPublic

# Align with unified types - SettlementActivity first to avoid circular imports
class SettlementActivityBase(BaseModel):
    expense_split_id: int
    paid_by_user_id: int
    amount_paid: Decimal
    paid_at: Optional[datetime] = None

class SettlementActivityCreate(SettlementActivityBase):
    pass

class SettlementActivityPublic(SettlementActivityBase):
    id: int
    created_by_user_id: int
    created_at: datetime
    updated_at: datetime
    payer: Optional[UserPublic] = None
    creator: Optional[UserPublic] = None
    model_config = ConfigDict(from_attributes=True)

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

class ExpenseSplitCreate(ExpenseSplitBase):
    pass

class ExpenseSplitUpdate(BaseModel):
    owed_amount: Optional[Decimal] = None
    share_percentage: Optional[Decimal] = None
    share_units: Optional[int] = None
    status: Optional[ExpenseSplitStatusEnum] = None

class ExpenseSplitPublic(ExpenseSplitBase):
    id: int
    expense_id: int
    status: ExpenseSplitStatusEnum
    paid_at: Optional[datetime] = None
    created_at: datetime
    updated_at: datetime
    user: Optional[UserPublic] = None
    settlement_activities: List[SettlementActivityPublic] = []
    model_config = ConfigDict(from_attributes=True)

class RecurrencePatternBase(BaseModel):
    type: RecurrenceTypeEnum
    interval: int = Field(default=1, ge=1)
    days_of_week: Optional[str] = Field(None, description="JSON string of array for weekly recurrence")
    end_date: Optional[datetime] = None
    max_occurrences: Optional[int] = Field(None, ge=1)

class RecurrencePatternCreate(RecurrencePatternBase):
    pass

class RecurrencePatternUpdate(RecurrencePatternBase):
    type: Optional[RecurrenceTypeEnum] = None
    interval: Optional[int] = None
    version: int

class RecurrencePatternPublic(RecurrencePatternBase):
    id: int
    created_at: datetime
    updated_at: datetime
    version: int
    model_config = ConfigDict(from_attributes=True)

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
    item_id: Optional[int] = None
    paid_by_user_id: int
    is_recurring: bool = Field(False, description="Whether this is a recurring expense")

class ExpenseCreate(ExpenseBase):
    splits_in: Optional[List[ExpenseSplitCreate]] = None
    recurrence_pattern: Optional[RecurrencePatternCreate] = 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

    @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

    @validator('recurrence_pattern')
    def validate_recurrence_pattern(cls, v, values):
        if values.get('is_recurring') and not v:
            raise ValueError('Recurrence pattern is required for recurring expenses')
        if not values.get('is_recurring') and v:
            raise ValueError('Recurrence pattern should not be provided for non-recurring expenses')
        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
    is_recurring: Optional[bool] = None
    recurrence_pattern: Optional[RecurrencePatternUpdate] = None
    next_occurrence: Optional[datetime] = None
    version: int

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

class ExpensePublic(ExpenseBase):
    id: int
    created_by_user_id: int
    overall_settlement_status: ExpenseOverallStatusEnum
    next_occurrence: Optional[datetime] = None
    last_occurrence: Optional[datetime] = None
    parent_expense_id: Optional[int] = None
    created_at: datetime
    updated_at: datetime
    version: int
    
    # Relationships
    paid_by_user: Optional[UserPublic] = None
    created_by_user: Optional[UserPublic] = None
    splits: List[ExpenseSplitPublic] = []
    recurrence_pattern: Optional[RecurrencePatternPublic] = None
    generated_expenses: List['ExpensePublic'] = []
    
    model_config = ConfigDict(from_attributes=True)

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
    version: int

    @validator('amount')
    def amount_must_be_positive(cls, v):
        if v is not None and v <= Decimal('0'):
            raise ValueError('Settlement amount must be positive')
        return v

class SettlementPublic(SettlementBase):
    id: int
    created_by_user_id: int
    created_at: datetime
    updated_at: datetime
    version: int
    
    # Relationships
    payer: Optional[UserPublic] = None
    payee: Optional[UserPublic] = None
    created_by_user: Optional[UserPublic] = None
    
    model_config = ConfigDict(from_attributes=True)

# WebSocket event schemas for type safety
class ExpenseWebSocketEvent(BaseModel):
    event: str
    payload: dict
    timestamp: datetime
    user_id: Optional[int] = None
    room: Optional[str] = None

# Update forward references
ExpensePublic.model_rebuild()