from typing import Dict, List

from marshmallow import fields, validate

from maps_adv.common.protomallow import ProtobufSchema
from maps_adv.manul.lib.data_managers import ClientsDataManager
from maps_adv.manul.proto import clients_pb2

from .schema_utils import with_schemas


class ClientInputSchema(ProtobufSchema):
    class Meta:
        pb_message_class = clients_pb2.ClientInput

    name = fields.String(validate=validate.Length(min=1, max=256))
    account_manager_id = fields.Integer(required=False)


class ClientSetAccountManagerSchema(ProtobufSchema):
    class Meta:
        pb_message_class = clients_pb2.ClientSetAccountManagerInput

    client_id = fields.Integer()
    account_manager_id = fields.Integer()


class ClientOutputSchema(ProtobufSchema):
    class Meta:
        pb_message_class = clients_pb2.ClientOutput

    id = fields.Integer()
    name = fields.String(validate=validate.Length(min=1, max=256))
    orders_count = fields.Integer()
    account_manager_id = fields.Integer(required=False)


class ClientsListSchema(ProtobufSchema):
    class Meta:
        pb_message_class = clients_pb2.ClientsList

    clients = fields.List(fields.Nested(ClientOutputSchema))


class ClientsApiProvider:
    __slots__ = ("_dm",)

    _dm: ClientsDataManager

    def __init__(self, dm: ClientsDataManager):
        self._dm = dm

    @with_schemas(ClientInputSchema, ClientOutputSchema)
    async def create_client(self, **kwargs) -> dict:
        return await self._dm.create_client(**kwargs)

    @with_schemas(ClientInputSchema, ClientOutputSchema)
    async def update_client(self, **kwargs) -> dict:
        return await self._dm.update_client(**kwargs)

    @with_schemas(ClientSetAccountManagerSchema)
    async def set_account_manager_for_client(self, **kwargs) -> dict:
        await self._dm.set_account_manager_for_client(**kwargs)

    @with_schemas(output_schema=ClientOutputSchema)
    async def retrieve_client(self, **kwargs) -> dict:
        return await self._dm.retrieve_client(**kwargs)

    @with_schemas(output_schema=ClientsListSchema)
    async def list_clients(self) -> Dict[str, List[dict]]:
        got = await self._dm.list_clients()
        return {"clients": got}
