# app/modules/loyalty/schemas/program.py
"""
Pydantic schemas for loyalty program operations.
"""

from datetime import datetime

from pydantic import BaseModel, ConfigDict, Field


class PointsRewardConfig(BaseModel):
    """Configuration for a points-based reward."""

    id: str = Field(..., description="Unique reward identifier")
    name: str = Field(..., max_length=100, description="Reward name")
    points_required: int = Field(..., gt=0, description="Points needed to redeem")
    description: str | None = Field(None, max_length=255, description="Reward description")
    is_active: bool = Field(True, description="Whether reward is currently available")


class ProgramCreate(BaseModel):
    """Schema for creating a loyalty program."""

    # Program type
    loyalty_type: str = Field(
        "stamps",
        pattern="^(stamps|points|hybrid)$",
        description="Program type: stamps, points, or hybrid",
    )

    # Stamps configuration
    stamps_target: int = Field(10, ge=1, le=50, description="Stamps needed for reward")
    stamps_reward_description: str = Field(
        "Free item",
        max_length=255,
        description="Description of stamp reward",
    )
    stamps_reward_value_cents: int | None = Field(
        None,
        ge=0,
        description="Value of reward in cents (for analytics)",
    )

    # Points configuration
    points_per_euro: int = Field(10, ge=1, le=1000, description="Points per euro spent")
    points_rewards: list[PointsRewardConfig] = Field(
        default_factory=list,
        description="Available point rewards",
    )

    # Anti-fraud
    cooldown_minutes: int = Field(15, ge=0, le=1440, description="Minutes between stamps")
    max_daily_stamps: int = Field(5, ge=1, le=50, description="Max stamps per card per day")
    require_staff_pin: bool = Field(True, description="Require staff PIN for operations")

    # Branding
    card_name: str | None = Field(None, max_length=100, description="Display name for card")
    card_color: str = Field(
        "#4F46E5",
        pattern="^#[0-9A-Fa-f]{6}$",
        description="Primary color (hex)",
    )
    card_secondary_color: str | None = Field(
        None,
        pattern="^#[0-9A-Fa-f]{6}$",
        description="Secondary color (hex)",
    )
    logo_url: str | None = Field(None, max_length=500, description="Logo URL")
    hero_image_url: str | None = Field(None, max_length=500, description="Hero image URL")

    # Terms
    terms_text: str | None = Field(None, description="Terms and conditions")
    privacy_url: str | None = Field(None, max_length=500, description="Privacy policy URL")


class ProgramUpdate(BaseModel):
    """Schema for updating a loyalty program."""

    model_config = ConfigDict(from_attributes=True)

    # Program type (cannot change from stamps to points after cards exist)
    loyalty_type: str | None = Field(
        None,
        pattern="^(stamps|points|hybrid)$",
    )

    # Stamps configuration
    stamps_target: int | None = Field(None, ge=1, le=50)
    stamps_reward_description: str | None = Field(None, max_length=255)
    stamps_reward_value_cents: int | None = Field(None, ge=0)

    # Points configuration
    points_per_euro: int | None = Field(None, ge=1, le=1000)
    points_rewards: list[PointsRewardConfig] | None = None

    # Anti-fraud
    cooldown_minutes: int | None = Field(None, ge=0, le=1440)
    max_daily_stamps: int | None = Field(None, ge=1, le=50)
    require_staff_pin: bool | None = None

    # Branding
    card_name: str | None = Field(None, max_length=100)
    card_color: str | None = Field(None, pattern="^#[0-9A-Fa-f]{6}$")
    card_secondary_color: str | None = Field(None, pattern="^#[0-9A-Fa-f]{6}$")
    logo_url: str | None = Field(None, max_length=500)
    hero_image_url: str | None = Field(None, max_length=500)

    # Terms
    terms_text: str | None = None
    privacy_url: str | None = Field(None, max_length=500)

    # Wallet integration
    google_issuer_id: str | None = Field(None, max_length=100)
    apple_pass_type_id: str | None = Field(None, max_length=100)

    # Status
    is_active: bool | None = None


class ProgramResponse(BaseModel):
    """Schema for loyalty program response."""

    model_config = ConfigDict(from_attributes=True)

    id: int
    vendor_id: int
    loyalty_type: str

    # Stamps
    stamps_target: int
    stamps_reward_description: str
    stamps_reward_value_cents: int | None = None

    # Points
    points_per_euro: int
    points_rewards: list[PointsRewardConfig] = []

    # Anti-fraud
    cooldown_minutes: int
    max_daily_stamps: int
    require_staff_pin: bool

    # Branding
    card_name: str | None = None
    card_color: str
    card_secondary_color: str | None = None
    logo_url: str | None = None
    hero_image_url: str | None = None

    # Terms
    terms_text: str | None = None
    privacy_url: str | None = None

    # Wallet
    google_issuer_id: str | None = None
    google_class_id: str | None = None
    apple_pass_type_id: str | None = None

    # Status
    is_active: bool
    activated_at: datetime | None = None
    created_at: datetime
    updated_at: datetime

    # Computed
    is_stamps_enabled: bool = False
    is_points_enabled: bool = False
    display_name: str = "Loyalty Card"


class ProgramListResponse(BaseModel):
    """Schema for listing loyalty programs (admin)."""

    programs: list[ProgramResponse]
    total: int


class ProgramStatsResponse(BaseModel):
    """Schema for program statistics."""

    # Cards
    total_cards: int = 0
    active_cards: int = 0

    # Stamps (if enabled)
    total_stamps_issued: int = 0
    total_stamps_redeemed: int = 0
    stamps_this_month: int = 0
    redemptions_this_month: int = 0

    # Points (if enabled)
    total_points_issued: int = 0
    total_points_redeemed: int = 0
    points_this_month: int = 0
    points_redeemed_this_month: int = 0

    # Engagement
    cards_with_activity_30d: int = 0
    average_stamps_per_card: float = 0.0
    average_points_per_card: float = 0.0

    # Value
    estimated_liability_cents: int = 0  # Unredeemed stamps/points value
