from typing import Optional
from pydantic import BaseModel, EmailStr, ConfigDict, field_validator

from app.core.constants import (
    ERR_PASSWORD_LEN,
    ERR_PASSWORD_NUMBER,
    ERR_PASSWORD_SPECIAL_CHAR
)

class UserBase(BaseModel):
    first_name: Optional[str] = None
    last_name: Optional[str] = None
    phone: Optional[str] = None

    model_config = ConfigDict(extra="forbid")

class UserCreate(UserBase):
    email: EmailStr
    password: str

    model_config = ConfigDict(extra="forbid")

    @field_validator("password")
    @classmethod
    def validate_password(cls, value: str) -> str:
        """Enforce a basic password policy for new registrations."""
        if len(value) < 8:
            raise ValueError(ERR_PASSWORD_LEN)
        if not any(c.isdigit() for c in value):
            raise ValueError(ERR_PASSWORD_NUMBER)
        if not any(c in "!@#$%^&*(),.?:{}|<>" for c in value):
            raise ValueError(ERR_PASSWORD_SPECIAL_CHAR)
        return value

class UserUpdate(UserBase):
    """Schema for partial user updates via PATCH."""
    model_config = ConfigDict(extra="forbid")

class UserPasswordChange(BaseModel):
    old_password: str
    new_password: str

    model_config = ConfigDict(extra="forbid")

    @field_validator("new_password")
    @classmethod
    def validate_new_password(cls, value: str) -> str:
        """Validate new password when changing password."""
        if len(value) < 8:
            raise ValueError(ERR_PASSWORD_LEN)
        if not any(c.isdigit() for c in value):
            raise ValueError(ERR_PASSWORD_NUMBER)
        if not any(c in "!@#$%^&*(),.?:{}|<>" for c in value):
            raise ValueError(ERR_PASSWORD_SPECIAL_CHAR)
        return value

class UserRead(UserBase):
    """Representation returned from API (safe, excludes hashed_password)."""
    id: int
    email: EmailStr
    profile_image: Optional[str] = None

    # Use from_attributes so SQLModel objects are serialized correctly
    model_config = ConfigDict(from_attributes=True, extra="ignore")
