from pydantic import BaseModel, Field, validator
from typing import Optional, List

class TicketExchangeRequest(BaseModel):
    app_id: str
    target_app_id: str
    user_mobile: str
    timestamp: int
    sign: str

class TicketExchangeResponse(BaseModel):
    ticket: str
    redirect_url: str

class TicketValidateRequest(BaseModel):
    ticket: str
    app_id: str # The app trying to validate
    sign: str
    timestamp: int

class TicketValidateResponse(BaseModel):
    valid: bool
    user_id: Optional[int] = None
    mobile: Optional[str] = None
    mapped_key: Optional[str] = None
    mapped_email: Optional[str] = None

class PasswordLoginRequest(BaseModel):
    app_id: Optional[str] = Field(
        None, 
        description="应用ID。不提供时为平台登录（返回access_token），提供时为应用SSO登录（返回ticket）"
    )
    identifier: str = Field(
        ..., 
        description="用户标识：手机号、映射key或映射email"
    )
    password: str = Field(
        ..., 
        description="用户密码"
    )
    remember_me: bool = Field(
        False,
        description="是否记住登录（长期有效）"
    )
    sign: Optional[str] = Field(
        None, 
        description="签名（可选）。如果提供，必须同时提供timestamp。用于服务端安全调用"
    )
    timestamp: Optional[int] = Field(
        None, 
        description="时间戳（可选）。如果提供，必须同时提供sign"
    )
    
    @validator('timestamp')
    def validate_sign_timestamp(cls, v, values):
        """验证 sign 和 timestamp 必须同时提供或同时不提供"""
        sign = values.get('sign')
        if (sign and not v) or (not sign and v):
            raise ValueError('sign 和 timestamp 必须同时提供或同时不提供')
        return v

class PasswordLoginResponse(BaseModel):
    ticket: Optional[str] = Field(
        None, 
        description="票据。当提供app_id时返回，用于应用SSO登录"
    )
    access_token: Optional[str] = Field(
        None, 
        description="访问令牌。当未提供app_id时返回，用于平台登录"
    )
    token_type: Optional[str] = Field(
        None, 
        description="令牌类型，固定为 'bearer'"
    )
    role: Optional[str] = Field(
        None, 
        description="用户角色：SUPER_ADMIN / DEVELOPER / ORDINARY_USER"
    )

class SmsLoginRequest(BaseModel):
    mobile: str = Field(..., description="手机号")
    code: str = Field(..., description="验证码")
    remember_me: bool = Field(
        False,
        description="记住我：为 true 时 JWT 使用较长有效期（与密码登录一致）",
    )
    app_id: Optional[str] = Field(
        None, 
        description="应用ID。不提供时为平台登录（返回access_token），提供时为应用SSO登录（返回ticket）"
    )
    sign: Optional[str] = Field(
        None, 
        description="签名（可选）。如果提供，必须同时提供timestamp。用于服务端安全调用"
    )
    timestamp: Optional[int] = Field(
        None, 
        description="时间戳（可选）。如果提供，必须同时提供sign"
    )
    
    @validator('timestamp')
    def validate_sign_timestamp(cls, v, values):
        """验证 sign 和 timestamp 必须同时提供或同时不提供"""
        sign = values.get('sign')
        if (sign and not v) or (not sign and v):
            raise ValueError('sign 和 timestamp 必须同时提供或同时不提供')
        return v

class UserRegisterRequest(BaseModel):
    mobile: str
    password: str
    name: str # Added field
    app_id: Optional[str] = None # Optional, if registering via an app context

class AdminPasswordResetRequest(BaseModel):
    user_id: int
    admin_password: str

class AdminPasswordResetResponse(BaseModel):
    new_password: str

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

class UserMappingResponse(BaseModel):
    app_name: str
    app_id: str
    protocol_type: str
    mapped_key: Optional[str] = None
    mapped_email: Optional[str] = None
    is_active: bool

class MyMappingsResponse(BaseModel):
    total: int
    items: List[UserMappingResponse]

class UserPromoteRequest(BaseModel):
    user_id: int
    new_role: str

class SsoLoginRequest(BaseModel):
    app_id: str = Field(
        ..., 
        description="应用ID（必填）。支持 SIMPLE_API、OIDC 与 NONE（导航）应用"
    )
    username: Optional[str] = Field(
        None, 
        description="用户名（条件必填）。如果用户未登录UAP平台，则必须提供 username 和 password"
    )
    password: Optional[str] = Field(
        None, 
        description="密码（条件必填）。如果用户未登录UAP平台，则必须提供 username 和 password"
    )
    
    class Config:
        json_schema_extra = {
            "examples": [
                {
                    "description": "场景1：用户已登录UAP（使用会话）",
                    "value": {
                        "app_id": "my_app_123"
                    }
                },
                {
                    "description": "场景2：用户未登录（使用凭据）",
                    "value": {
                        "app_id": "my_app_123",
                        "username": "13800138000",
                        "password": "password123"
                    }
                }
            ]
        }

class SsoLoginResponse(BaseModel):
    redirect_url: str = Field(
        ..., 
        description="重定向URL。SIMPLE_API 为「回调地址?ticket=...」；OIDC 为仅含 scheme+host 的地址；NONE 为导航 URL 原文，无 ticket"
    )

class LaunchpadAppResponse(BaseModel):
    """快捷导航应用响应模型（包含分类和描述）"""
    app_name: str
    app_id: str
    protocol_type: str
    mapped_key: Optional[str] = None
    mapped_email: Optional[str] = None
    is_active: bool
    description: Optional[str] = None  # 应用描述
    category_id: Optional[int] = None  # 分类ID
    category_name: Optional[str] = None  # 分类名称
    icon_url: Optional[str] = None  # 解析后的 Logo 地址（预签名或直链）
    icon_object_key: Optional[str] = None  # MinIO object key（非 http(s)），供前端 IndexedDB 稳定缓存键

class LaunchpadAppsResponse(BaseModel):
    """快捷导航应用列表响应"""
    total: int  # 总数量（方便前端使用）
    items: List[LaunchpadAppResponse]