from typing import Optional, List
from datetime import datetime
from pydantic import BaseModel, Field, model_validator


_DEFAULT_SCOPES = "user:read,user:write,org:read,org:write"
_ALLOWED_SCOPES = {"user:read", "user:write", "org:read", "org:write"}


def _normalize_scopes(value: Optional[str]) -> str:
    """规范化 scopes 字符串：去重、去空、按字典序、白名单校验。"""
    if not value:
        return _DEFAULT_SCOPES
    parts = [s.strip() for s in value.split(",") if s.strip()]
    cleaned = sorted(set(parts))
    invalid = [s for s in cleaned if s not in _ALLOWED_SCOPES]
    if invalid:
        raise ValueError(f"无效的 scope: {', '.join(invalid)}")
    return ",".join(cleaned) if cleaned else _DEFAULT_SCOPES


class AdminApiKeyCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    description: Optional[str] = None
    scopes: Optional[str] = Field(default=None, description="逗号分隔；允许 user:read/write 与 org:read/write")
    admin_password: str = Field(..., min_length=1, description="操作者密码")
    sms_code: str = Field(..., min_length=1, description="发送至操作者手机的短信验证码")

    @model_validator(mode="after")
    def _normalize(self):
        self.scopes = _normalize_scopes(self.scopes)
        return self


class AdminApiKeyUpdate(BaseModel):
    name: Optional[str] = Field(None, min_length=1, max_length=100)
    description: Optional[str] = None
    scopes: Optional[str] = None

    @model_validator(mode="after")
    def _normalize(self):
        if self.scopes is not None:
            self.scopes = _normalize_scopes(self.scopes)
        return self


class AdminApiKeyRevoke(BaseModel):
    admin_password: str = Field(..., min_length=1)
    sms_code: str = Field(..., min_length=1)


class AdminApiKeyResponse(BaseModel):
    id: int
    name: str
    description: Optional[str] = None
    key_prefix: str
    scopes: str
    is_active: bool
    is_revoked: bool
    created_by: int
    creator_mobile: Optional[str] = None
    last_used_at: Optional[datetime] = None
    last_used_ip: Optional[str] = None
    use_count: int
    created_at: datetime
    updated_at: datetime

    @model_validator(mode="before")
    @classmethod
    def _flatten_creator(cls, data):
        from app.models.admin_api_key import AdminApiKey as _AdminApiKey

        if isinstance(data, _AdminApiKey):
            d = {c.name: getattr(data, c.name) for c in data.__table__.columns}
            creator = getattr(data, "creator", None)
            d["creator_mobile"] = creator.mobile if creator is not None else None
            return d
        return data

    class Config:
        from_attributes = True


class AdminApiKeyList(BaseModel):
    total: int
    items: List[AdminApiKeyResponse]


class AdminApiKeySecretDisplay(AdminApiKeyResponse):
    """创建接口专用：携带一次性明文。"""

    key_once: str = Field(..., description="完整明文 Key，仅在创建时返回一次")


# ---------------------------------------------------------------------------
# /admin-api/users 入参 schema（独立于 users.py 的 UserCreate / UserUpdate，
# 不接受 mobile/role/status/is_deleted 等敏感字段）
# ---------------------------------------------------------------------------

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


class AdminApiUserCreate(BaseModel):
    mobile: str = Field(..., pattern=_CN_MOBILE_PATTERN, description="中国大陆手机号")
    password: str = Field(..., min_length=6, max_length=64)
    name: Optional[str] = None
    english_name: Optional[str] = None
    organization_id: Optional[int] = None


class AdminApiUserUpdate(BaseModel):
    """更新用户：仅允许常规非敏感字段。

    显式不允许 mobile / role / status / is_deleted —— 在 endpoint 中通过
    extra="forbid" 直接 422，二次保险。
    """

    name: Optional[str] = None
    english_name: Optional[str] = None
    password: Optional[str] = Field(None, min_length=6, max_length=64)
    organization_id: Optional[int] = None

    class Config:
        extra = "forbid"


# ---------------------------------------------------------------------------
# /admin-api/organizations 入参 schema（与原 OrganizationUpdate 不同：
# 不要求 captcha，因为 X-Admin-Api-Key 本身已是凭证）
# ---------------------------------------------------------------------------


class AdminApiOrganizationCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    description: Optional[str] = None
    sort_order: int = 0


class AdminApiOrganizationUpdate(BaseModel):
    name: Optional[str] = Field(None, min_length=1, max_length=100)
    description: Optional[str] = None
    sort_order: Optional[int] = None

    class Config:
        extra = "forbid"
