# coding=utf-8
""""""
from __future__ import absolute_import, division, print_function, \
    unicode_literals

from flask import current_app, flash, request
from flask.signals import request_started
from flask_wtf.csrf import CsrfProtect
from markupsafe import Markup
from werkzeug.exceptions import BadRequest

from abilian.core.util import unwrap
from abilian.i18n import _l

wtf_csrf = CsrfProtect()


class AbilianCsrf(object):
    """CSRF error handler, that allows supporting views to gracefully report
    error instead of a plain 400 error.

    views supporting this must
    """

    #: for views that gracefully support csrf errors, this message can be
    #: displayed to user. It can be changed if you have a better one for your
    #: users.
    csrf_failed_message = _l(
        "Security informations are missing or expired. "
        "This may happen if you have opened the form for a long time. "
        "<br /><br />"
        "Please try to resubmit the form."
    )

    def init_app(self, app):
        if "csrf" not in app.extensions:
            raise RuntimeError(
                'Please install flask_wtf.csrf.CsrfProtect() as "csrf" in '
                "extensions before AbilianCsrf()"
            )
        app.extensions["csrf"].error_handler(self.csrf_error_handler)
        app.extensions["csrf-handler"] = self
        request_started.connect(self.request_started, sender=app)
        app.before_request(self.before_request)

    def flash_csrf_failed_message(self):
        flash(Markup(self.csrf_failed_message), "error")

    def request_started(self, app):
        request.csrf_failed = False

    def csrf_error_handler(self, reason):
        request.csrf_failed = reason

    def before_request(self):
        req = unwrap(request)
        failed = req.csrf_failed

        if not failed:
            return

        rule = req.url_rule
        view = current_app.view_functions[rule.endpoint]
        if getattr(view, "csrf_support_graceful_failure", False):
            # view can handle it nicely for the user
            return None

        if hasattr(view, "view_class") and getattr(
            view.view_class, "csrf_support_graceful_failure", False
        ):
            return None

        raise BadRequest(failed)


abilian_csrf = AbilianCsrf()
