#code from Real Python 
#https://realpython.com/flask-google-login/

# Python standard libraries
import json
import os
import sqlite3
from datetime import timedelta

import requests

# Internal imports
#from app.db import init_db_command

# Third party libraries
from flask import Flask, redirect, request, url_for, session
from flask_login import (
    LoginManager,
    current_user,
    login_required,
    login_user,
    logout_user,
)
from oauthlib.oauth2 import WebApplicationClient


from FlaskApp.app.user import User
import FlaskApp.app.common as common
from FlaskApp.app import app 

if ('LOCAL' in app.config) and app.config['LOCAL']:
    file_prefix = './FlaskApp/'
else:
    file_prefix ='/home/gary/users_db/'
conn  =  sqlite3.connect(file_prefix + 'users.sqlite3', check_same_thread=False,timeout=20)
cursor = conn.cursor()
#sql_query = """SELECT name FROM sqlite_master  WHERE type='table';"""
#cursor.execute(sql_query)
#common.logger.debug(str(cursor.fetchall()))

#app = app.create_app()

# Configuration
GOOGLE_CLIENT_ID = common.access_secret_version('global_parameters',None,'google_client_id')
GOOGLE_CLIENT_SECRET = common.access_secret_version('global_parameters',None,'google_client_secret')
GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration"
)

valid_users = common.access_secret_version('customer_parameters','aemery','dashboard_auth')

# Flask app setup
#app = Flask(__name__)
app.secret_key = os.urandom(24)

# User session management setup
# https://flask-login.readthedocs.io/en/latest
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.session_protection = 'strong'


@login_manager.unauthorized_handler
def unauthorized():
    #common.logger.debug('handler: ' + str(request.args) + str(request.path))
    #common.logger.debug('handler: ' + str(request.__dict__))
    session['next_url'] = request.path
    return redirect(url_for('login',next=request.endpoint))

'''
# Naive database setup
try:
    init_db_command()
except sqlite3.OperationalError:
    # Assume it's already been created
    pass
'''
# OAuth2 client setup
client = WebApplicationClient(GOOGLE_CLIENT_ID)


# Flask-Login helper to retrieve a user from our db
@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)


'''@app.route("/")
def index():
    if current_user.is_authenticated:
        return (
            "<p>Hello, {}! You're logged in! Email: {}</p>"
            "<div><p>Google Profile Picture:</p>"
            '<img src="{}" alt="Google profile pic"></img></div>'
            '<a class="button" href="/logout">Logout</a>'.format(
                current_user.name, current_user.email, current_user.profile_pic
            )
        )
    else:
        return '<a class="button" href="/login">Google Login</a>'
'''

@app.route("/login")
def login():
    # Find out what URL to hit for Google login
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]
    #common.logger.debug('login: ' + str(request.args) + str(request.path))
    #common.logger.debug('login 2: ' + str(request.__dict__))
    
    #session['next_url'] = request.path

    #common.logger.debug(request.base_url + "/callback")
    # Use library to construct the request for login and provide
    # scopes that let you retrieve user's profile from Google
    request_uri = client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri=request.base_url + "/callback",
        scope=["openid", "email", "profile"],
    )
    return redirect(request_uri)


@app.route("/login/callback")
def callback():
    # Get authorization code Google sent back to you
    #common.logger.debug('callback: ' + str(request.args))
    code = request.args.get("code")

    # Find out what URL to hit to get tokens that allow you to ask for
    # things on behalf of a user
    google_provider_cfg = get_google_provider_cfg()
    token_endpoint = google_provider_cfg["token_endpoint"]

    # Prepare and send request to get tokens! Yay tokens!
    token_url, headers, body = client.prepare_token_request(
        token_endpoint,
        authorization_response=request.url,
        redirect_url=request.base_url,
        code=code,
    )
    token_response = requests.post(
        token_url,
        headers=headers,
        data=body,
        auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
    )

    # Parse the tokens!
    client.parse_request_body_response(json.dumps(token_response.json()))

    # Now that we have tokens (yay) let's find and hit URL
    # from Google that gives you user's profile information,
    # including their Google Profile Image and Email
    userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
    uri, headers, body = client.add_token(userinfo_endpoint)
    userinfo_response = requests.get(uri, headers=headers, data=body)

    # We want to make sure their email is verified.
    # The user authenticated with Google, authorized our
    # app, and now we've verified their email through Google!
    if userinfo_response.json().get("email_verified"):
        unique_id = userinfo_response.json()["sub"]
        users_email = userinfo_response.json()["email"]
        picture = userinfo_response.json()["picture"]
        users_name = userinfo_response.json()["given_name"]
        #common.logger.debug(users_email + '\n' + str(list(valid_users.values())))
        if not users_email in list(valid_users.values()):
            return "User not authorised", 401
    else:
        return "User email not available or not verified by Google.", 401

    # Create a user in our db with the information provided
    # by Google
    user = User(
        id_=unique_id, name=users_name, email=users_email, profile_pic=picture
    )

    # Doesn't exist? Add to database
    if not User.get(unique_id):
        User.create(unique_id, users_name, users_email, picture)

    # Begin user session by logging the user in
    login_user(user,remember=True,duration=timedelta(days=1))

    #common.logger.debug(str(session))
    if 'next_url' in session:
        if session['next_url']:
            url = session['next_url']
            session['next_url'] = None
            #common.logger.debug(str(session))
            if url != '/login':
               return redirect(url)

    return redirect_dest(url_for('/dashboard/'))

def redirect_dest(fallback):
    #common.logger.debug('redirect: ' + str(request.args) + str(request.path))
    #common.logger.debug('redirect 2: ' + str(request.__dict__))
    dest = request.args.get('next')
    #common.logger.debug('dest: ' + str(dest))
    try:
        dest_url = url_for(dest)
    except:
        #common.logger.debug('fall back url used')
        return redirect(fallback)
    return redirect(dest_url)

@app.route("/logout")
@login_required
def logout():
    logout_user()
    #session['next_url'] = request.path
    #common.logger.debug('User logged out')
    return 'Logged out<br><br><a class="button" href="/login">Please feel free to Login again</a>'

@app.route('/user')
@login_required
def user():
    #session['next_url'] = request.__dict__['url']
    return 'You are logged in as {0}'.format(current_user.email)

def get_google_provider_cfg():
    return requests.get(GOOGLE_DISCOVERY_URL).json()

