"""
Copyright (c) 2014 Miguel Grinberg
Copyright (c) 2015 Alexandru Ciobanu
"""
from datetime import timedelta
import functools
from time import time
from threading import Thread
from werkzeug.wrappers import Response
from flask import jsonify, url_for, request, make_response, current_app
from flask import g, abort
from flask_login import current_user
from app.models import Permission


def json_response(f):
    """A decorator without arguments

    :param func f:
    :return:
    :rtype: func
    """

    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        current_app.log.warn('Using the json_response decorator is deprecated.'
                             'Please use app.core.ApiResponse.')
        # invoke the wrapped function
        rv = f(*args, **kwargs)
        # wrapped function is a redirect
        # return it without doing anything
        if isinstance(rv, Response):
            return rv

        # the wrapped function can return the dictionary alone,
        # or can also include a status code and/or headers.
        # here we separate all these items
        status_or_headers = None
        headers = None
        if isinstance(rv, tuple):
            rv, status_or_headers, headers = rv + (None, ) * (3 - len(rv))
        if isinstance(status_or_headers, (dict, list)):
            headers, status_or_headers = status_or_headers, None

        # if the response was a database model, then convert it to a
        # dictionary
        if not isinstance(rv, dict):
            rv = rv.serialize()

        # generate the JSON response
        rv = jsonify(rv)
        if status_or_headers is not None:
            rv.status_code = status_or_headers
        if headers is not None:
            rv.headers.extend(headers)
        return rv

    return wrapped


def paginate(f=None, *, max_per_page=20, headers_prefix='DO-'):
    """Pagination decorator.
    Generate a paginated response for a resource collection.
    Routes that use this decorator must return a SQLAlchemy query as a
    response.

    :param f: function to be decorated
    :param max_per_page: Items per page
    :param headers_prefix: Prefix for custom headers
    :return: tuple as (response, headers)
    """
    if f is None:
        return functools.partial(paginate,
                                 max_per_page=max_per_page,
                                 headers_prefix=headers_prefix)

    @functools.wraps(f)
    def wrapped(*args, **kwargs):
        page = request.args.get('page', 1, type=int)
        per_page = min(request.args.get('per_page', max_per_page,
                                        type=int), max_per_page)
        query = f(*args, **kwargs)
        p = query.paginate(page, per_page)
        rv = {'page': page, 'per_page': per_page, 'count': p.total}
        if p.has_prev:
            rv['prev'] = url_for(request.endpoint, page=p.prev_num,
                                 per_page=per_page,
                                 _external=True, **kwargs)
        else:
            rv['prev'] = None
        if p.has_next:
            rv['next'] = url_for(request.endpoint, page=p.next_num,
                                 per_page=per_page,
                                 _external=True, **kwargs)
        else:
            rv['next'] = None
        rv['first'] = url_for(request.endpoint, page=1,
                              per_page=per_page, _external=True,
                              **kwargs)
        rv['last'] = url_for(request.endpoint, page=p.pages,
                             per_page=per_page, _external=True,
                             **kwargs)
        rv['items'] = [item.serialize() for item in p.items]
        headers = {
            headers_prefix + 'Page-Current': page,
            headers_prefix + 'Page-Prev': rv['prev'],
            headers_prefix + 'Page-Next': rv['next'],