from random import choice
from datetime import date, timedelta
from flask import flash, session, redirect, url_for, request, render_template
from sqlalchemy import desc
from share import share
from create_db import Card, Rating, get_session, get_engine
from settings import get_settings
from link_handler import render_embed_link


"""
testing
"""
def autofill_ratings():

    Session = get_session()
    with Session() as dbsession:
        for i in range(100):
            card = Rating(user_id="1", card_id=choice([10, 13, 14, 75]), rating_value=choice(["Maybe", "No"]), rating_time=date.today()-timedelta(choice([i for i in range(100)])))
            dbsession.add(card)
            dbsession.commit()
            dbsession.close()    
    get_engine().dispose()
    return None

"""
Config
"""
maybe_factor    = 1.2
no_factor       = 2.1

"""
Main fuctions
"""
def calculate_interval(sorted_rates, maybe_factor, no_factor):   
    if sorted_rates == []:
        return 1
    elif sorted_rates[0].rating_value == "Yes":
        return 1
    elif sorted_rates[0].rating_value == "Maybe":
        sorted_rates.pop(0)
        return calculate_interval(sorted_rates, maybe_factor, no_factor) * maybe_factor
    elif sorted_rates[0].rating_value == "No":
        sorted_rates.pop(0)
        return calculate_interval(sorted_rates, maybe_factor, no_factor) * no_factor
    elif sorted_rates[0].rating_value == "Delete":
        return -1 #"Deleted"


def get_interval(card_id):
    """
    takes card_id looks at the history of rates and gives the current interval
    """
    Session = get_session()
    with Session() as dbsession:
        sorted_rates_by_card = dbsession.query(Rating).filter(Rating.card_id == card_id).order_by(desc(Rating.rating_time)).all()
        dbsession.close()
    get_engine().dispose()

    if sorted_rates_by_card == None:
        print("ni kart... kaj zdaj") #@TODO
        return None
    else:
        interval = calculate_interval(sorted_rates_by_card, maybe_factor, no_factor)
        return round(interval)

#to vključuje tudi new...
def is_due(card_id):
    Session = get_session()
    with Session() as dbsession:

        interval = get_interval(card_id)
        last_rating_date = dbsession.query(Rating).filter(Rating.card_id == card_id).order_by(desc(Rating.rating_time)).first()
        due_date = last_rating_date.rating_time + timedelta(interval)
        dbsession.close()
    get_engine().dispose()

    if interval < 0:
        return False
    if last_rating_date == None:
        return True
    return date.today() >= due_date


def is_new(card_id):
    Session = get_session()
    with Session() as dbsession:
        rating = dbsession.query(Rating).filter(Rating.card_id == card_id).first()
        dbsession.close()
    get_engine().dispose()

    return rating == None


def list_of_due_cards_by_ids(user_id):
    "this should not include new cards"
    Session = get_session()
    with Session() as dbsession:
        cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
        l = []
        for card in cards:
            if is_new(card.id):
                pass
            elif is_due(card.id):
                l.append(card.id)
        dbsession.close()

    get_engine().dispose()
    return l


def list_of_new_cards_by_ids(user_id):
    Session = get_session()
    with Session() as dbsession:
        cards = dbsession.query(Card).filter(Card.owner_id == user_id).all()
        l = []
        for card in cards:
            rating = dbsession.query(Rating).filter(Rating.card_id == card.id).first()
            if rating == None:
                l.append(card.id)
        dbsession.close()
    return l


def rated_today_by_staus (card_status, user_id):
    """
    Returns number of cards rated today by user by status (new or due)
    """
    n = 0
    d = 0
    today = date.today()

    Session = get_session()
    with Session() as dbsession:
        ratings_today = dbsession.query(Rating).filter(
            Rating.rating_time == today,
            Rating.user_id == user_id
        )
        for rating in ratings_today:
            count_all_rates_of_card = dbsession.query(Rating).filter(rating.card_id == Rating.card_id).count()
            print("count_all_rates_of_card: ", count_all_rates_of_card) 

            if count_all_rates_of_card == 1:
                n+=1
            elif count_all_rates_of_card > 1:
                d+=1
            else:
                print("wtf")
                raise Exception("Count be wrong! There should be at least one rating")
        
        dbsession.close()
    get_engine().dispose()    
    
    if card_status == "new":
        return n
    elif card_status == "due":
        return d
    else:
        raise Exception("must input either 'new' or 'due' as parameter")


def get_a_card_by_status(user_id, card_status):
    if card_status == "new":
        l = list_of_new_cards_by_ids(user_id)
        card_id = l[0]
    if card_status == "due":
        l = list_of_due_cards_by_ids(user_id)
        card_id = l[0]
    return card_id

"""
Export functions
"""
def remaining_items(max_items, total_queue, rated_today):
    """
    gives number of remaining items. Either upto max or if total runs out earlier.
    """    
    n_of_remaining = min((max_items-rated_today), total_queue)
    return n_of_remaining

def schedule_status(user_id):
    """
    Returns information needed for start/continue/done menu ui
    """
    user_settings = get_settings(user_id)
    max_new = int(user_settings["max_new"])
    max_due = int(user_settings["max_due"])

    rated_new = rated_today_by_staus("new", user_id)
    rated_due = rated_today_by_staus("due", user_id)

    total_new = len(list_of_new_cards_by_ids(user_id))
    total_due = len(list_of_due_cards_by_ids(user_id))
    
    remaining_new_today = remaining_items(max_new, total_new, rated_new)
    remaining_due_today = remaining_items(max_due, total_due, rated_due)
    remaining_total_today = remaining_due_today + remaining_new_today

    if remaining_total_today == 0:
        return "done"
    elif rated_due+rated_new == 0:
        return "start"
    else:
        return "continue"

def remaining_by_status(user_id, status):
    if status == "new":
        l = len(list_of_new_cards_by_ids(user_id))
    elif status == "due":
        l = len(list_of_due_cards_by_ids(user_id))
    return l

"""
Engine
"""
def sr_session():
    
    #check if user in session
    if not 'user_id' in session:
        redirect(url_for('login'))
    user_id = session['user_id']
    username = session['username']


    #form sent?
    if request.method == 'POST':
        #get card_id from the card, rendered from the template, data actually from the template... why tho
        card_id = request.form.get('card_id', None)
        if not card_id:
            raise Exception("card_id necesarry!")

        #@TODO check if this card is part of the user's deck to prevent possibile hack?
        Session = get_session()
        with Session() as dbsession:
            submit_card = dbsession.query(Card).get(card_id)

            # Share
            #@@TODO, this should not change the card
            share_request = request.form.get("share", None)
            if share_request:
                share(submit_card, user_id)
            #Rate
            else:
                rate = request.form.get('rate', None)            
                if not rate:
                    raise Exception("Need rate info!")

                r = Rating(user_id=user_id, card_id=submit_card.id, rating_value=rate, rating_time=date.today())
                dbsession.add(r)
                dbsession.commit()
                dbsession.close()
        get_engine().dispose()
    
    user_settings = get_settings(user_id)
    max_new = int(user_settings["max_new"])
    max_due = int(user_settings["max_due"])

    total_new = len(list_of_new_cards_by_ids(user_id))
    total_due = len(list_of_due_cards_by_ids(user_id))

    rated_today_new = rated_today_by_staus("new", user_id)
    rated_today_due = rated_today_by_staus("due", user_id)

    remaining_new_today = remaining_items(max_new, total_new, rated_today_new)
    remaining_due_today = remaining_items(max_due, total_due, rated_today_due)
    
    print("remaining_new_today: ", remaining_new_today)
    print("remaining_due_today: ", remaining_due_today)

    print("list_of_due_cards_by_ids: ", list_of_due_cards_by_ids(user_id))
    print("list_of_new_cards_by_ids: ", list_of_new_cards_by_ids(user_id))

    #checks if there are any new/due cards left for today and gets the next one. 
    #max can be more than all scheduled, min decides which is the limt.
    if remaining_new_today > 0:
        print("gettin new") ##TODO problem je, ker na produkciji zgleda kot da jemlje skoz new, čeprav bi moral due
        next_card_id=get_a_card_by_status(user_id, "new")
    elif remaining_due_today > 0:
        print("getting due")
        next_card_id=get_a_card_by_status(user_id, "due")
    else:
        flash("no more cards today")
        return redirect("/menu")
    
    Session = get_session()
    with Session() as dbsession:
        show_card = dbsession.query(Card).get(next_card_id)
        dbsession.close()
    get_engine().dispose()
    
    interval = get_interval(next_card_id)
    
    card_type = show_card.card_type
    print("card type: ", card_type)

    if card_type == 'PDF':
        #these factors should be better packaged
        return render_template("deck.html", username=username, card=show_card, maybe_in=round(interval*maybe_factor), no_in=round(no_factor*interval))
    elif card_type == 'URL':
        #templates for different kinds of links
        return render_embed_link(cm_username=username,
                          card=show_card, 
                          maybe_in=round(interval*maybe_factor), 
                          no_in=round(no_factor*interval))

 

        #return render_template("link.html", username=username, card=show_card, maybe_in=round(interval*maybe_factor), no_in=round(no_factor*interval))