#
# Copyright (c) 2021 Nitric Technologies Pty Ltd.
#
# This file is part of Nitric Python 3 SDK.
# See https://github.com/nitrictech/python-sdk for further info.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: nitric/proto/apis/v1/apis.proto
# plugin: python-betterproto
# This file has been @generated

from dataclasses import dataclass
from typing import (
    TYPE_CHECKING,
    AsyncIterable,
    AsyncIterator,
    Dict,
    Iterable,
    List,
    Optional,
    Union,
)

import betterproto
import grpclib
from betterproto.grpc.grpclib_server import ServiceBase


if TYPE_CHECKING:
    import grpclib.server
    from betterproto.grpc.grpclib_client import MetadataLike
    from grpclib.metadata import Deadline


@dataclass(eq=False, repr=False)
class ApiDetailsRequest(betterproto.Message):
    api_name: str = betterproto.string_field(1)


@dataclass(eq=False, repr=False)
class ApiDetailsResponse(betterproto.Message):
    url: str = betterproto.string_field(1)


@dataclass(eq=False, repr=False)
class ClientMessage(betterproto.Message):
    """ClientMessage sent by the service to the nitric server"""

    id: str = betterproto.string_field(1)
    """globally unique ID of the request/response pair"""

    registration_request: "RegistrationRequest" = betterproto.message_field(
        2, group="content"
    )
    """Register an API route handler"""

    http_response: "HttpResponse" = betterproto.message_field(3, group="content")
    """Response to an HTTP request"""


@dataclass(eq=False, repr=False)
class HeaderValue(betterproto.Message):
    value: List[str] = betterproto.string_field(1)


@dataclass(eq=False, repr=False)
class QueryValue(betterproto.Message):
    value: List[str] = betterproto.string_field(1)


@dataclass(eq=False, repr=False)
class HttpRequest(betterproto.Message):
    method: str = betterproto.string_field(1)
    """The request method"""

    path: str = betterproto.string_field(2)
    """The path of the request"""

    headers: Dict[str, "HeaderValue"] = betterproto.map_field(
        3, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """HTTP request headers"""

    query_params: Dict[str, "QueryValue"] = betterproto.map_field(
        4, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """HTTP Query params"""

    path_params: Dict[str, str] = betterproto.map_field(
        5, betterproto.TYPE_STRING, betterproto.TYPE_STRING
    )
    """HTTP Path parameters"""

    body: bytes = betterproto.bytes_field(6)
    """HTTP Request body"""


@dataclass(eq=False, repr=False)
class HttpResponse(betterproto.Message):
    """HttpResponseMessage"""

    status: int = betterproto.int32_field(1)
    """The HTTP response status code"""

    headers: Dict[str, "HeaderValue"] = betterproto.map_field(
        2, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """HTTP response headers"""

    body: bytes = betterproto.bytes_field(3)
    """HTTP response body"""


@dataclass(eq=False, repr=False)
class ServerMessage(betterproto.Message):
    """ServerMessage sent by the nitric server to the service"""

    id: str = betterproto.string_field(1)
    """globally unique ID of the request/response pair"""

    registration_response: "RegistrationResponse" = betterproto.message_field(
        2, group="content"
    )
    """Response to an API serve request"""

    http_request: "HttpRequest" = betterproto.message_field(3, group="content")
    """HTTP request to be routed to the service (handler)"""


@dataclass(eq=False, repr=False)
class RegistrationResponse(betterproto.Message):
    pass


@dataclass(eq=False, repr=False)
class ApiWorkerScopes(betterproto.Message):
    scopes: List[str] = betterproto.string_field(1)


@dataclass(eq=False, repr=False)
class ApiWorkerOptions(betterproto.Message):
    security: Dict[str, "ApiWorkerScopes"] = betterproto.map_field(
        1, betterproto.TYPE_STRING, betterproto.TYPE_MESSAGE
    )
    """
    Apply security definitions to this operation This will be mapped to named
    ApiSecurityDefinitionResource(s)
    """

    security_disabled: bool = betterproto.bool_field(2)
    """
    explicitly disable security for this endpoint We need to do this as the
    default value of a repeated field is always empty so there is no way of
    knowing if security is explicitly disabled
    """


@dataclass(eq=False, repr=False)
class RegistrationRequest(betterproto.Message):
    api: str = betterproto.string_field(1)
    path: str = betterproto.string_field(2)
    methods: List[str] = betterproto.string_field(3)
    options: "ApiWorkerOptions" = betterproto.message_field(4)


class ApiStub(betterproto.ServiceStub):
    async def serve(
        self,
        client_message_iterator: Union[
            AsyncIterable["ClientMessage"], Iterable["ClientMessage"]
        ],
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> AsyncIterator["ServerMessage"]:
        async for response in self._stream_stream(
            "/nitric.proto.apis.v1.Api/Serve",
            client_message_iterator,
            ClientMessage,
            ServerMessage,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        ):
            yield response

    async def api_details(
        self,
        api_details_request: "ApiDetailsRequest",
        *,
        timeout: Optional[float] = None,
        deadline: Optional["Deadline"] = None,
        metadata: Optional["MetadataLike"] = None
    ) -> "ApiDetailsResponse":
        return await self._unary_unary(
            "/nitric.proto.apis.v1.Api/ApiDetails",
            api_details_request,
            ApiDetailsResponse,
            timeout=timeout,
            deadline=deadline,
            metadata=metadata,
        )


class ApiBase(ServiceBase):
    async def serve(
        self, client_message_iterator: AsyncIterator["ClientMessage"]
    ) -> AsyncIterator["ServerMessage"]:
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)
        yield ServerMessage()

    async def api_details(
        self, api_details_request: "ApiDetailsRequest"
    ) -> "ApiDetailsResponse":
        raise grpclib.GRPCError(grpclib.const.Status.UNIMPLEMENTED)

    async def __rpc_serve(
        self, stream: "grpclib.server.Stream[ClientMessage, ServerMessage]"
    ) -> None:
        request = stream.__aiter__()
        await self._call_rpc_handler_server_stream(
            self.serve,
            stream,
            request,
        )

    async def __rpc_api_details(
        self, stream: "grpclib.server.Stream[ApiDetailsRequest, ApiDetailsResponse]"
    ) -> None:
        request = await stream.recv_message()
        response = await self.api_details(request)
        await stream.send_message(response)

    def __mapping__(self) -> Dict[str, grpclib.const.Handler]:
        return {
            "/nitric.proto.apis.v1.Api/Serve": grpclib.const.Handler(
                self.__rpc_serve,
                grpclib.const.Cardinality.STREAM_STREAM,
                ClientMessage,
                ServerMessage,
            ),
            "/nitric.proto.apis.v1.Api/ApiDetails": grpclib.const.Handler(
                self.__rpc_api_details,
                grpclib.const.Cardinality.UNARY_UNARY,
                ApiDetailsRequest,
                ApiDetailsResponse,
            ),
        }
