from datetime import date, datetime
from decimal import Decimal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, model_validator

FREQUENCIES = {"MONTHLY", "WEEKLY", "DAILY", "OTHER"}
METHODS = {"CASH", "POS", "TRANSFER", "OTHER"}

class PayrollProfileCreate(BaseModel):
    membership_id: UUID
    salary: Decimal = Field(ge=0, max_digits=14, decimal_places=2)
    payment_frequency: str
    @model_validator(mode="after")
    def frequency_valid(self):
        self.payment_frequency = self.payment_frequency.upper()
        if self.payment_frequency not in FREQUENCIES: raise ValueError("Invalid payment frequency.")
        return self
class PayrollProfileUpdate(BaseModel):
    salary: Decimal | None = Field(default=None, ge=0, max_digits=14, decimal_places=2)
    payment_frequency: str | None = None
    is_active: bool | None = None
    @model_validator(mode="after")
    def frequency_valid(self):
        if self.payment_frequency:
            self.payment_frequency = self.payment_frequency.upper()
            if self.payment_frequency not in FREQUENCIES: raise ValueError("Invalid payment frequency.")
        return self
class PayrollProfileRead(BaseModel):
    id: UUID; business_id: UUID; membership_id: UUID; salary: Decimal; payment_frequency: str; is_active: bool; created_at: datetime; updated_at: datetime
    model_config = ConfigDict(from_attributes=True)

class PayrollRunCreate(BaseModel):
    membership_id: UUID; payroll_profile_id: UUID; period_start: date; period_end: date
    adjustment_amount: Decimal = Field(default=Decimal("0"), max_digits=14, decimal_places=2)
    adjustment_note: str | None = Field(default=None, max_length=2000)
    @model_validator(mode="after")
    def valid(self):
        if self.period_end < self.period_start: raise ValueError("Period end cannot be before period start.")
        if self.adjustment_amount != 0 and not (self.adjustment_note or "").strip(): raise ValueError("An adjustment note is required for non-zero adjustments.")
        return self
class PayrollRunUpdate(BaseModel):
    period_start: date | None = None; period_end: date | None = None
    adjustment_amount: Decimal | None = Field(default=None, max_digits=14, decimal_places=2)
    adjustment_note: str | None = Field(default=None, max_length=2000)
class PayrollPay(BaseModel):
    payment_method: str
    @model_validator(mode="after")
    def method_valid(self):
        self.payment_method = self.payment_method.upper()
        if self.payment_method not in METHODS: raise ValueError("Invalid payment method.")
        return self
class PayrollRunRead(BaseModel):
    id: UUID; business_id: UUID; membership_id: UUID; payroll_profile_id: UUID; period_start: date; period_end: date; base_salary: Decimal; adjustment_amount: Decimal; adjustment_note: str | None; total_amount: Decimal; payment_method: str | None; status: str; approved_by: UUID | None; approved_at: datetime | None; paid_by: UUID | None; paid_at: datetime | None; expense_id: UUID | None; created_by: UUID; created_at: datetime; updated_at: datetime
    model_config = ConfigDict(from_attributes=True)
