from flask import Blueprint, request, render_template, redirect, session, url_for, send_file, jsonify, Response, current_app, send_from_directory
import psycopg2, math, json, datetime, main, copy, requests, process, database, pprint, MyDataclasses
from config import config, sites_config
from main import unfoldCostLayers
from user_api import login_required
import os
import postsqldb, webpush
from flasgger import swag_from
from scripts.recipes import database_recipes 
from flask_restx import Api, fields

recipes_api = Blueprint('recipes_api', __name__)
model_api = Api(recipes_api)

@recipes_api.route("/recipes")
@login_required
def recipes():
    """This is the main endpoint to reach the webpage for a list of all recipes
    ---
    responses:
        200:
            description: returns recipes/index.html with sites, current_site.
    """
    sites = [site[1] for site in main.get_sites(session['user']['sites'])]
    return render_template("recipes/index.html", 
                           current_site=session['selected_site'], 
                           sites=sites)

@recipes_api.route("/recipe/<mode>/<id>")
@login_required
def recipe(id, mode='view'):
    """This is the main endpoint to reach the webpage for a recipe's view or edit mode.
    ---
    parameters:
      - name: mode
        in: path
        type: string
        required: true
        default: view
      - name: id
        in: path
        type: integer
        required: true
        default: all
    responses:
      200:
        description: Respondes with either the Edit or View webpage for the recipe.
    """
    database_config = config()
    with psycopg2.connect(**database_config) as conn:
        units = postsqldb.UnitsTable.getAll(conn)

    if mode == "edit":
        return render_template("recipes/recipe_edit.html", recipe_id=id, current_site=session['selected_site'], units=units)
    if mode == "view":
        return render_template("recipes/recipe_view.html", recipe_id=id, current_site=session['selected_site'])

@recipes_api.route('/recipes/getRecipes', methods=["GET"])
def getRecipes():
    """ Get a subquery of recipes from the database by passing a page, limit
    ---
    responses:
        200:
            description: limit of rows passed returned to requester
    """
    recipes = []
    count=0
    if request.method == "GET":
        page = int(request.args.get('page', 1))
        limit = int(request.args.get('limit', 1))
        offset = (page-1)*limit
        site_name = session['selected_site']
        recipes, count = database_recipes.getRecipes(site_name, (limit, offset))
        return jsonify({'recipes': recipes, 'end': math.ceil(count/limit), 'error': False, 'message': 'fetch was successful!'})
    return jsonify({'recipes': recipes, 'end': math.ceil(count/limit), 'error': True, 'message': f'method is not allowed: {request.method}'})

@recipes_api.route('/recipe/getRecipe', methods=["GET"])
def getRecipe():
    """ Get a query for recipe id from database by passing an id
    ---
    responses:
        200:
            description: id queried successfully!

    """
    recipe = {}
    if request.method == "GET":
        id = int(request.args.get('id', 1))
        site_name = session['selected_site']
        recipe = database_recipes.getRecipe(site_name, (id,), convert=True)
        return jsonify({'recipe': recipe, 'error': False, 'message': 'Recipe returned successfully!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': f'method {request.method} not allowed'})

@recipes_api.route('/recipes/addRecipe', methods=["POST"])
def addRecipe():
    if request.method == "POST":
        recipe_name = request.get_json()['recipe_name']
        recipe_description = request.get_json()['recipe_description']
        database_config = config()
        site_name = session['selected_site']
        user_id = session['user_id']
        with psycopg2.connect(**database_config) as conn:
            recipe = postsqldb.RecipesTable.Payload(
                name=recipe_name,
                author=user_id,
                description=recipe_description
            )
            recipe = postsqldb.RecipesTable.insert_tuple(conn, site_name, recipe.payload())
            webpush.push_ntfy('New Recipe', f"New Recipe added to {site_name}; {recipe_name}!{recipe_description} http://test.treehousefullofstars.com/recipe/view/{recipe['id']} http://test.treehousefullofstars.com/recipe/edit/{recipe['id']}")
        return jsonify({'recipe': recipe, 'error': False, 'message': 'Add Recipe successful!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': 'Add Recipe unsuccessful!'})

@recipes_api.route('/recipe/getItems', methods=["GET"])
def getItems():
    """ Pass along a page, limit, and search strings to get a pagination of items from the system
    ---
    responses:
        200:
            description: Items were returned successfully!
    """
    recordset = []
    count = {'count': 0}
    if request.method == "GET":
        page = int(request.args.get('page', 1))
        limit = int(request.args.get('limit', 10))
        search_string = request.args.get('search_string', 10)
        site_name = session['selected_site']
        offset = (page - 1) * limit
        recordset, count = database_recipes.getModalSKUs(site_name, (search_string, limit, offset))
        print(recordset)
        return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":False, "message":"items fetched succesfully!"})
    return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":True, "message":"There was an error with this GET statement"})


update_model = model_api.model('model', {
    'id': fields.Integer(min=1),
    'update': fields.Raw(required=True, description="all the data to be updated!")
})

@recipes_api.route('/recipe/postUpdate', methods=["POST"])
@model_api.expect(update_model)
def postUpdate():
    """ This is an endpoint for updating an RecipeTuple in the sites recipes table
    ---
    responses:
        200:
            description: The time was updated successfully!

    Returns:
        dict: returns a dictionary containing the updated recipe object, error status, and a message to post for notifications
    """
    recipe = {}
    if request.method == "POST":
        recipe_id = int(request.get_json()['recipe_id'])
        update = request.get_json()['update']
        site_name = session['selected_site']
        recipe = database_recipes.postRecipeUpdate(site_name, {'id': recipe_id, 'update': update})
        return jsonify({'recipe': recipe, 'error': False, 'message': 'Update of Recipe successful!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': 'Update of Recipe unsuccessful!'})

@recipes_api.route('/recipe/postCustomItem', methods=["POST"])
def postCustomItem():
    recipe = {}
    if request.method == "POST":
        database_config = config()
        site_name = session['selected_site']
        with psycopg2.connect(**database_config) as conn:
            recipe_item = postsqldb.RecipesTable.ItemPayload(
                uuid=f"%{int(request.get_json()['rp_id'])}{database.getUUID(6)}%",
                rp_id=int(request.get_json()['rp_id']),
                item_type=request.get_json()['item_type'],
                item_name=request.get_json()['item_name'],
                uom=request.get_json()['uom'],
                qty=float(request.get_json()['qty']),
                links=request.get_json()['links']
            )
            postsqldb.RecipesTable.insert_item_tuple(conn, site_name, recipe_item.payload(), convert=True)
            recipe = postsqldb.RecipesTable.getRecipe(conn, site_name, (int(request.get_json()['rp_id']), ), convert=True)
        return jsonify({'recipe': recipe, 'error': False, 'message': 'Recipe Item was added successful!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': 'Recipe Item was not added unsuccessful!'})

@recipes_api.route('/recipe/postSKUItem', methods=["POST"])
def postSKUItem():
    recipe = {}
    if request.method == "POST":
        recipe_id = int(request.get_json()['recipe_id'])
        item_id = int(request.get_json()['item_id'])

        database_config = config()
        site_name = session['selected_site']
        with psycopg2.connect(**database_config) as conn:
            item = database.getItemAllByID(conn, site_name, (item_id, ), convert=True)
            recipe_item = postsqldb.RecipesTable.ItemPayload(
                uuid=item['barcode'],
                rp_id=recipe_id,
                item_type='sku',
                item_name=item['item_name'],
                uom=item['item_info']['uom']['id'],
                qty=float(item['item_info']['uom_quantity']),
                item_id=item['id'],
                links=item['links']
            )
            postsqldb.RecipesTable.insert_item_tuple(conn, site_name, recipe_item.payload(), convert=True)
            recipe = postsqldb.RecipesTable.getRecipe(conn, site_name, (recipe_id, ), convert=True)
        return jsonify({'recipe': recipe, 'error': False, 'message': 'Recipe Item was added successful!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': 'Recipe Item was not added unsuccessful!'})

@recipes_api.route('/recipe/postImage/<recipe_id>', methods=["POST"])
def uploadImage(recipe_id):
    file = request.files['file']
    file_path = current_app.config['UPLOAD_FOLDER'] + f"/recipes/{file.filename.replace(" ", "_")}"
    file.save(file_path)

    database_config = config()
    site_name = session['selected_site']
    with psycopg2.connect(**database_config) as conn:
        postsqldb.RecipesTable.updateRecipe(conn, site_name, {'id': recipe_id, 'update': {'picture_path': file.filename.replace(" ", "_")}})
    
    return jsonify({})

@recipes_api.route('/recipe/getImage/<recipe_id>')
def get_image(recipe_id):
    database_config = config()
    site_name = session['selected_site']
    with psycopg2.connect(**database_config) as conn:
        with conn.cursor() as cur:
            cur.execute(f"SELECT picture_path FROM {site_name}_recipes WHERE id=%s;", (recipe_id,))
            rows = cur.fetchone()[0]
            return send_from_directory('static/pictures/recipes', rows)

@recipes_api.route('/recipe/deleteRecipeItem', methods=["POST"])
def deleteRecipeItem():
    recipe = {}
    if request.method == "POST":
        id = int(request.get_json()['id'])
        database_config = config()
        site_name = session['selected_site']
        with psycopg2.connect(**database_config) as conn:
            deleted_item = postsqldb.RecipesTable.delete_item_tuple(conn, site_name, (id, ), convert=True)
            recipe = postsqldb.RecipesTable.getRecipe(conn, site_name, (int(deleted_item['rp_id']), ), convert=True)
        return jsonify({'recipe': recipe, 'error': False, 'message': f'Recipe Item {deleted_item['item_name']} was deleted successful!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': 'Recipe Item was not deleted unsuccessful!'})

@recipes_api.route('/recipe/saveRecipeItem', methods=["POST"])
def saveRecipeItem():
    recipe = {}
    if request.method == "POST":
        id = int(request.get_json()['id'])
        update = request.get_json()['update']
        database_config = config()
        site_name = session['selected_site']
        with psycopg2.connect(**database_config) as conn:
            updated_line = postsqldb.RecipesTable.update_item_tuple(conn, site_name, {'id': id, 'update': update}, convert=True)
            recipe = postsqldb.RecipesTable.getRecipe(conn, site_name, (int(updated_line['rp_id']), ), convert=True)
        return jsonify({'recipe': recipe, 'error': False, 'message': f'Recipe Item {updated_line['item_name']} was updated successful!'})
    return jsonify({'recipe': recipe, 'error': True, 'message': 'Recipe Item was not updated unsuccessful!'})