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


class PromotionType(str, Enum):
    PERCENTAGE_DISCOUNT = "Percentage Discount"
    FIXED_DISCOUNT = "Fixed Discount"
    FREE_SHIPPING = "Free Shipping"
    FEATURED_LISTING = "Featured Listing"


class PromotionBase(BaseModel):
    code: Optional[str] = None
    name: str
    description: Optional[str] = None
    promotion_type: PromotionType
    discount_percentage: Optional[Decimal] = None
    discount_amount: Optional[Decimal] = None
    minimum_purchase_amount: Optional[Decimal] = None
    max_uses: Optional[int] = None
    starts_at: datetime
    expires_at: datetime
    is_active: bool = True

    @field_validator("discount_percentage")
    @classmethod
    def validate_discount_percentage(cls, v):
        if v is not None and (v < 0 or v > 100):
            raise ValueError("Discount percentage must be between 0 and 100")
        return v

    @field_validator("discount_amount")
    @classmethod
    def validate_discount_amount(cls, v):
        if v is not None and v < 0:
            raise ValueError("Discount amount must be positive")
        return v

    @field_validator("minimum_purchase_amount")
    @classmethod
    def validate_minimum_purchase_amount(cls, v):
        if v is not None and v < 0:
            raise ValueError("Minimum purchase amount must be positive")
        return v

    @field_validator("max_uses")
    @classmethod
    def validate_max_uses(cls, v):
        if v is not None and v < 1:
            raise ValueError("Max uses must be at least 1")
        return v

    @field_validator("expires_at")
    @classmethod
    def validate_expires_at(cls, v, info):
        if "starts_at" in info.data and v <= info.data["starts_at"]:
            raise ValueError("Expiration date must be after start date")
        return v


class PromotionCreate(PromotionBase):
    pass


class PromotionUpdate(BaseModel):
    code: Optional[str] = None
    name: Optional[str] = None
    description: Optional[str] = None
    promotion_type: Optional[PromotionType] = None
    discount_percentage: Optional[Decimal] = None
    discount_amount: Optional[Decimal] = None
    minimum_purchase_amount: Optional[Decimal] = None
    max_uses: Optional[int] = None
    current_uses: Optional[int] = None
    starts_at: Optional[datetime] = None
    expires_at: Optional[datetime] = None
    is_active: Optional[bool] = None

    @field_validator("discount_percentage")
    @classmethod
    def validate_discount_percentage(cls, v):
        if v is not None and (v < 0 or v > 100):
            raise ValueError("Discount percentage must be between 0 and 100")
        return v

    @field_validator("discount_amount")
    @classmethod
    def validate_discount_amount(cls, v):
        if v is not None and v < 0:
            raise ValueError("Discount amount must be positive")
        return v

    @field_validator("minimum_purchase_amount")
    @classmethod
    def validate_minimum_purchase_amount(cls, v):
        if v is not None and v < 0:
            raise ValueError("Minimum purchase amount must be positive")
        return v

    @field_validator("max_uses")
    @classmethod
    def validate_max_uses(cls, v):
        if v is not None and v < 1:
            raise ValueError("Max uses must be at least 1")
        return v


class PromotionResponse(PromotionBase):
    id: str
    current_uses: int
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)


class PromotionusageBase(BaseModel):
    promotion_id: str
    user_id: str
    order_id: str
    discount_applied: Decimal

    @field_validator("discount_applied")
    @classmethod
    def validate_discount_applied(cls, v):
        if v < 0:
            raise ValueError("Discount applied must be positive")
        return v


class PromotionusageCreate(PromotionusageBase):
    pass


class PromotionusageUpdate(BaseModel):
    promotion_id: Optional[str] = None
    user_id: Optional[str] = None
    order_id: Optional[str] = None
    discount_applied: Optional[Decimal] = None

    @field_validator("discount_applied")
    @classmethod
    def validate_discount_applied(cls, v):
        if v is not None and v < 0:
            raise ValueError("Discount applied must be positive")
        return v


class PromotionusageResponse(PromotionusageBase):
    id: str
    created_at: datetime
    updated_at: datetime

    model_config = ConfigDict(from_attributes=True)