# generated by datamodel-codegen:
#   filename:  openapi.bundled.json

from __future__ import annotations

from enum import Enum, StrEnum
from typing import Annotated, Any

from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, EmailStr, Field


class HealthResponse(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    status: str


class ApiError(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    code: str
    message: str
    details: dict[str, Any] | None


class OAuthErrorCode(StrEnum):
    invalid_request = 'invalid_request'
    invalid_client = 'invalid_client'
    invalid_grant = 'invalid_grant'
    unauthorized_client = 'unauthorized_client'
    unsupported_grant_type = 'unsupported_grant_type'
    invalid_scope = 'invalid_scope'
    invalid_token = 'invalid_token'
    access_denied = 'access_denied'
    server_error = 'server_error'
    temporarily_unavailable = 'temporarily_unavailable'


class OAuthScope(StrEnum):
    openid = 'openid'
    profile = 'profile'
    email = 'email'


class OAuthClientStatus(StrEnum):
    active = 'active'
    disabled = 'disabled'


class ResponseTypesSupportedEnum(StrEnum):
    code = 'code'


class GrantTypesSupportedEnum(StrEnum):
    authorization_code = 'authorization_code'


class SubjectTypesSupportedEnum(StrEnum):
    public = 'public'


class IdTokenSigningAlgValuesSupportedEnum(StrEnum):
    RS256 = 'RS256'


class TokenEndpointAuthMethodsSupportedEnum(StrEnum):
    client_secret_basic = 'client_secret_basic'
    client_secret_post = 'client_secret_post'


class ClaimsSupportedEnum(StrEnum):
    iss = 'iss'
    sub = 'sub'
    aud = 'aud'
    exp = 'exp'
    iat = 'iat'
    nonce = 'nonce'
    name = 'name'
    preferred_username = 'preferred_username'
    email = 'email'
    picture = 'picture'


class OpenIdConfiguration(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    issuer: Annotated[
        AnyUrl,
        Field(
            description='Stable issuer URL. id_token `iss` must exactly match this value.'
        ),
    ]
    authorization_endpoint: AnyUrl
    token_endpoint: AnyUrl
    userinfo_endpoint: AnyUrl
    jwks_uri: AnyUrl
    revocation_endpoint: AnyUrl
    end_session_endpoint: AnyUrl
    response_types_supported: list[ResponseTypesSupportedEnum]
    grant_types_supported: list[GrantTypesSupportedEnum]
    subject_types_supported: list[SubjectTypesSupportedEnum]
    id_token_signing_alg_values_supported: list[IdTokenSigningAlgValuesSupportedEnum]
    token_endpoint_auth_methods_supported: list[TokenEndpointAuthMethodsSupportedEnum]
    scopes_supported: list[OAuthScope]
    claims_supported: list[ClaimsSupportedEnum]
    authorization_code_ttl_seconds: Annotated[
        int,
        Field(
            description='Maximum lifetime for one-time authorization codes.',
            ge=30,
            le=600,
        ),
    ]
    access_token_ttl_seconds: Annotated[
        int,
        Field(
            description='Maximum lifetime for access tokens used with userinfo and revocation.',
            ge=300,
            le=86400,
        ),
    ]
    id_token_ttl_seconds: Annotated[
        int,
        Field(
            description='Maximum lifetime for id tokens validated by business-system backends.',
            ge=300,
            le=86400,
        ),
    ]


class GrantType(StrEnum):
    authorization_code = 'authorization_code'


class OAuthTokenRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    grant_type: GrantType
    code: Annotated[str, Field(max_length=1024, min_length=16)]
    redirect_uri: AnyUrl
    client_id: Annotated[
        str | None,
        Field(
            description='Required when client credentials are sent in the request body. Optional when HTTP Basic client authentication is used.',
            max_length=128,
            min_length=1,
        ),
    ] = None
    client_secret: Annotated[
        str | None,
        Field(
            description='Required when using client_secret_post. Must only be sent by confidential backend clients.',
            max_length=512,
            min_length=1,
        ),
    ] = None


class TokenType(StrEnum):
    Bearer = 'Bearer'


class OAuthTokenResponse(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    access_token: Annotated[
        str,
        Field(
            description='Bearer token for User Bill Center resource endpoints such as userinfo.'
        ),
    ]
    token_type: TokenType
    expires_in: Annotated[
        int, Field(description='Access token lifetime in seconds.', ge=1)
    ]
    id_token: Annotated[
        str,
        Field(
            description='JWT signed by User Bill Center. Business systems must validate signature, issuer, audience, expiry, and nonce before creating their local session.'
        ),
    ]
    scope: Annotated[
        str, Field(description='Granted scopes as a space-delimited string.')
    ]


class OidcIdTokenClaims(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    iss: Annotated[AnyUrl, Field(description='Must equal discovery `issuer`.')]
    sub: Annotated[
        str,
        Field(
            description='Stable cross-system user subject. Must not be username or email because those are mutable.'
        ),
    ]
    aud: Annotated[
        str,
        Field(
            description='OAuth client_id for the business system receiving the token.'
        ),
    ]
    exp: Annotated[
        int, Field(description='Expiration time as a Unix timestamp in seconds.')
    ]
    iat: Annotated[
        int, Field(description='Issued-at time as a Unix timestamp in seconds.')
    ]
    nonce: Annotated[str, Field(description='Nonce from the authorize request.')]


class Kty(StrEnum):
    RSA = 'RSA'


class Use(StrEnum):
    sig = 'sig'


class Alg(StrEnum):
    RS256 = 'RS256'


class JsonWebKey(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    kty: Kty
    use: Use
    kid: Annotated[str, Field(description='Key id referenced by JWT header `kid`.')]
    alg: Alg
    n: Annotated[str, Field(description='Base64url-encoded RSA modulus.')]
    e: Annotated[str, Field(description='Base64url-encoded RSA exponent.')]


class JsonWebKeySet(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    keys: list[JsonWebKey]


class TokenTypeHint(Enum):
    access_token = 'access_token'
    refresh_token = 'refresh_token'
    NoneType_None = None


class OAuthTokenRevocationRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    token: Annotated[str, Field(max_length=4096, min_length=1)]
    token_type_hint: TokenTypeHint | None
    client_id: Annotated[
        str | None,
        Field(
            description='Required when client credentials are sent in the request body. Optional when HTTP Basic client authentication is used.',
            max_length=128,
            min_length=1,
        ),
    ] = None
    client_secret: Annotated[
        str | None,
        Field(
            description='Required when using client_secret_post. Must only be sent by confidential backend clients.',
            max_length=512,
            min_length=1,
        ),
    ] = None


class OAuthTokenRevocationResponse(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    revoked: bool


class AuthProvider(StrEnum):
    password = 'password'
    wechat_open = 'wechat_open'


class UserStatus(StrEnum):
    active = 'active'
    disabled = 'disabled'


class UserRole(StrEnum):
    visitor = 'visitor'
    user = 'user'
    super_admin = 'super_admin'


class AdminCreatableUserRole(StrEnum):
    visitor = 'visitor'
    user = 'user'


class AuthMethod(StrEnum):
    password = 'password'
    wechat_open = 'wechat_open'


class OAuthIdentityProvider(StrEnum):
    wechat_open = 'wechat_open'


class LinkedOAuthIdentity(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    identity_id: str
    provider: OAuthIdentityProvider
    appid: str
    openid: str
    unionid: str | None
    nickname: str | None
    avatar_url: AnyUrl | None


class RegisterRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    username: Annotated[str | None, Field(max_length=64, min_length=3)]
    phone: Annotated[str | None, Field(max_length=32, min_length=3)] = None
    email: EmailStr | None = None
    password: Annotated[str, Field(max_length=256, min_length=8)]
    nickname: Annotated[str | None, Field(max_length=100)]


class LoginRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    login_identifier: Annotated[str, Field(max_length=255, min_length=1)]
    password: Annotated[str, Field(max_length=256, min_length=1)]


class ChangePasswordRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    current_password: Annotated[str, Field(max_length=256, min_length=1)]
    new_password: Annotated[str, Field(max_length=256, min_length=8)]


class PasswordResetRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    login_identifier: Annotated[str, Field(max_length=255, min_length=1)]


class PasswordResetRequestResult(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    accepted: bool
    expires_at: AwareDatetime | None
    dev_reset_token: str | None


class ConfirmPasswordResetRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    reset_token: Annotated[str, Field(max_length=512, min_length=16)]
    new_password: Annotated[str, Field(max_length=256, min_length=8)]


class AdminUser(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    user_id: str
    username: str | None
    phone: Annotated[str | None, Field(max_length=32, min_length=3)]
    email: EmailStr | None
    nickname: str | None
    avatar_url: AnyUrl | None
    status: UserStatus
    role: UserRole
    auth_methods: list[AuthMethod]
    linked_oauth_identities: list[LinkedOAuthIdentity]
    created_at: AwareDatetime
    updated_at: AwareDatetime


class AdminUserList(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    users: list[AdminUser]


class AdminCreateUserRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    username: Annotated[str | None, Field(max_length=64, min_length=3)]
    phone: Annotated[str | None, Field(max_length=32, min_length=3)] = None
    email: EmailStr | None = None
    password: Annotated[str, Field(max_length=256, min_length=8)]
    nickname: Annotated[str | None, Field(max_length=100)]
    role: AdminCreatableUserRole


class AdminOAuthClient(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    client_id: Annotated[
        str,
        Field(
            description='Stable OAuth audience. id_token `aud` must equal this value.',
            max_length=128,
            min_length=1,
        ),
    ]
    client_name: Annotated[str, Field(max_length=128, min_length=1)]
    status: OAuthClientStatus
    redirect_uris: Annotated[
        list[AnyUrl],
        Field(
            description='Exact redirect_uri whitelist. Authorize and token requests must use one of these values.',
            min_length=1,
        ),
    ]
    post_logout_redirect_uris: Annotated[
        list[AnyUrl], Field(description='Exact post-logout redirect whitelist.')
    ]
    allowed_scopes: Annotated[list[OAuthScope], Field(min_length=1)]
    authorization_code_ttl_seconds: Annotated[int, Field(ge=30, le=600)]
    access_token_ttl_seconds: Annotated[int, Field(ge=300, le=86400)]
    id_token_ttl_seconds: Annotated[int, Field(ge=300, le=86400)]
    created_at: AwareDatetime
    updated_at: AwareDatetime


class AdminOAuthClientWithSecret(AdminOAuthClient):
    client_secret: Annotated[
        str,
        Field(
            description='One-time plaintext client secret. Store only on the confidential client backend.',
            max_length=512,
            min_length=32,
        ),
    ]


class AdminOAuthClientList(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    clients: list[AdminOAuthClient]


class AdminCreateOAuthClientRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    client_id: Annotated[str, Field(max_length=128, min_length=1)]
    client_name: Annotated[str, Field(max_length=128, min_length=1)]
    redirect_uris: Annotated[list[AnyUrl], Field(min_length=1)]
    post_logout_redirect_uris: list[AnyUrl]
    allowed_scopes: Annotated[list[OAuthScope], Field(min_length=1)]
    authorization_code_ttl_seconds: Annotated[int, Field(ge=30, le=600)]
    access_token_ttl_seconds: Annotated[int, Field(ge=300, le=86400)]
    id_token_ttl_seconds: Annotated[int, Field(ge=300, le=86400)]


class AdminUpdateOAuthClientRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    client_name: Annotated[str | None, Field(max_length=128, min_length=1)]
    status: OAuthClientStatus | None
    redirect_uris: Annotated[list[AnyUrl] | None, Field(min_length=1)]
    post_logout_redirect_uris: list[AnyUrl] | None
    allowed_scopes: Annotated[list[OAuthScope] | None, Field(min_length=1)]
    authorization_code_ttl_seconds: Annotated[int | None, Field(ge=30, le=600)]
    access_token_ttl_seconds: Annotated[int | None, Field(ge=300, le=86400)]
    id_token_ttl_seconds: Annotated[int | None, Field(ge=300, le=86400)]


class Scope(StrEnum):
    snsapi_login = 'snsapi_login'


class WechatLoginConfig(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    appid: str
    redirect_uri: AnyUrl
    scope: Scope
    state: str
    auth_url: AnyUrl


class WechatLoginStatusValue(StrEnum):
    pending = 'pending'
    scanned = 'scanned'
    confirmed = 'confirmed'
    logged_in = 'logged_in'
    expired = 'expired'


class WechatLoginStateRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    state: Annotated[str, Field(max_length=256, min_length=1)]


class DevMockWechatQrSession(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    state: str
    status: WechatLoginStatusValue
    qr_payload: str
    expires_at: AwareDatetime


class DevMockWechatLoginRequest(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    openid: Annotated[str, Field(max_length=128, min_length=1)]
    unionid: Annotated[str | None, Field(max_length=128)]
    nickname: Annotated[str | None, Field(max_length=100)]
    avatar_url: AnyUrl | None


class OAuthError(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    error: OAuthErrorCode
    error_description: str | None
    error_uri: AnyUrl | None


class OAuthUserInfo(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    sub: Annotated[
        str,
        Field(description='Stable User Bill Center subject, equal to id_token `sub`.'),
    ]
    name: str | None
    preferred_username: str | None
    email: EmailStr | None
    picture: AnyUrl | None
    status: UserStatus
    role: UserRole


class AuthUser(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    user_id: str
    username: str | None
    phone: Annotated[str | None, Field(max_length=32, min_length=3)]
    email: EmailStr | None
    nickname: str | None
    avatar_url: AnyUrl | None
    status: UserStatus
    role: UserRole
    auth_provider: AuthProvider


class AuthSession(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    user: AuthUser


class CurrentAuthSession(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    user: AuthUser | None


class WechatLoginStatus(BaseModel):
    model_config = ConfigDict(
        extra='forbid',
    )
    state: str
    status: WechatLoginStatusValue
    user: AuthUser | None
    expires_at: AwareDatetime | None
