from app import app, db, models, login_manager, oauth
from app.forms.app_forms import UserSignUp, UserLogIn
from flask import render_template, flash, url_for, redirect, request
from app.misc_func import flash_errors, send, send_async
import flask_login
from sqlalchemy.exc import IntegrityError
from itsdangerous.url_safe import URLSafeSerializer
from itsdangerous.exc import BadSignature

ts = URLSafeSerializer(app.config["SECRET_KEY"])


@app.route("/signup", methods=["GET", "POST"])
def register_user():
    if request.method == "GET" and flask_login.current_user.is_authenticated:
        return redirect(url_for("user_dashboard"))
    form = UserSignUp()
    if form.validate_on_submit():
        form.email.data = form.email.data.lower()
        user = models.User(
            first_name=form.first_name.data,
            last_name=form.last_name.data,
            email=form.email.data,
            confirmation=False,
            password=form.password.data,
        )
        db.session.add(user)
        try:
            db.session.commit()
        except IntegrityError:
            flash("Oops! An account with that email already exists")
            return render_template("auth/signup.html", form=form)

        subject = "Confirm Your Email"
        confirmation_token = ts.dumps(user.email, salt="email-confirm-key")
        confirmation_url = url_for(
            "confirm_email", confirmation_token=confirmation_token, _external=True
        )
        body_html = render_template(
            "misc/email_confirm.html", confirmation_url=confirmation_url
        )
        body = render_template(
            "misc/email_confirm.txt", confirmation_url=confirmation_url
        )
        send(user.email, subject, body, body_html)

        flash("Please confirm your email before signing in..")
        return redirect(url_for("signin_user"))

    flash_errors(form)
    return render_template("auth/signup.html", form=form)


@app.route("/signin", methods=["GET", "POST"])
def signin_user():
    if request.method == "GET" and flask_login.current_user.is_authenticated:
        return redirect(url_for("user_dashboard"))
    form = UserLogIn()
    if form.validate_on_submit():
        form.email.data = form.email.data.lower()
        user = models.User.query.filter_by(email=form.email.data).first()
        if user is not None:
            if user.login_type != "Normie":
                flash("Please Use Sign in With {}".format(user.login_type.title()))
            elif user.check_password(form.password.data):
                if user.confirmation:
                    flask_login.login_user(user)
                    return redirect(url_for("user_dashboard"))
                flash("Please Confirm Your Email First.")
            else:
                flash("Incorrect Password")
        else:
            flash("Incorrect Email")
    else:
        flash_errors(form)
    return render_template("auth/signin.html", form=form)


@app.route("/login/with/google")
def login_with_google():
    redirect_uri = url_for("login_with_google_auth", _external=True)
    return oauth.google.authorize_redirect(redirect_uri)


@app.route("/login/with/google/callback")
def login_with_google_auth():
    token = oauth.google.authorize_access_token()
    g_user = oauth.google.parse_id_token(token)
    print(g_user)
    if g_user["email_verified"]:
        user = models.User(
            first_name=g_user["given_name"],
            last_name=g_user["family_name"],
            email=g_user["email"].lower(),
            confirmation=True,
            login_type="google",
        )
        db.session.add(user)
        try:
            db.session.commit()
            flask_login.login_user(user)
            return redirect(url_for("user_dashboard"))
        except IntegrityError:
            db.session.rollback()
            user = models.User.query.filter_by(email=g_user["email"]).first()
            if user.login_type == "google":
                flask_login.login_user(user)
                return redirect(url_for("user_dashboard"))
            flash(
                "An account already exists for this email. Please use your password to log in."
            )
            return redirect(url_for("signin_user"))
    else:
        return render_template(
            "message.html",
            message="To use sign-in with Google, you need a verified e-mail.",
        )


@app.route("/confirm", methods=["GET", "POST"])
def confirm_email():
    confirmation_token = request.args.get("confirmation_token")
    try:
        email = ts.loads(confirmation_token, salt="email-confirm-key", max_age=86400)
    except TypeError:
        return render_template(
            "message.html", message="Token not provided in URL Parameter"
        )
    except BadSignature:
        return render_template("message.html", message="Bad Token Provided")
    user = models.User.query.filter_by(email=email).first()
    print(email)
    user.confirmation = True
    db.session.commit()
    flash("Email Has Been Succesfully Verified, You May Log In")
    return redirect(url_for("signin_user"))


@app.route("/dashboard")
@flask_login.login_required
def user_dashboard():
    return render_template("dashboard.html", user=flask_login.current_user)


@app.route("/logout")
def logout():
    flask_login.logout_user()
    return render_template("message.html", message="You have been logged out.")


@login_manager.unauthorized_handler
def unauthorized():
    return (
        render_template(
            "message.html",
            message="You need to be logged in to access this resource",
            code=401,
        ),
        401,
    )