from distutils.log import debug
from unicodedata import name

from fastapi import BackgroundTasks, HTTPException, Request, Response, status
from sqlalchemy.orm import Session

from models.ingredients import Ingredient
from models.recipeingredients import RecipeIngredient
from models.recipes import Recipe
from schemas.recipes import RecipeCreate, RecipeOut


def get_recipes(db: Session, current_user):

    # get recipes
    recipes = db.query(Recipe).filter(Recipe.owner_id == current_user.id).all()

    # generate recipeout response
    recipe_list = []

    for recipe in recipes:

        temp_contents = []

        if recipe.contents is None:
            recipe.contents = []
        for content in recipe.contents:
            ingredient_name = db.query(Ingredient).filter(
                Ingredient.id == content.ingredient_id).first()
            ingredient_name = ingredient_name.name
            item = {
                "quantity": content.quantity,
                "unit": content.unit,
                "ingredient": ingredient_name
            }
            temp_contents.append(item)

        temp_recipe = {
            "name": recipe.name,
            "note": recipe.note,
            "star": recipe.star,
            "contents": temp_contents,
            "id": recipe.id,
            "owner_id": recipe.owner_id,
            "created": recipe.created
        }
        recipe_list.append(temp_recipe)

    return recipe_list


def get_recipe(recipe_id: int, db: Session, current_user):

    # lookup recipe_id in the database
    recipe = db.query(Recipe).filter(Recipe.id == recipe_id,
                                     Recipe.owner_id == current_user.id).first()
    if not recipe:  # recipe not found
        raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
                            f"Failed to find recipe id '{recipe_id}' associated to your user account")

    # lookup RecipeIngredients in the database
    recipeingredients = db.query(RecipeIngredient).filter(
        RecipeIngredient.recipe_id == recipe_id).all()

    # generate recipeout response
    temp_contents = []
    if recipeingredients is None:
        recipeingredients = []
    for item in recipeingredients:  # enumerate contents and build json

        if item.ingredient_id:
            ingredient_name = db.query(Ingredient).filter(
                Ingredient.id == item.ingredient_id).first()
            ingredient_name = ingredient_name.name
            item = {
                "quantity": item.quantity,
                "unit": item.unit,
                "ingredient": ingredient_name
            }
            temp_contents.append(item)

    # build recipe with contents
    temp_recipe = {
        "name": recipe.name,
        "note": recipe.note,
        "star": recipe.star,
        "contents": temp_contents,
        "id": recipe.id,
        "owner_id": recipe.owner_id,
        "created": recipe.created
    }

    return temp_recipe


def update_recipe(recipe_id: int, recipe_details: RecipeCreate, db: Session, current_user):

    # lookup recipe_id in the database
    recipe = db.query(Recipe).filter(Recipe.id == recipe_id,
                                     Recipe.owner_id == current_user.id).first()
    if not recipe:  # recipe not found
        raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
                            f"Failed to find recipe id '{recipe_id}' associated to your user account")

    # normalize recipe_details
    try:
        recipe_details.name = recipe_details.name.strip().lower()
        recipe_details.note = recipe_details.note.strip().lower()
    except:
        pass

    # update the recipe in the database
    recipe.name = recipe_details.name
    recipe.note = recipe_details.note
    recipe.star = recipe_details.star
    db.add(recipe)
    db.commit()

    # lookup recipeingredients in the database
    recipeingredients = db.query(RecipeIngredient).filter(
        RecipeIngredient.recipe_id == recipe_id).all()
    if recipeingredients:  # recipeingredients found
        for item in recipeingredients:  # delete recipeingredients from the database where recipe_id = recipe_id
            db.delete(item)
            db.commit()
            db.flush

    # create a new recipeingredient in the database
    if recipe_details.contents is None:
        recipe_details.contents = []  # no recipe contents
    for item in recipe_details.contents:  # enumerate though List of recipeingredient
        try:  # normalize recipe contents
            ingredient = None
            ingredient = item.ingredient.strip().lower()

            quantity = None
            quantity = item.quantity.strip().lower()

            unit = None
            unit = item.unit.strip().lower()
        except Exception as msg:  # failure
            pass

        # create a new ingredient in the database if it doesn't exist
        if ingredient:

            try:    # lookup ingredient in the database
                ingredient_id = ''
                if ingredient.isdigit():    # by id
                    ingredient_id = db.query(Ingredient).filter(
                        Ingredient.id == ingredient).first()
                    ingredient_id = ingredient_id.id

                    if ingredient_id is None:  # failure
                        raise HTTPException(
                            status.HTTP_400_BAD_REQUEST, "Ingredient id doesn't exist.")
                else:                       # by name
                    ingredient_id = db.query(Ingredient).filter(
                        Ingredient.name == ingredient).first()
                    ingredient_id = ingredient_id.id
            except:  # ingredient not found by id or name in the database
                try:  # create a new ingredient in the database
                    db_ingredient = Ingredient(
                        name=ingredient)
                    db.add(db_ingredient)
                    db.commit()
                    db.refresh(db_ingredient)
                    ingredient_id = db_ingredient
                    ingredient_id = ingredient_id.id
                except Exception as msg:  # failure
                    print(f"Failed to create ingredient '{name}': {msg}")
                    raise HTTPException(
                        status.HTTP_500_INTERNAL_SERVER_ERROR, f"Failed to create ingredient '{name}'")

            try:  # create a new recipeingredient in the database
                db_recipeingredient = RecipeIngredient(
                    recipe_id=recipe_id,
                    quantity=quantity,
                    unit=unit,
                    ingredient_id=ingredient_id)
                db.add(db_recipeingredient)
                db.commit()
                db.refresh(db_recipeingredient)
            except Exception as msg:  # failure
                print(f"Failed to create recipeingredient: {msg}")
                raise HTTPException(
                    status_code=500, detail="Failed to create recipeingredient")

    # get updated recipe
    recipe = db.query(Recipe).filter(Recipe.id == recipe_id).first()

    # generate recipeout response
    temp_contents = []
    if recipe_details.contents is None:
        recipe_details.contents = []
    for item in recipe_details.contents:  # enumerate contents and build json

        if item.ingredient:
            item = {
                "quantity": item.quantity,
                "unit": item.unit,
                "ingredient": ingredient
            }
            temp_contents.append(item)

    # build recipe with contents
    temp_recipe = {
        "name": recipe.name,
        "note": recipe.note,
        "star": recipe.star,
        "contents": temp_contents,
        "id": recipe_id,
        "owner_id": recipe.owner_id,
        "created": recipe.created
    }

    return temp_recipe


def create_recipe(recipe_details: RecipeCreate, db: Session, current_user):

    # ormalize recipe_details
    try:
        recipe_details.name = recipe_details.name.strip().lower()
        recipe_details.note = recipe_details.note.strip().lower()
    except:
        pass

    # create a new recipe in the database
    try:
        db_recipe = Recipe(
            name=recipe_details.name,
            note=recipe_details.note,
            star=recipe_details.star,
            owner_id=current_user.id)
        db.add(db_recipe)
        db.commit()
        db.refresh(db_recipe)
    except Exception as msg:  # failure
        print(f"Failed to create recipe '{name}': {msg}")
        raise HTTPException(
            status.HTTP_500_INTERNAL_SERVER_ERROR, f"Failed to create recipe '{name}'")

    # loop through Recipe.contents
    if recipe_details.contents is None:
        recipe_details.contents = []  # no recipe_details.contents
    for item in recipe_details.contents:  # enumerate though List of recipe_details.contents

        # normalize item.contents
        try:
            ingredient = None
            ingredient = item.ingredient.strip().lower()

            quantity = None
            quantity = item.quantity.strip().lower()

            unit = None
            unit = item.unit.strip().lower()
        except Exception as msg:  # failure
            pass

        # create a new ingredient in database if it doesn't exist
        if ingredient:

            # lookup ingredient in the database
            try:
                ingredient_id = ''
                if ingredient.isdigit():    # lookup by id
                    ingredient_id = db.query(Ingredient).filter(
                        Ingredient.id == ingredient).first()
                    ingredient_id = ingredient_id.id

                    if ingredient_id is None:  # failure
                        raise HTTPException(
                            status.HTTP_400_BAD_REQUEST, "Ingredient id doesn't exist.")
                else:                       # lookup by name
                    ingredient_id = db.query(Ingredient).filter(
                        Ingredient.name == ingredient).first()
                    ingredient_id = ingredient_id.id
            except:  # ingredient not found by id or name in the database

                # create a new ingredient in the database
                try:
                    db_ingredient = Ingredient(
                        name=ingredient)
                    db.add(db_ingredient)
                    db.commit()
                    db.refresh(db_ingredient)
                    ingredient_id = db_ingredient
                    ingredient_id = ingredient_id.id
                except Exception as msg:  # failure
                    print(f"Failed to create ingredient '{name}': {msg}")
                    raise HTTPException(
                        status.HTTP_500_INTERNAL_SERVER_ERROR, f"Failed to create ingredient '{name}'")

            try:  # create a new recipeingredient in the database
                db_recipeingredient = RecipeIngredient(
                    recipe_id=db_recipe.id,
                    quantity=quantity,
                    unit=unit,
                    ingredient_id=ingredient_id)
                db.add(db_recipeingredient)
                db.commit()
                db.refresh(db_recipeingredient)
            except Exception as msg:  # Failure
                print(f"Failed to create recipeingredient: {msg}")
                raise HTTPException(
                    status_code=500, detail="Failed to create recipeingredient")

    # get updated recipe
    recipe_details = db.query(Recipe).filter(Recipe.id == db_recipe.id).first()

    # generate recipeout response
    temp_contents = []
    if recipe_details.contents is None:
        recipe_details.contents = []
    for item in recipe_details.contents:  # enumerate contents and build json

        if item.ingredient_id:
            ingredient_name = db.query(Ingredient).filter(
                Ingredient.id == item.ingredient_id).first()
            ingredient_name = ingredient_name.name
            item = {
                "quantity": item.quantity,
                "unit": item.unit,
                "ingredient": ingredient_name
            }
            temp_contents.append(item)

    # build recipe with contents
    temp_recipe = {
        "name": recipe_details.name,
        "note": recipe_details.note,
        "star": recipe_details.star,
        "contents": temp_contents,
        "id": recipe_details.id,
        "owner_id": recipe_details.owner_id,
        "created": recipe_details.created
    }

    return temp_recipe


def delete_recipe(recipe_id: int, db: Session, current_user):

    # lookup recipe_id in the database
    recipe = db.query(Recipe).filter(Recipe.id == recipe_id,
                                     Recipe.owner_id == current_user.id).first()
    if not recipe:  # recipe not found
        raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR,
                            f"Failed to find recipe id '{recipe_id}' associated to your user account")

    # lookup recipeingredients in the database
    recipeingredients = db.query(RecipeIngredient).filter(
        RecipeIngredient.recipe_id == recipe_id).all()
    if recipeingredients:  # recipeingredients found
        for item in recipeingredients:  # delete recipeingredients from the database where recipe_id = recipe_id
            db.delete(item)
            db.commit()
            db.flush

    # delete recipe from the database
    db.delete(recipe)
    db.commit()
    db.flush

    return status.HTTP_204_NO_CONTENT
