from functools import lru_cache

from flask import Flask, render_template, request

from ml_editor.ml_editor import get_recommendations_from_input
import ml_editor.model_v2 as v2_model
import ml_editor.model_v3 as v3_model

app = Flask(__name__)


@app.route("/")
def landing_page():
    """
    Wyświetlenie strony głównej
    """
    return render_template("landing.html")


@app.route("/v1", methods=["POST", "GET"])
def v1():
    """
    Wyświetlenie formularza dla danych wejściowych i wyników w pierwszej wersji modelu.
    """
    return handle_text_request(request, "v1.html")


@app.route("/v2", methods=["POST", "GET"])
def v2():
    """
        Wyświetlenie formularza dla danych wejściowych i wyników w drugiej wersji modelu.
        """
    return handle_text_request(request, "v2.html")


@app.route("/v3", methods=["POST", "GET"])
def v3():
    """
        Wyświetlenie formularza dla danych wejściowych i wyników w trzeciej wersji modelu.
    """
    return handle_text_request(request, "v3.html")


def get_model_from_template(template_name):
    """
    Uzyskanie nazwy odpowiedniego modelu na podstawie nazwy szablonu.
    :param template_name: nazwa szablonu HTML
    :return: nazwa modelu
    """
    return template_name.split(".")[0]


@lru_cache(maxsize=128)
def retrieve_recommendations_for_model(question, model):
    """
    Funkcja wyliczająca lub pobierająca zalecenia. Wykorzystuje bufor 
    LRU do zapisywania przetwarzanych wyników. Jeżeli to samo pytanie 
    pojawi się po raz drugi, można odczytać wyniki z bufora i szybciej 
    je wyświetlić.
    :param question: wejściowy tekst dla modelu
    :param model: model, którego należy użyć
    :return: zalecenia modelu
    """
    if model == "v1":
        return get_recommendations_from_input(question)
    if model == "v2":
        return v2_model.get_pos_score_from_text(question)
    if model == "v3":
        return v3_model.get_recommendation_and_prediction_from_text(question)
    raise ValueError("Błędny model")


def handle_text_request(request, template_name):
    """
    Wyświetlenie formularza wejściowego po odebraniu zapytania GET oraz 
    wyświetlenie wyników dla wpisanego pytania przesłanego za pomocą 
    zapytania POST.
    :param request: zapytanie HTTP
    :param template_name: nazwa szablonu (np. v2.html)
    :return: formularz wejściowy lub wyniki w zależności od typu zapytania
    """
    if request.method == "POST":
        question = request.form.get("question")
        model_name = get_model_from_template(template_name)
        suggestions = retrieve_recommendations_for_model(question, model_name)
        payload = {
            "input": question,
            "suggestions": suggestions,
            "model_name": model_name,
        }
        return render_template("results.html", ml_result=payload)
    else:
        return render_template(template_name)
