# app/modules/customers/schemas/customer.py
"""
Pydantic schemas for customer-related operations.

Provides schemas for:
- Customer registration and authentication
- Customer profile management
- Customer addresses
- Admin customer management
"""

from datetime import date, datetime
from decimal import Decimal

from pydantic import BaseModel, EmailStr, Field, field_validator

# ============================================================================
# Customer Registration & Authentication
# ============================================================================


class CustomerRegister(BaseModel):
    """Schema for customer registration."""

    email: EmailStr = Field(..., description="Customer email address")
    password: str = Field(
        ..., min_length=8, description="Password (minimum 8 characters)"
    )
    first_name: str = Field(..., min_length=1, max_length=100)
    last_name: str = Field(..., min_length=1, max_length=100)
    phone: str | None = Field(None, max_length=50)
    marketing_consent: bool = Field(default=False)
    preferred_language: str | None = Field(
        None, description="Preferred language (en, fr, de, lb)"
    )

    @field_validator("email")
    @classmethod
    def email_lowercase(cls, v: str) -> str:
        """Convert email to lowercase."""
        return v.lower()

    @field_validator("password")
    @classmethod
    def password_strength(cls, v: str) -> str:
        """Validate password strength."""
        if len(v) < 8:
            raise ValueError("Password must be at least 8 characters")
        if not any(char.isdigit() for char in v):
            raise ValueError("Password must contain at least one digit")
        if not any(char.isalpha() for char in v):
            raise ValueError("Password must contain at least one letter")
        return v


class CustomerUpdate(BaseModel):
    """Schema for updating customer profile."""

    email: EmailStr | None = None
    first_name: str | None = Field(None, min_length=1, max_length=100)
    last_name: str | None = Field(None, min_length=1, max_length=100)
    phone: str | None = Field(None, max_length=50)
    birth_date: date | None = Field(
        None, description="Date of birth (YYYY-MM-DD)"
    )
    marketing_consent: bool | None = None
    preferred_language: str | None = Field(
        None, description="Preferred language (en, fr, de, lb)"
    )

    @field_validator("email")
    @classmethod
    def email_lowercase(cls, v: str | None) -> str | None:
        """Convert email to lowercase."""
        return v.lower() if v else None

    @field_validator("birth_date")
    @classmethod
    def birth_date_sane(cls, v: date | None) -> date | None:
        """Birthday must be in the past and within a plausible age range."""
        if v is None:
            return v
        today = date.today()
        if v >= today:
            raise ValueError("birth_date must be in the past")
        # Plausible human age range — guards against typos like 0001-01-01
        years = (today - v).days / 365.25
        if years < 13 or years > 120:
            raise ValueError("birth_date implies an implausible age")
        return v


class CustomerPasswordChange(BaseModel):
    """Schema for customer password change."""

    current_password: str = Field(..., description="Current password")
    new_password: str = Field(
        ..., min_length=8, description="New password (minimum 8 characters)"
    )
    confirm_password: str = Field(..., description="Confirm new password")

    @field_validator("new_password")
    @classmethod
    def password_strength(cls, v: str) -> str:
        """Validate password strength."""
        if len(v) < 8:
            raise ValueError("Password must be at least 8 characters")
        if not any(char.isdigit() for char in v):
            raise ValueError("Password must contain at least one digit")
        if not any(char.isalpha() for char in v):
            raise ValueError("Password must contain at least one letter")
        return v


# ============================================================================
# Customer Response
# ============================================================================


class CustomerResponse(BaseModel):
    """Schema for customer response (excludes password)."""

    id: int
    store_id: int
    email: str
    first_name: str | None
    last_name: str | None
    phone: str | None
    birth_date: date | None = None
    customer_number: str
    marketing_consent: bool
    preferred_language: str | None
    is_active: bool
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}

    @property
    def full_name(self) -> str:
        """Get customer full name."""
        if self.first_name and self.last_name:
            return f"{self.first_name} {self.last_name}"
        return self.email


class CustomerListResponse(BaseModel):
    """Schema for paginated customer list."""

    customers: list[CustomerResponse]
    total: int
    page: int
    per_page: int
    total_pages: int


# ============================================================================
# Customer Address
# ============================================================================


class CustomerAddressCreate(BaseModel):
    """Schema for creating customer address."""

    address_type: str = Field(..., pattern="^(billing|shipping)$")
    first_name: str = Field(..., min_length=1, max_length=100)
    last_name: str = Field(..., min_length=1, max_length=100)
    company: str | None = Field(None, max_length=200)
    address_line_1: str = Field(..., min_length=1, max_length=255)
    address_line_2: str | None = Field(None, max_length=255)
    city: str = Field(..., min_length=1, max_length=100)
    postal_code: str = Field(..., min_length=1, max_length=20)
    country_name: str = Field(..., min_length=2, max_length=100)
    country_iso: str = Field(..., min_length=2, max_length=5)
    is_default: bool = Field(default=False)


class CustomerAddressUpdate(BaseModel):
    """Schema for updating customer address."""

    address_type: str | None = Field(None, pattern="^(billing|shipping)$")
    first_name: str | None = Field(None, min_length=1, max_length=100)
    last_name: str | None = Field(None, min_length=1, max_length=100)
    company: str | None = Field(None, max_length=200)
    address_line_1: str | None = Field(None, min_length=1, max_length=255)
    address_line_2: str | None = Field(None, max_length=255)
    city: str | None = Field(None, min_length=1, max_length=100)
    postal_code: str | None = Field(None, min_length=1, max_length=20)
    country_name: str | None = Field(None, min_length=2, max_length=100)
    country_iso: str | None = Field(None, min_length=2, max_length=5)
    is_default: bool | None = None


class CustomerAddressResponse(BaseModel):
    """Schema for customer address response."""

    id: int
    store_id: int
    customer_id: int
    address_type: str
    first_name: str
    last_name: str
    company: str | None
    address_line_1: str
    address_line_2: str | None
    city: str
    postal_code: str
    country_name: str
    country_iso: str
    is_default: bool
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class CustomerAddressListResponse(BaseModel):
    """Schema for customer address list response."""

    addresses: list[CustomerAddressResponse]
    total: int


# ============================================================================
# Customer Preferences
# ============================================================================


class CustomerPreferencesUpdate(BaseModel):
    """Schema for updating customer preferences."""

    marketing_consent: bool | None = None
    preferred_language: str | None = Field(
        None, description="Preferred language (en, fr, de, lb)"
    )
    currency: str | None = Field(None, max_length=3)
    notification_preferences: dict[str, bool] | None = None


# ============================================================================
# Store Customer Management Response Schemas
# ============================================================================


class CustomerMessageResponse(BaseModel):
    """Simple message response for customer operations."""

    message: str


class StoreCustomerListResponse(BaseModel):
    """Schema for store customer list with skip/limit pagination."""

    customers: list[CustomerResponse] = []
    total: int = 0
    skip: int = 0
    limit: int = 100
    message: str | None = None


class CustomerDetailResponse(BaseModel):
    """Detailed customer response for store management.

    Note: Order-related statistics (total_orders, total_spent, last_order_date)
    are available via the orders module endpoint:
    GET /api/store/customers/{customer_id}/order-stats
    """

    id: int | None = None
    store_id: int | None = None
    email: str | None = None
    first_name: str | None = None
    last_name: str | None = None
    phone: str | None = None
    birth_date: date | None = None
    customer_number: str | None = None
    marketing_consent: bool | None = None
    preferred_language: str | None = None
    is_active: bool | None = None
    created_at: datetime | None = None
    updated_at: datetime | None = None
    message: str | None = None

    model_config = {"from_attributes": True}


class CustomerOrderInfo(BaseModel):
    """Basic order info for customer order history."""

    id: int
    order_number: str
    status: str
    total: Decimal
    created_at: datetime


class CustomerOrdersResponse(BaseModel):
    """Response for customer order history."""

    orders: list[CustomerOrderInfo] = []
    total: int = 0
    message: str | None = None


class CustomerStatisticsResponse(BaseModel):
    """Response for customer statistics."""

    total: int = 0
    active: int = 0
    inactive: int = 0


# ============================================================================
# Admin Customer Management Response Schemas
# ============================================================================


class AdminCustomerItem(BaseModel):
    """Admin customer list item with store info."""

    id: int
    store_id: int
    email: str
    first_name: str | None = None
    last_name: str | None = None
    phone: str | None = None
    birth_date: date | None = None
    customer_number: str
    marketing_consent: bool = False
    preferred_language: str | None = None
    is_active: bool = True
    created_at: datetime
    updated_at: datetime
    store_name: str | None = None
    store_code: str | None = None

    model_config = {"from_attributes": True}


class AdminCustomerListResponse(BaseModel):
    """Admin paginated customer list with skip/limit."""

    customers: list[AdminCustomerItem] = []
    total: int = 0
    skip: int = 0
    limit: int = 20


class AdminCustomerDetailResponse(AdminCustomerItem):
    """Detailed customer response for admin."""
