from aiohttp.web import Request, Response, middleware
from marshmallow import ValidationError

from maps_adv.geosmb.scenarist.proto.errors_pb2 import Error

from ..exceptions import (
    CurrentCouponDuplicate,
    CurrentStatusDuplicate,
    SubscriptionAlreadyExists,
    UnknownSubscription,
)


def _dict_to_str(data: dict, separator=": ") -> str:
    return ", ".join(f"{field}{separator}{data[field]}" for field in sorted(data))


@middleware
async def handle_validation_errors(req: Request, handler) -> Response:
    try:
        return await handler(req)
    except ValidationError as exc:
        if isinstance(exc.messages, dict):
            description = _dict_to_str(exc.messages)
        else:
            description = ", ".join(sorted(exc.messages))

        error = Error(code=Error.VALIDATION_ERROR, description=description)
        return Response(status=400, body=error.SerializeToString())


@middleware
async def handle_data_manager_errors(req: Request, handler) -> Response:
    try:
        return await handler(req)
    except UnknownSubscription as e:
        error = Error(code=Error.UNKNOWN_SUBSCRIPTION, description=", ".join(e.args))
        return Response(status=404, body=error.SerializeToString())
    except SubscriptionAlreadyExists:
        return Response(
            status=409,
            body=Error(code=Error.SUBSCRIPTION_ALREADY_EXISTS).SerializeToString(),
        )
    except CurrentStatusDuplicate:
        return Response(
            status=400,
            body=Error(code=Error.CURRENT_STATUS_DUPLICATE).SerializeToString(),
        )
    except CurrentCouponDuplicate:
        return Response(
            status=400,
            body=Error(code=Error.CURRENT_COUPON_DUPLICATE).SerializeToString(),
        )
