""" The user controller to manage all of the user related endpoints
    in the web app
"""
from flask import Blueprint

from flask import render_template, redirect, request, session, flash, url_for
from controllers.database.user import UserController
from models.users.customer import Customer
from models.users.seller import Seller
from models.users.user import User
from utils.user_utils import is_role
from hashlib import sha512

# Blueprint to append user endpoints to
blueprint = Blueprint("users", __name__, url_prefix="/users")

ROLES = [
    "Customer",
    "Seller",
    "Admin"
]


@blueprint.context_processor
def roles_list():
    """ Places a list of all the available roles in the
        users context
    """
    return dict(roles=ROLES)


# LOGIN FUNCTIONALITY
@blueprint.route('/login')
def display_login():
    """ Function responsible for delivering the Login page for the site """
    return render_template('index.html', content="login.html")


@blueprint.post('/login')
def login():
    """ Function to handle the backend processing of a login request """
    database = UserController()
    user = database.read(request.form['username'])
    error = None

    # No user found
    if user is None:
        error = "No user found with the username " + request.form['username']
        flash(error, 'warning')
        return redirect(url_for('main.users.login'))

    # Incorrect Password
    if sha512(request.form['password'].encode()).hexdigest() != user.password:
        error = "Incorrect Password"
        flash(error, 'warning')
        return redirect(url_for('main.users.login'))

    session['user_id'] = user.id
    return redirect(url_for('main.index'))


# SIGNUP FUNCTIONALITY
@blueprint.route('/update/<int:id>')
def display_update(id: int):
    """ Function responsible for delivering the Update User page
        for the site
    """
    db = UserController()
    user = db.read_id(id)

    return render_template(
        'index.html',
        content="user.html",
        updating_user=user
    )


@blueprint.post('/update/<int:id>')
def update(id: int):
    """ Function to handle the backend processing of a signup request """
    if not is_role("Admin"):
        flash("You must be logged in an admin to update users!", "error")
        return redirect(url_for('main.index'))

    user = User(
        request.form['username'],
        "",  # Password
        request.form['firstname'],
        request.form['lastname'],
        request.form['email'],
        request.form['phone'],
        request.form['role'],
    )

    user.id = id

    db = UserController()
    checking_user = db.read(user.username)

    # User with this new username is already taken
    if checking_user is not None and checking_user.id != user.id:
        flash(
            f"User with the username {user.username} already exists!",
            "warning"
        )
        return redirect(url_for('main.users.display_update', id=id))

    # Invalid role submitted
    if user.role not in ROLES:
        flash(
            f"Selected role, {user.role}, is not valid!",
            "warning"
        )
        return redirect(url_for('main.users.display_update', id=id))

    db.update(user)

    return redirect(url_for('main.admin.users'))


# SIGN OUT FUNCTIONALITY
@blueprint.route('/logout')
def logout():
    """ Function responsible for handling logouts from the site """
    # Clear the current user from the session if they are logged in
    session.pop('user_id', None)
    return redirect(url_for('main.index'))


# SIGNUP FUNCTIONALITY
@blueprint.route('/signup')
def display_signup():
    """ Function responsible for delivering the Signup page for the site """
    return render_template('index.html', content="signup.html")


@blueprint.post('/signup')
def signup():
    """ Function to handle the backend processing of a signup request """
    database = UserController()

    # User already exists
    if database.read(request.form['username']) is not None:
        error = "User, " + request.form['username'] + " already exists"
        flash(error, 'warning')
        return redirect(url_for('main.users.signup'))

    # Signup as Seller or Customer
    if request.form.get('seller'):
        user = Seller(
            request.form['username'],
            # Hashed as soon as it is recieved on the backend
            sha512(request.form['password'].encode()).hexdigest(),
            request.form['firstname'],
            request.form['lastname'],
            request.form['email'],
            "123"
        )
    else:
        user = Customer(
            request.form['username'],
            # Hashed as soon as it is recieved on the backend
            sha512(request.form['password'].encode()).hexdigest(),
            request.form['firstname'],
            request.form['lastname'],
            request.form['email'],
            "123"
        )

    database.create(user)
    # Code 307 Preserves the original request (POST)
    return redirect(url_for('main.users.login'), code=307)


# DELETE USER FUNCTIONALITY
@blueprint.post('/delete/<int:id>')
def delete(id: int):
    """ Function responsible for deleting users from the site """
    if not is_role("Admin"):
        flash("You must be logged in an admin to remove users!", "error")
        return redirect(url_for('main.index'))

    db = UserController()
    db.delete(id)
    return redirect(url_for('main.admin.users'))
