from datetime import datetime

from pydantic import BaseModel, EmailStr, Field, field_validator

from app.core import sensitive

CN_PHONE_PATTERN = r"^1[3-9]\d{9}$"


class GeetestPayload(BaseModel):
    lot_number: str
    captcha_output: str
    pass_token: str
    gen_time: str


class SendCodeRequest(BaseModel):
    email: EmailStr
    captcha: GeetestPayload | None = None


class SendSmsRequest(BaseModel):
    phone: str = Field(..., pattern=CN_PHONE_PATTERN)
    captcha: GeetestPayload | None = None


class UserRegister(BaseModel):
    email: EmailStr
    username: str = Field(..., min_length=3, max_length=50, pattern=r"^[a-zA-Z0-9_]+$")
    code: str = Field(..., min_length=6, max_length=6, pattern=r"^\d{6}$")
    password: str | None = Field(default=None, min_length=8, max_length=128)
    captcha: GeetestPayload | None = None
    invite_code: str | None = None


class UserRegisterBySms(BaseModel):
    phone: str = Field(..., pattern=CN_PHONE_PATTERN)
    username: str = Field(..., min_length=3, max_length=50, pattern=r"^[a-zA-Z0-9_]+$")
    code: str = Field(..., min_length=6, max_length=6, pattern=r"^\d{6}$")
    password: str | None = Field(default=None, min_length=8, max_length=128)
    captcha: GeetestPayload | None = None
    invite_code: str | None = None


class UserLogin(BaseModel):
    email: str
    password: str
    captcha: GeetestPayload | None = None


class LoginByCodeRequest(BaseModel):
    email: EmailStr
    code: str = Field(..., min_length=6, max_length=6, pattern=r"^\d{6}$")
    captcha: GeetestPayload | None = None


class LoginBySmsRequest(BaseModel):
    phone: str = Field(..., pattern=CN_PHONE_PATTERN)
    code: str = Field(..., min_length=6, max_length=6, pattern=r"^\d{6}$")
    captcha: GeetestPayload | None = None


class UserResponse(BaseModel):
    id: int
    email: str | None
    username: str
    phone: str | None
    avatar: str | None
    nickname: str | None
    real_name: str | None
    id_card_verified: str | None
    role: str
    status: str
    is_email_verified: bool
    has_password: bool
    balance: int
    created_at: datetime

    @field_validator("real_name", mode="before")
    @classmethod
    def mask_real_name(cls, value: str | None) -> str | None:
        return sensitive.mask_name(value)

    model_config = {"from_attributes": True}


class UserUpdate(BaseModel):
    nickname: str | None = None
    avatar: str | None = None


class PasswordChange(BaseModel):
    old_password: str | None = None
    new_password: str = Field(..., min_length=8, max_length=128)


class BindEmailRequest(BaseModel):
    email: EmailStr
    code: str = Field(..., min_length=6, max_length=6, pattern=r"^\d{6}$")


class BindPhoneRequest(BaseModel):
    phone: str = Field(..., pattern=CN_PHONE_PATTERN)
    code: str = Field(..., min_length=6, max_length=6, pattern=r"^\d{6}$")
