from pydantic import BaseModel, EmailStr, Field, validator, ConfigDict
from typing import Optional

class RegisterRequest(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    email: EmailStr
    password: str = Field(..., min_length=8)
    phone: Optional[str] = None

    @validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be at least 8 characters')
        if not any((c.isupper() for c in v)):
            raise ValueError('Password must contain at least one uppercase letter')
        if not any((c.islower() for c in v)):
            raise ValueError('Password must contain at least one lowercase letter')
        if not any((c.isdigit() for c in v)):
            raise ValueError('Password must contain at least one number')
        return v

    @validator('phone')
    def validate_phone(cls, v):
        if v:
            cleaned = ''.join(c for c in v if c.isdigit())
            if len(cleaned) < 5:
                raise ValueError('Phone number must contain at least 5 digits')
        return v

class LoginRequest(BaseModel):
    email: EmailStr
    password: str
    rememberMe: Optional[bool] = False
    mfaToken: Optional[str] = None
    expectedRole: Optional[str] = None  # Optional role validation for role-specific login endpoints

class RefreshTokenRequest(BaseModel):
    refreshToken: Optional[str] = None

class ForgotPasswordRequest(BaseModel):
    email: EmailStr

class ResetPasswordRequest(BaseModel):
    token: str
    password: str = Field(..., min_length=8)

    @validator('password')
    def validate_password(cls, v):
        if len(v) < 8:
            raise ValueError('Password must be at least 8 characters')
        if not any((c.isupper() for c in v)):
            raise ValueError('Password must contain at least one uppercase letter')
        if not any((c.islower() for c in v)):
            raise ValueError('Password must contain at least one lowercase letter')
        if not any((c.isdigit() for c in v)):
            raise ValueError('Password must contain at least one number')
        return v

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    phone: Optional[str]
    role: str
    createdAt: Optional[str]
    updatedAt: Optional[str]

    class Config:
        from_attributes = True

class AuthResponse(BaseModel):
    user: UserResponse
    token: str
    refreshToken: Optional[str] = None

class TokenResponse(BaseModel):
    token: str

class MessageResponse(BaseModel):
    status: str
    message: str

class MFAInitResponse(BaseModel):
    secret: str
    qr_code: str

class EnableMFARequest(BaseModel):
    secret: str
    verification_token: str

class VerifyMFARequest(BaseModel):
    token: str
    is_backup_code: Optional[bool] = False

class MFAStatusResponse(BaseModel):
    mfa_enabled: bool
    backup_codes_count: int

class UpdateProfileRequest(BaseModel):
    full_name: Optional[str] = Field(None, min_length=2, max_length=100, description='Full name')
    email: Optional[EmailStr] = Field(None, description='Email address')
    phone_number: Optional[str] = Field(None, min_length=5, max_length=20, description='Phone number')
    password: Optional[str] = Field(None, min_length=8, description='New password')
    currentPassword: Optional[str] = Field(None, alias='current_password', description='Current password (required when changing password)')
    currency: Optional[str] = Field(None, min_length=3, max_length=3, description='Currency code (ISO 4217, e.g., USD, EUR, VND)')

    @validator('password')
    def validate_password(cls, v):
        if v is not None:
            if len(v) < 8:
                raise ValueError('Password must be at least 8 characters')
            if not any((c.isupper() for c in v)):
                raise ValueError('Password must contain at least one uppercase letter')
            if not any((c.islower() for c in v)):
                raise ValueError('Password must contain at least one lowercase letter')
            if not any((c.isdigit() for c in v)):
                raise ValueError('Password must contain at least one number')
        return v

    @validator('phone_number')
    def validate_phone(cls, v):
        if v is not None:
            cleaned = ''.join(c for c in v if c.isdigit())
            if len(cleaned) < 5:
                raise ValueError('Phone number must contain at least 5 digits')
        return v

    @validator('currency')
    def validate_currency(cls, v):
        if v is not None:
            if len(v) != 3 or not v.isalpha():
                raise ValueError('Currency must be a 3-letter ISO 4217 code (e.g., USD, EUR, VND)')
        return v.upper() if v else v

    model_config = ConfigDict(populate_by_name=True)  # Allows population by field name (alias)