import jwt
import gzip

from functools import wraps
from flask import request, after_this_request, current_app, jsonify
from flask_jwt_extended import get_jwt_identity
from io import BytesIO as IO
from server.models import User


def check_confirmed(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        current_identity = get_jwt_identity()
        db_user = User.query.get(current_identity)
        if not db_user.confirmed:
            return (
                jsonify(
                    {
                        "message": "User not verified.",
                        "authenticated": False,
                        "confirmed": False,
                    }
                ),
                403,
            )
        return func(*args, **kwargs)

    return decorated_function


def token_required(f):
    @wraps(f)
    def _verify(*args, **kwargs):
        auth_headers = request.headers.get("Authorization", "").split()

        invalid_msg = {
            "message": "Invalid token. Authentication required.",
            "authenticated": False,
        }
        expired_msg = {
            "message": "Expired token. Re-authentication required.",
            "authenticated": False,
        }

        if len(auth_headers) != 2:
            return jsonify(invalid_msg), 401

        try:
            token = auth_headers[1]
            data = jwt.decode(token, current_app.config["SECRET_KEY"])
            user = User.query.filter_by(email=data["sub"]).first()
            if not user:
                raise RuntimeError("User not found")
            return f(user, *args, **kwargs)
        except jwt.ExpiredSignatureError:
            return jsonify(expired_msg), 401
        except (jwt.InvalidTokenError, Exception) as e:
            print(e)
            return jsonify(invalid_msg), 401

    return _verify


def gzipped(f):
    @wraps(f)
    def view_func(*args, **kwargs):
        @after_this_request
        def zipper(response):
            accept_encoding = request.headers.get("Accept-Encoding", "")

            if "gzip" not in accept_encoding.lower():
                return response

            response.direct_passthrough = False

            if (
                response.status_code < 200
                or response.status_code >= 300
                or "Content-Encoding" in response.headers
            ):
                return response
            gzip_buffer = IO()
            gzip_file = gzip.GzipFile(mode="wb", fileobj=gzip_buffer)
            gzip_file.write(response.data)
            gzip_file.close()

            response.data = gzip_buffer.getvalue()
            response.headers["Content-Encoding"] = "gzip"
            response.headers["Vary"] = "Accept-Encoding"
            response.headers["Content-Length"] = len(response.data)

            return response

        return f(*args, **kwargs)

    return view_func

import jwt
import gzip

from functools import wraps
from flask import request, after_this_request, current_app, jsonify
from flask_jwt_extended import get_jwt_identity
from io import BytesIO as IO
from server.models import User


def check_confirmed(func):
    @wraps(func)
    def decorated_function(*args, **kwargs):
        current_identity = get_jwt_identity()
        db_user = User.query.get(current_identity)
        if not db_user.confirmed:
            return (
                jsonify(
                    {
                        "message": "User not verified.",
                        "authenticated": False,
                        "confirmed": False,
                    }
                ),
                403,
            )
        return func(*args, **kwargs)

    return decorated_function


def token_required(f):
    @wraps(f)
    def _verify(*args, **kwargs):
        auth_headers = request.headers.get("Authorization", "").split()

        invalid_msg = {
            "message": "Invalid token. Authentication required.",
            "authenticated": False,
        }
        expired_msg = {
            "message": "Expired token. Re-authentication required.",
            "authenticated": False,
        }

        if len(auth_headers) != 2:
            return jsonify(invalid_msg), 401

        try:
            token = auth_headers[1]
            data = jwt.decode(token, current_app.config["SECRET_KEY"])
            user = User.query.filter_by(email=data["sub"]).first()
            if not user:
                raise RuntimeError("User not found")
            return f(user, *args, **kwargs)
        except jwt.ExpiredSignatureError:
            return jsonify(expired_msg), 401
        except (jwt.InvalidTokenError, Exception) as e:
            print(e)
            return jsonify(invalid_msg), 401

    return _verify


def gzipped(f):
    @wraps(f)
    def view_func(*args, **kwargs):
        @after_this_request
        def zipper(response):
            accept_encoding = request.headers.get("Accept-Encoding", "")

            if "gzip" not in accept_encoding.lower():
                return response

            response.direct_passthrough = False

            if (
                response.status_code < 200
                or response.status_code >= 300
                or "Content-Encoding" in response.headers
            ):
                return response
            gzip_buffer = IO()
            gzip_file = gzip.GzipFile(mode="wb", fileobj=gzip_buffer)
            gzip_file.write(response.data)
            gzip_file.close()

            response.data = gzip_buffer.getvalue()
            response.headers["Content-Encoding"] = "gzip"
            response.headers["Vary"] = "Accept-Encoding"
            response.headers["Content-Length"] = len(response.data)

            return response

        return f(*args, **kwargs)

    return view_func
