"""This module contains api preprocessors and the api configuration."""
from flask_restless import ProcessingException
from flask_login import current_user

from server.forms import RegistrationForm
from server.models import User, Keyword, Category, Event
from server.models.event import event_serializer
from server.logger import logger, logging


def log_post(data):
    """Log data of a POST."""
    logger.log(logging.INFO, data)


def created_by(data):
    """Add current user username to POST data."""
    data['created_by'] = [current_user.username]


def make_non_admin(data):
    """Ensure all users created through registration are non admin."""
    data['is_admin'] = False


def only_admin_can_approve(instance_id: int, data, **kwargs):
    """Ensure only admin users can approve events."""
    if 'is_approved' in data and current_user.is_admin is False:
        raise ProcessingException('Only admins can approve events')


def owner_or_admin_required(instance_id: int, data, **kwargs):
    """Ensure only an event owner or an admin can update an event."""
    if (
        not current_user.owns_event_with_id(instance_id) and
        not current_user.is_admin
    ):
        raise ProcessingException(
            'Only event owners or admins can update this event')


def approved_preprocessor(data):
    """Ensure that events are entered as not approved."""
    data['is_approved'] = current_user.is_admin


def event_owned_by_current_user(instance_id: int):
    """Preprocessor for api event DELETE endpoint.

    Ensures event can only be deleted by a user with role 'owner'

    :param instance_id: id of instance to be deleted
    :raises ProcessingException: if current_user is not an owner of the event
    :return:None
    :rtype: None
    """
    event = Event.query.filter_by(id=instance_id).first()
    owners = event.get_owners()
    if current_user not in owners:
        raise ProcessingException('Only event owners can delete events')


def validate_with_form(form_class):
    """Wrapper for form validating preprocessor."""
    def preprocessor(data=None):
        form = form_class.from_json(data)
        if not form.validate():
            raise ProcessingException

    return preprocessor


def remove_props(props):
    """Wrapper for preprocessor which removes specified props."""
    def preprocessor(data=None):
        for prop in props:
            del data[prop]

    return preprocessor


def login_required_preprocessor(*args, **kwargs):
    """Ensure user is logged in via preprocessor."""
    if not current_user.is_authenticated():
        raise ProcessingException(
            description='Not Authorized',
            code=401
        )
    return True


api_config = [
    {
        'model': User,
        'methods': ['GET', 'POST', 'DELETE'],
        'preprocessors': {
            'POST': [
                make_non_admin,
                validate_with_form(RegistrationForm),
                remove_props(['confirm'])
            ],
        }
    },
    {
        'model': Keyword,
        'methods': ['GET', 'POST', 'DELETE'],
        'preprocessors': {
            'POST': [login_required_preprocessor],
            'DELETE': [login_required_preprocessor]
        }
    },
    {
        'model': Category,
        'methods': ['GET', 'POST', 'DELETE'],
        'preprocessors': {
            'POST': [login_required_preprocessor],

        }
    },
    {
        'model': Event,
        'methods': ['GET', 'POST', 'DELETE', 'PATCH'],
        'serializer': event_serializer,
        'preprocessors': {
            'PATCH_SINGLE': [
                owner_or_admin_required,
                only_admin_can_approve
            ],
            'POST': [
                login_required_preprocessor,
                created_by,
                approved_preprocessor
            ],
            'DELETE': [
                login_required_preprocessor,
                event_owned_by_current_user
            ]

        },
        'include_columns': ['id',
                            'name',
                            'description',
                            'subtitle',
                            'start',
                            'end',
                            'created_by',
                            'keywords',
                            'categories',
                            'subscribed_users',
                            'address',
                            'address_name']
    }
]

@@ -265,86 +265,1116 @@
 ver.
-models.event import event_serializer%0Afrom server.logger import logger, logging
+logger import log%0A%0A%0Adef _add_is_current_user_subscribed(event):%0A    %22%22%22Add is_subscribed field to a single event dictionary.%22%22%22%0A    if current_user is None:%0A        return%0A    eid = event%5B%22id%22%5D%0A    event%5B%22is_subscribed%22%5D = current_user.is_subscribed_to_event(eid)%0A%0A%0Adef add_is_current_user_subscribed(result=None, **kwargs):%0A    %22%22%22Add is_subscribed field to GET event response.%22%22%22%0A    if result is None:%0A        return%0A    if %22objects%22 in result:%0A        for event in result%5B%22objects%22%5D:%0A            _add_is_current_user_subscribed(event)%0A    else:%0A        _add_is_current_user_subscribed(result)%0A%0A%0Adef _change_subscribed_list_to_count(event):%0A    %22%22%22Change the subscribed_users to a count for a singel event dict.%22%22%22%0A    event%5B%22subscribed_users%22%5D = len(event%5B%22subscribed_users%22%5D)%0A%0A%0Adef change_subscribed_list_to_count(result=None, **kwargs):%0A    %22%22%22Change the subscribed_list to a count.%22%22%22%0A    if result is None:%0A        return%0A    if %22objects%22 in result:%0A        for event in result%5B%22objects%22%5D:%0A            _change_subscribed_list_to_count(event)%0A    else:%0A        _change_subscribed_list_to_count(result)
 %0A%0A%0Ad
@@ -1433,30 +1433,9 @@
  log
-ger.log(logging.INFO, 
+(
 data
@@ -4496,48 +4496,8 @@
 '%5D,%0A
-        'serializer': event_serializer,%0A
     
@@ -4919,17 +4919,16 @@
       %5D%0A
-%0A
         

Implement postprocessors for event subscription related functions