from flask import jsonify
from flexmeasures.data.schemas.utils import FMValidationError
from webargs.multidictproxy import MultiDictProxy
from webargs import ValidationError
from webargs.flaskparser import parser

"""
Utils for argument parsing (we use webargs),
including error handling.
"""


@parser.error_handler
def handle_error(error, req, schema, *, error_status_code, error_headers):
    """Replacing webargs's error parser, so we can throw custom Exceptions."""
    if error.__class__ == ValidationError:
        # re-package all marshmallow's validation errors as our own kind (see below)
        raise FMValidationError(message=error.messages)
    raise error


def validation_error_handler(error: FMValidationError):
    """Handles errors during parsing.
    Aborts the current HTTP request and responds with a 422 error.
    FMValidationError attributes "result" and "status" are packaged in the response.
    """
    status_code = 422
    response_data = dict(message=error.messages)
    if hasattr(error, "result"):
        response_data["result"] = error.result
    if hasattr(error, "status"):
        response_data["status"] = error.status
    response = jsonify(response_data)
    response.status_code = status_code
    return response


@parser.location_loader("args_and_json")
def load_data(request, schema):
    """
    We allow parameters to come from either GET args or POST JSON,
    as validators can be attached to either.
    """
    newdata = request.args.copy()
    if request.mimetype == "application/json" and request.method == "POST":
        newdata.update(request.get_json())
    return MultiDictProxy(newdata, schema)
