from flask import Flask, Response, render_template, request, session, redirect, url_for
from flask_bcrypt import Bcrypt
import functools
import re
import Constants
from urllib.parse import urlparse
from scripts.scraping.scraper import scrape
from scripts.scraping.ai_scraping import run_ai_query 
from scripts.recipes.handle_recipes import recipe_exists, add_single_recipe, get_all_recipes, get_single_recipe, get_facets, delete_single_recipe, search_recipes, delete_multiple_recipes
from scripts.users.handle_users import user_exists, add_user, delete_single_user, update_user

app = Flask(__name__)
bcrypt = Bcrypt(app)
app.config["TEMPLATES_AUTO_RELOAD"] = True
app.secret_key = Constants.SECRET_KEY 

# Decorator function to check for username in session to protect routes
def login_required(func):
    @functools.wraps(func)
    def secure_function(*args, **kwargs):
        if "username" not in session:
            return redirect(url_for("login"))
        return func(*args, **kwargs)
    return secure_function

# Pages
@app.route("/home")
@login_required
def home_page():
    tags = get_facets(session["username"])
    all_recipes = get_all_recipes(session["username"])
    return render_template("/pages/home.html",recipes=all_recipes, facets=tags)

@app.route("/")
def landing_page():
    return render_template("/pages/landing.html")

@app.route("/recipe/<recipe_id>")
@login_required
def single_recipe_page(recipe_id):
    recipe_details = get_single_recipe(recipe_id)

    # If there are instruction sections, be sure to render correctly
    if "subInstructions" in recipe_details["instructions"][0]:
        new_instructions = [{"i": x["subInstructions"], "n": x["name"]} for x in recipe_details["instructions"]]
        recipe_details["instructions"] = new_instructions
        recipe_details["has_subsections"] = True

    return render_template("/pages/single-recipe.html", single_recipe=recipe_details)

@app.route("/login")
def login():
    return render_template("/pages/login.html")

@app.route("/signup")
def signup():
    return render_template("/pages/signup.html")

@app.route("/account")
def account():
    if "username" not in session:
        return redirect(url_for("login"))
    else:
        return render_template("/pages/account.html")
    
@app.route("/about")
def about():
    return render_template("/pages/about.html")

# API routes
@app.post("/recipes/add")
def add_recipe():
    req_data = request.form.to_dict()
    submitted_url = req_data["url"]
    if submitted_url == '':
        return "<span class='text-red-500'>No recipe supplied!</span>", 422

    does_recipe_exist = recipe_exists(session["username"], submitted_url)

    if does_recipe_exist:
        return "<span class='error'>Recipe already exists!</span>", 422
    else:
        response = scrape(submitted_url)

        if response["success"]:
            add_single_recipe(response["data"])
            all_recipes = get_all_recipes(session["username"])
            all_facets = get_facets(session["username"])
            return render_template("/components/app.html", recipes=all_recipes, facets=all_facets)

        elif not response["success"]:
            ai_res = run_ai_query(submitted_url)
            add_single_recipe(ai_res["data"])
            all_recipes = get_all_recipes(session["username"])
            all_facets = get_facets(session["username"])
            return render_template("/components/app.html", recipes=all_recipes, facets=all_facets)
        else:
            return "something went wrong", 400


@app.post("/recipes/search")
def search():
    req_data = request.form.to_dict()
    all_recipes = search_recipes(req_data, session["username"])
    all_facets = get_facets(session["username"], req_data)
    return render_template("/components/app.html", recipes=all_recipes, facets=all_facets)

@app.delete("/recipes/delete/<recipe_id>")
def delete_recipe(recipe_id):
    res = delete_single_recipe(recipe_id)
    if res["success"]:
        return f'<p class="success">Recipe {recipe_id} successfully deleted, <a href="/home">Go home</a>'
    else:
        error_html = f'<p class="error">Error deleting {recipe_id}</p>'
        return  error_html

@app.post("/login")
def login_user():
    req_data = request.form.to_dict()
    user = req_data["username"]
    pw = req_data["password"]
    res = user_exists(user)
    if res["success"] and res["user"] is None:
        return "<p class='error'>User doesn't exist, <a href='/signup'>signup instead</a></p>"
    elif res["success"] and res["user"] is not None:
        pw_matches = bcrypt.check_password_hash(res["password"], pw)
        if pw_matches:
            session["username"] = user
            session["isAiSubscriber"] = res["isAiSubscriber"]
            return Response(headers={"HX-Redirect": "/home"})
        else:
            return "Incorrect password, try again"
    else:
        return "<p class='error'>Something went wrong with the login</p>"

@app.post("/signup")
def signup_user():
    req_data = request.form.to_dict()
    user = req_data.get("username")
    pw = req_data.get("password") 
    pw_confirm = req_data.get("password-confirm") 

    if user == "" or pw == "":
        return "<p class='error'>You must fill in both username and password</p>"
    
    if pw != pw_confirm:
        return "<p class='error'>Passwords do not match</p>"

    res = user_exists(user)
    if res["success"] and res["user"] is not None:
        return "<p class='error'>User already exists, <a href='/login'>Login instead</a></p>"
    elif res["success"] and res["user"] is None:
        pattern = r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$'
        is_strong = bool(re.match(pattern, pw))
        if is_strong:
            pw_hash = bcrypt.generate_password_hash(pw)
            res = add_user(user, pw_hash) 
            if res["success"]:
                session["username"] = user
                return Response(headers={"HX-Redirect": "/home"})
            else:
                return "<p class='error'>Something went wrong</p>"
        else:
            return "<p class='error'>Password must be at least 8 characters long and contain at least 1 digit and 1 number</p>"

@app.post("/logout")
def logout_user():
    session.pop('username', None)    
    return Response(headers={"HX-Redirect": "/"})

@app.delete("/delete-account")
def delete_user():
    delete_user_res = delete_single_user(session["username"])
    delete_recipes_res = delete_multiple_recipes(session["username"]) 
    if delete_user_res["success"] and delete_recipes_res["success"]:
        session.pop("username", None)
        return Response(headers={"HX-Redirect": "/"})
    else:
        return "Something went wrong deleting the user and recipes"

@app.post("/update-account")
def update_account():
    user_prefs = request.form.to_dict()
    response = update_user(session["username"], user_prefs)

    if response["success"]:
        session["isAiSubscriber"] = True
        return Response(headers={"HX-Redirect": "/account"})
    else:
        return f"<span class='error'>{response['message']}</span>", 422

    
if __name__ == "__main__":
    app.run(host="0.0.0.0")