# generated by datamodel-codegen:
#   filename:  schema.yaml

from __future__ import annotations

from enum import Enum
from typing import Annotated, Any, Dict, List, Optional, Union, Mapping

from pydantic import AnyUrl, BaseModel, EmailStr, Extra, Field


class Reference(BaseModel):
    class Config:
        extra = Extra.forbid

    ref: Annotated[str, Field(alias='$ref')]


class Contact(BaseModel):
    class Config:
        extra = Extra.forbid

    name: Optional[str]
    url: Optional[str]
    email: Optional[EmailStr]


class License(BaseModel):
    class Config:
        extra = Extra.forbid

    name: str
    url: Optional[str]


class ServerVariable(BaseModel):
    class Config:
        extra = Extra.forbid

    enum: Optional[List[str]]
    default: str
    description: Optional[str]


class Type(Enum):
    array = 'array'
    boolean = 'boolean'
    integer = 'integer'
    number = 'number'
    object = 'object'
    string = 'string'


class Discriminator(BaseModel):
    propertyName: str
    mapping: Optional[Dict[str, str]]


class XML(BaseModel):
    class Config:
        extra = Extra.forbid

    name: Optional[str]
    namespace: Optional[AnyUrl]
    prefix: Optional[str]
    attribute: Optional[bool] = False
    wrapped: Optional[bool] = False


class Example(BaseModel):
    class Config:
        extra = Extra.forbid

    summary: Optional[str]
    description: Optional[str]
    value: Optional[Any]
    externalValue: Optional[str]


class Style(Enum):
    simple = 'simple'


class Paths(BaseModel):
    __root__: Annotated[dict[str, Union[PathItem, Reference]], Field(default_factory=dict)]


class SecurityRequirement(BaseModel):
    __root__: Annotated[dict[str, list[str]], Field(default_factory=dict)]


class ExternalDocumentation(BaseModel):
    class Config:
        extra = Extra.forbid

    description: Optional[str]
    url: str


class ExampleXORExamples(BaseModel):
    __root__: Annotated[
        Any,
        Field(
            description='Example and examples are mutually exclusive',
            not_={'required': ['example', 'examples']},
        ),
    ]


class SchemaXORContentItem(Reference):
    """
    Some properties are not allowed if content is present
    """

    pass


class SchemaXORContent(BaseModel):
    __root__: Annotated[
        Union[Any, SchemaXORContentItem],
        Field(
            description='Schema and content are mutually exclusive, at least one is required',
            not_={'required': ['schema', 'content']},
        ),
    ]


class In(Enum):
    path = 'path'


class Style1(Enum):
    matrix = 'matrix'
    label = 'label'
    simple = 'simple'


class Required(Enum):
    bool_True = True


class ParameterLocationItem(BaseModel):
    """
    Parameter in path
    """

    in_: Annotated[Optional[In], Field(alias='in')]
    style: Optional[Style1] = 'simple'
    required: Required


class In1(Enum):
    query = 'query'


class Style2(Enum):
    form = 'form'
    spaceDelimited = 'spaceDelimited'
    pipeDelimited = 'pipeDelimited'
    deepObject = 'deepObject'


class ParameterLocationItem1(BaseModel):
    """
    Parameter in query
    """

    in_: Annotated[Optional[In1], Field(alias='in')]
    style: Optional[Style2] = 'form'


class In2(Enum):
    header = 'header'


class ParameterLocationItem2(BaseModel):
    """
    Parameter in header
    """

    in_: Annotated[Optional[In2], Field(alias='in')]
    style: Optional[Style] = 'simple'


class In3(Enum):
    cookie = 'cookie'


class Style4(Enum):
    form = 'form'


class ParameterLocationItem3(BaseModel):
    """
    Parameter in cookie
    """

    in_: Annotated[Optional[In3], Field(alias='in')]
    style: Optional[Style4] = 'form'


class ParameterLocation(BaseModel):
    __root__: Annotated[
        Union[
            ParameterLocationItem,
            ParameterLocationItem1,
            ParameterLocationItem2,
            ParameterLocationItem3,
        ],
        Field(description='Parameter location'),
    ]


class Type1(Enum):
    apiKey = 'apiKey'


class In4(Enum):
    header = 'header'
    query = 'query'
    cookie = 'cookie'


class APIKeySecurityScheme(BaseModel):
    class Config:
        extra = Extra.forbid

    type: Type1
    name: str
    in_: Annotated[In4, Field(alias='in')]
    description: Optional[str]


class Type2(Enum):
    http = 'http'


class HTTPSecurityScheme1(BaseModel):
    class Config:
        extra = Extra.forbid

    scheme: str
    bearerFormat: Optional[str]
    description: Optional[str]
    type: Type2


class Scheme(Enum):
    bearer = 'bearer'


class HTTPSecuritySchemeItem(BaseModel):
    """
    Bearer
    """

    scheme: Optional[Scheme]


class HTTPSecuritySchemeItem1(BaseModel):
    """
    Non Bearer
    """

    scheme: Annotated[Optional[Any], Field(not_={'enum': ['bearer']})]


class HTTPSecurityScheme(BaseModel):
    class Config:
        extra = Extra.forbid

    __root__: Union[
        HTTPSecurityScheme1, HTTPSecuritySchemeItem, HTTPSecuritySchemeItem1
    ]


class Type3(Enum):
    oauth2 = 'oauth2'


class Type4(Enum):
    openIdConnect = 'openIdConnect'


class OpenIdConnectSecurityScheme(BaseModel):
    class Config:
        extra = Extra.forbid

    type: Type4
    openIdConnectUrl: str
    description: Optional[str]


class ImplicitOAuthFlow(BaseModel):
    class Config:
        extra = Extra.forbid

    authorizationUrl: str
    refreshUrl: Optional[str]
    scopes: Dict[str, str]


class PasswordOAuthFlow(BaseModel):
    class Config:
        extra = Extra.forbid

    tokenUrl: str
    refreshUrl: Optional[str]
    scopes: Optional[Dict[str, str]]


class ClientCredentialsFlow(PasswordOAuthFlow):
    pass


class AuthorizationCodeOAuthFlow(BaseModel):
    class Config:
        extra = Extra.forbid

    authorizationUrl: str
    tokenUrl: str
    refreshUrl: Optional[str]
    scopes: Optional[Dict[str, str]]


class Callback(BaseModel):
    __root__: Annotated[dict[str, Union[PathItem, Reference]], Field(default_factory=dict)]


class Info(BaseModel):
    class Config:
        extra = Extra.forbid

    title: str
    description: Optional[str]
    termsOfService: Optional[str]
    contact: Optional[Contact]
    license: Optional[License]
    version: str


class Server(BaseModel):
    class Config:
        extra = Extra.forbid

    url: str
    description: Optional[str]
    variables: Optional[Dict[str, ServerVariable]]


class Schema(BaseModel):
    class Config:
        extra = Extra.forbid

    title: Optional[str]
    multipleOf: Annotated[Optional[float], Field(gt=0.0)]
    maximum: Optional[float]
    exclusiveMaximum: Optional[bool] = False
    minimum: Optional[float]
    exclusiveMinimum: Optional[bool] = False
    maxLength: Annotated[Optional[int], Field(ge=0)]
    minLength: Annotated[Optional[int], Field(ge=0)] = 0
    pattern: Optional[str]
    maxItems: Annotated[Optional[int], Field(ge=0)]
    minItems: Annotated[Optional[int], Field(ge=0)] = 0
    uniqueItems: Optional[bool] = False
    maxProperties: Annotated[Optional[int], Field(ge=0)]
    minProperties: Annotated[Optional[int], Field(ge=0)] = 0
    required: Annotated[Optional[List[str]], Field(min_items=1, unique_items=True)]
    enum: Annotated[Optional[List], Field(min_items=1, unique_items=False)]
    type: Optional[Type]
    not_: Annotated[Optional[Union[Schema, Reference]], Field(alias='not')]
    allOf: Optional[List[Union[Schema, Reference]]]
    oneOf: Optional[List[Union[Schema, Reference]]]
    anyOf: Optional[List[Union[Schema, Reference]]]
    items: Optional[Union[Schema, Reference]]
    properties: Optional[Dict[str, Union[Schema, Reference]]]
    additionalProperties: Optional[Union[Schema, Reference, bool]] = True
    description: Optional[str]
    format: Optional[str]
    default: Optional[Any]
    nullable: Optional[bool] = False
    discriminator: Optional[Discriminator]
    readOnly: Optional[bool] = False
    writeOnly: Optional[bool] = False
    example: Optional[Any]
    externalDocs: Optional[ExternalDocumentation]
    deprecated: Optional[bool] = False
    xml: Optional[XML]


class Tag(BaseModel):
    class Config:
        extra = Extra.forbid

    name: str
    description: Optional[str]
    externalDocs: Optional[ExternalDocumentation]


class OAuthFlows(BaseModel):
    class Config:
        extra = Extra.forbid

    implicit: Optional[ImplicitOAuthFlow]
    password: Optional[PasswordOAuthFlow]
    clientCredentials: Optional[ClientCredentialsFlow]
    authorizationCode: Optional[AuthorizationCodeOAuthFlow]


class Link(BaseModel):
    class Config:
        extra = Extra.forbid

    operationId: Optional[str]
    operationRef: Optional[str]
    parameters: Optional[Dict[str, Any]]
    requestBody: Optional[Any]
    description: Optional[str]
    server: Optional[Server]


class OAuth2SecurityScheme(BaseModel):
    class Config:
        extra = Extra.forbid

    type: Type3
    flows: OAuthFlows
    description: Optional[str]


class SecurityScheme(BaseModel):
    __root__: Union[
        APIKeySecurityScheme,
        HTTPSecurityScheme,
        OAuth2SecurityScheme,
        OpenIdConnectSecurityScheme,
    ]


def ref_to_path(ref: str) -> list[str]:
    return ref.split('/')[1:]


class OpenApiModel(BaseModel):
    """
    Validation schema for OpenAPI Specification 3.0.X.
    """

    class Config:
        extra = Extra.forbid

    openapi: Annotated[str, Field(regex='^3\\.0\\.\\d(-.+)?$')]
    info: Info
    externalDocs: Optional[ExternalDocumentation]
    servers: Optional[List[Server]]
    security: Optional[List[SecurityRequirement]]
    tags: Annotated[Optional[List[Tag]], Field(unique_items=True)]
    paths: Paths
    components: Optional[Components]

    def resolve(self, ref: str, t: Optional[type]) -> Any:
        result = self._schema_get(self.recursive_resolve(ref))
        if t is not None and not isinstance(result, t):
            raise TypeError(ref, t, type(result))
        else:
            return result

    def recursive_resolve(self, ref: str) -> str:
        """
        Resolve recursive references
        :return: The last reference, which points to a non-reference object
        """

        stack = []

        while True:
            model = self._schema_get(ref)
            if isinstance(model, Reference):
                ref = model.ref
                if ref in stack:
                    raise RecursionError(stack, ref)
                else:
                    stack.append(ref)
            else:
                return ref

    def _schema_get(self, ref: str) -> Any:
        model = self
        path = ref_to_path(ref)
        for part in path:
            model = model[part] if isinstance(model, Mapping) else getattr(model, part)
        return model


class Components(BaseModel):
    class Config:
        extra = Extra.forbid

    schemas: Optional[Dict[str, Union[Schema, Reference]]]
    responses: Optional[Dict[str, Union[Reference, Response]]]
    parameters: Optional[Dict[str, Union[Reference, Parameter]]]
    examples: Optional[Dict[str, Union[Reference, Example]]]
    requestBodies: Optional[Dict[str, Union[Reference, RequestBody]]]
    headers: Optional[Dict[str, Union[Reference, Header]]]
    securitySchemes: Optional[Dict[str, Union[Reference, SecurityScheme]]]
    links: Optional[Dict[str, Union[Reference, Link]]]
    callbacks: Optional[Dict[str, Union[Reference, Callback]]]


class Response(BaseModel):
    class Config:
        extra = Extra.forbid

    description: str
    headers: Optional[Dict[str, Union[Header, Reference]]]
    content: Optional[Dict[str, MediaType]]
    links: Optional[Dict[str, Union[Link, Reference]]]


class MediaType(BaseModel):
    class Config:
        extra = Extra.forbid

    schema_: Annotated[Optional[Union[Schema, Reference]], Field(alias='schema')]
    example: Optional[Any]
    examples: Optional[Dict[str, Union[Example, Reference]]]
    encoding: Optional[Dict[str, Encoding]]


class Header(BaseModel):
    class Config:
        extra = Extra.forbid

    description: Optional[str]
    required: Optional[bool] = False
    deprecated: Optional[bool] = False
    allowEmptyValue: Optional[bool] = False
    style: Optional[Style] = 'simple'
    explode: Optional[bool]
    allowReserved: Optional[bool] = False
    schema_: Annotated[Optional[Union[Schema, Reference]], Field(alias='schema')]
    content: Annotated[
        Optional[Dict[str, MediaType]], Field(maxProperties=1, minProperties=1)
    ]
    example: Optional[Any]
    examples: Optional[Dict[str, Union[Example, Reference]]]


class PathItem(BaseModel):
    class Config:
        extra = Extra.forbid

    summary: Optional[str]
    description: Optional[str]
    servers: Optional[List[Server]]
    parameters: Annotated[
        Optional[List[Union[Parameter, Reference]]], Field(unique_items=True)
    ]
    get: Optional[Operation]
    put: Optional[Operation]
    post: Optional[Operation]
    delete: Optional[Operation]
    options: Optional[Operation]
    head: Optional[Operation]
    patch: Optional[Operation]
    trace: Optional[Operation]


class Operation(BaseModel):
    class Config:
        extra = Extra.forbid

    tags: Optional[List[str]]
    summary: Optional[str]
    description: Optional[str]
    externalDocs: Optional[ExternalDocumentation]
    operationId: Optional[str]
    parameters: Annotated[
        Optional[List[Union[Parameter, Reference]]], Field(unique_items=True)
    ]
    requestBody: Optional[Union[RequestBody, Reference]]
    responses: Responses
    callbacks: Optional[Dict[str, Union[Callback, Reference]]]
    deprecated: Optional[bool] = False
    security: Optional[List[SecurityRequirement]]
    servers: Optional[List[Server]]


class Responses(BaseModel):
    __root__: Annotated[Optional[dict[str, Union[Response, Reference]]], Field(default_factory=dict)]


class Parameter(BaseModel):
    class Config:
        extra = Extra.forbid

    name: str
    in_: Annotated[str, Field(alias='in')]
    description: Optional[str]
    required: Optional[bool] = False
    deprecated: Optional[bool] = False
    allowEmptyValue: Optional[bool] = False
    style: Optional[str]
    explode: Optional[bool]
    allowReserved: Optional[bool] = False
    schema_: Annotated[Optional[Union[Schema, Reference]], Field(alias='schema')]
    content: Annotated[
        Optional[Dict[str, MediaType]], Field(maxProperties=1, minProperties=1)
    ]
    example: Optional[Any]
    examples: Optional[Dict[str, Union[Example, Reference]]]


class RequestBody(BaseModel):
    class Config:
        extra = Extra.forbid

    description: Optional[str]
    content: Dict[str, MediaType]
    required: Optional[bool] = False


class Encoding(BaseModel):
    class Config:
        extra = Extra.forbid

    contentType: Optional[str]
    headers: Optional[Dict[str, Header]]
    style: Optional[Style2]
    explode: Optional[bool]
    allowReserved: Optional[bool] = False


Schema.update_forward_refs()
OpenApiModel.update_forward_refs()
Components.update_forward_refs()
Response.update_forward_refs()
MediaType.update_forward_refs()
PathItem.update_forward_refs()
Operation.update_forward_refs()
Paths.update_forward_refs()
