from app import app
from flask import render_template, request, jsonify, g, make_response
from app.models import User

# Using JWT
import jwt
from flask import _request_ctx_stack
from functools import wraps
import datetime

# Create a JWT @requires_auth decorator
# This decorator can be used to denote that a specific route should check
# for a valid JWT token before displaying the contents of that route.
def requires_auth(f):
  @wraps(f)
  def decorated(*args, **kwargs):
    auth = request.headers.get('Authorization', None) # or request.cookies.get('token', None) 

    if not auth:
      return jsonify({'code': 'authorization_header_missing', 'description': 'Authorization header is expected'}), 401

    parts = auth.split()

    if parts[0].lower() != 'bearer':
      return jsonify({'code': 'invalid_header', 'description': 'Authorization header must start with Bearer'}), 401
    elif len(parts) == 1:
      return jsonify({'code': 'invalid_header', 'description': 'Token not found'}), 401
    elif len(parts) > 2:
      return jsonify({'code': 'invalid_header', 'description': 'Authorization header must be Bearer + \s + token'}), 401

    token = parts[1]
    try:
        payload = jwt.decode(token, app.config['SECRET_KEY'], algorithms=["HS256"])

    except jwt.ExpiredSignatureError:
        return jsonify({'code': 'token_expired', 'description': 'token is expired'}), 401
    except jwt.DecodeError:
        return jsonify({'code': 'token_invalid_signature', 'description': 'Token signature is invalid'}), 401

    g.current_user = user = payload
    return f(*args, **kwargs)

  return decorated


###
# Routing for your application.
###

@app.route('/')
def home():
    """Render website's home page."""
    return render_template('home.html')


@app.route('/demo')
def demo():
    # This loads a static HTML file where we then hand over the interaction
    # to VueJS
    return app.send_static_file('partials/index.html')


# This route requires a JWT in order to work. Note the @reques_auth
@app.route('/api/secure', methods=['GET'])
@requires_auth
def api_secure():
    # This data was retrieved from the payload of the JSON Web Token
    # take a look at the requires_auth decorator code to see how we decoded
    # the information from the JWT.
    user = g.current_user
    return jsonify(data={"user": user}, message="Success")


# This route doesn't require a JWT
@app.route('/api/unsecure', methods=['GET'])
def api_unsecure():
    user = {"name": "Mr. Anonymous Unsecure"}
    return jsonify(data={"user": user}, message="Success")


# This route is just used to demonstrate a JWT being generated.
@app.route('/token')
def generate_token():
    # Under normal circumstances you would generate this token when a user
    # logs into your web application and you send it back to the frontend
    # where it can be stored in localStorage for any subsequent API requests.
    payload = {
        'sub': '12345', # subject, usually a unique identifier
        'name': 'John Doe',
        'iat': datetime.datetime.now(datetime.timezone.utc), # issued at time
        'exp': datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=2) # expiration time
    }
    token = jwt.encode(payload, app.config['SECRET_KEY'], algorithm='HS256')

    return jsonify(error=None, data={'token': token}, message="Token Generated")

    # If you wanted to store the token in a cookie
    # resp = make_response(jsonify(error=None, data={'token': token}, message="Token Generated"))
    # resp.set_cookie('token', "Bearer " + token, httponly=True, secure=True)
    # return resp


@app.route('/api/tasks')
@requires_auth
def tasks():
    tasks = [
        {
            'id': 1,
            'title': 'Teach class'
        },
        {
            'id': 2,
            'title': 'Eat Lunch'
        },
        {
            'id': 3,
            'title': 'Build the next great web app!'
        }
    ]
    return jsonify(error=None, tasks=tasks)

###
# The functions below should be applicable to all Flask apps.
###


@app.route('/<file_name>.txt')
def send_text_file(file_name):
    """Send your static text file."""
    file_dot_text = file_name + '.txt'
    return app.send_static_file(file_dot_text)


@app.after_request
def add_header(response):
    """
    Add headers to both force latest IE rendering engine or Chrome Frame,
    and also to tell browser not to cache the rendered page.
    """
    response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1'
    response.headers['Cache-Control'] = 'public, max-age=0'
    return response


@app.errorhandler(404)
def page_not_found(error):
    """Custom 404 page."""
    return render_template('404.html'), 404


if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port="8080")
