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


class ExpenseStatus(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"
    PAID = "paid"


class CommissionStatus(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    PAID = "paid"


class ExpenseBase(BaseModel):
    tour_schedule_id: Optional[str] = None
    category: str = Field(..., min_length=1, max_length=100)
    description: str = Field(..., min_length=1, max_length=500)
    amount: Decimal = Field(..., gt=0, decimal_places=2)
    currency: str = Field(..., min_length=3, max_length=3)
    vendor_name: Optional[str] = Field(None, max_length=255)
    expense_date: date
    payment_method: Optional[str] = Field(None, max_length=50)
    receipt_url: Optional[str] = Field(None, max_length=500)
    status: ExpenseStatus
    submitted_by: str
    approved_by: Optional[str] = None
    approval_date: Optional[datetime] = None
    notes: Optional[str] = None

    @field_validator("amount")
    @classmethod
    def validate_amount(cls, v):
        if v <= 0:
            raise ValueError("Amount must be greater than zero")
        return v

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


class ExpenseCreate(BaseModel):
    tour_schedule_id: Optional[str] = None
    category: str = Field(..., min_length=1, max_length=100)
    description: str = Field(..., min_length=1, max_length=500)
    amount: Decimal = Field(..., gt=0, decimal_places=2)
    currency: str = Field(..., min_length=3, max_length=3)
    vendor_name: Optional[str] = Field(None, max_length=255)
    expense_date: date
    payment_method: Optional[str] = Field(None, max_length=50)
    receipt_url: Optional[str] = Field(None, max_length=500)
    submitted_by: str
    notes: Optional[str] = None

    @field_validator("amount")
    @classmethod
    def validate_amount(cls, v):
        if v <= 0:
            raise ValueError("Amount must be greater than zero")
        return v

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


class ExpenseUpdate(BaseModel):
    tour_schedule_id: Optional[str] = None
    category: Optional[str] = Field(None, min_length=1, max_length=100)
    description: Optional[str] = Field(None, min_length=1, max_length=500)
    amount: Optional[Decimal] = Field(None, gt=0, decimal_places=2)
    currency: Optional[str] = Field(None, min_length=3, max_length=3)
    vendor_name: Optional[str] = Field(None, max_length=255)
    expense_date: Optional[date] = None
    payment_method: Optional[str] = Field(None, max_length=50)
    receipt_url: Optional[str] = Field(None, max_length=500)
    status: Optional[ExpenseStatus] = None
    submitted_by: Optional[str] = None
    approved_by: Optional[str] = None
    approval_date: Optional[datetime] = None
    notes: Optional[str] = None

    @field_validator("amount")
    @classmethod
    def validate_amount(cls, v):
        if v is not None and v <= 0:
            raise ValueError("Amount must be greater than zero")
        return v

    @field_validator("currency")
    @classmethod
    def validate_currency(cls, v):
        if v is not None and len(v) != 3:
            raise ValueError("Currency must be a 3-letter code")
        return v.upper() if v else v


class ExpenseResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    tour_schedule_id: Optional[str]
    category: str
    description: str
    amount: Decimal
    currency: str
    vendor_name: Optional[str]
    expense_date: date
    payment_method: Optional[str]
    receipt_url: Optional[str]
    status: str
    submitted_by: str
    approved_by: Optional[str]
    approval_date: Optional[datetime]
    notes: Optional[str]
    created_at: datetime
    updated_at: datetime


class CommissionBase(BaseModel):
    booking_id: str
    booking_agent_id: str
    booking_amount: Decimal = Field(..., gt=0, decimal_places=2)
    commission_rate: Decimal = Field(..., ge=0, le=100, decimal_places=2)
    commission_amount: Decimal = Field(..., ge=0, decimal_places=2)
    status: CommissionStatus
    payment_date: Optional[date] = None
    notes: Optional[str] = None

    @field_validator("booking_amount", "commission_amount")
    @classmethod
    def validate_amounts(cls, v):
        if v < 0:
            raise ValueError("Amount must be greater than or equal to zero")
        return v

    @field_validator("commission_rate")
    @classmethod
    def validate_commission_rate(cls, v):
        if v < 0 or v > 100:
            raise ValueError("Commission rate must be between 0 and 100")
        return v


class CommissionCreate(BaseModel):
    booking_id: str
    booking_agent_id: str
    booking_amount: Decimal = Field(..., gt=0, decimal_places=2)
    commission_rate: Decimal = Field(..., ge=0, le=100, decimal_places=2)
    commission_amount: Decimal = Field(..., ge=0, decimal_places=2)
    notes: Optional[str] = None

    @field_validator("booking_amount", "commission_amount")
    @classmethod
    def validate_amounts(cls, v):
        if v < 0:
            raise ValueError("Amount must be greater than or equal to zero")
        return v

    @field_validator("commission_rate")
    @classmethod
    def validate_commission_rate(cls, v):
        if v < 0 or v > 100:
            raise ValueError("Commission rate must be between 0 and 100")
        return v


class CommissionUpdate(BaseModel):
    booking_id: Optional[str] = None
    booking_agent_id: Optional[str] = None
    booking_amount: Optional[Decimal] = Field(None, gt=0, decimal_places=2)
    commission_rate: Optional[Decimal] = Field(None, ge=0, le=100, decimal_places=2)
    commission_amount: Optional[Decimal] = Field(None, ge=0, decimal_places=2)
    status: Optional[CommissionStatus] = None
    payment_date: Optional[date] = None
    notes: Optional[str] = None

    @field_validator("booking_amount", "commission_amount")
    @classmethod
    def validate_amounts(cls, v):
        if v is not None and v < 0:
            raise ValueError("Amount must be greater than or equal to zero")
        return v

    @field_validator("commission_rate")
    @classmethod
    def validate_commission_rate(cls, v):
        if v is not None and (v < 0 or v > 100):
            raise ValueError("Commission rate must be between 0 and 100")
        return v


class CommissionResponse(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: str
    booking_id: str
    booking_agent_id: str
    booking_amount: Decimal
    commission_rate: Decimal
    commission_amount: Decimal
    status: str
    payment_date: Optional[date]
    notes: Optional[str]
    created_at: datetime
    updated_at: datetime