"""inference.py: Ten moduł zawiera przykładowe funkcje opisane w książce.
Nie są one wykorzystywane w edytorze ani w notatnikach.
"""

from functools import lru_cache

REQUIRED_FEATURES = [
    "is_question",
    "action_verb_full",
    "language_question",
    "question_mark_full",
    "norm_text_len",
]


def find_absent_features(data):
    missing = []
    for feat in REQUIRED_FEATURES:
        if feat not in data.keys():
            missing.append(feat)
    return missing


def check_feature_types(data):
    types = {
        "is_question": bool,
        "action_verb_full": bool,
        "language_question": bool,
        "question_mark_full": bool,
        "norm_text_len": float,
    }
    mistypes = []
    for field, data_type in types:
        if not isinstance(data[field], data_type):
            mistypes.append((data[field], data_type))
    return mistypes


def run_heuristic(question_len):
    pass


@lru_cache(maxsize=128)
def run_model(question_data):
    """
    Przykładowa funkcja. Właściwa funkcja jest wykorzystywana w pliku app.py.
    :param question_data:
    """
    # Umieść tutaj kod modelu o długim czasie wnioskowania.
    pass


def validate_and_handle_request(question_data):
    missing = find_absent_features(question_data)
    if len(missing) > 0:
        raise ValueError("Liczba brakujących cech: %s" % missing)

    wrong_types = check_feature_types(question_data)
    if len(wrong_types) > 0:
        # Jeżeli dane są błędne, ale znana jest długość pytania, uruchamiana jest heurystyka.
        if "text_len" in question_data.keys():
            if isinstance(question_data["text_len"], float):
                return run_heuristic(question_data["text_len"])
        raise ValueError("Liczba błędnych typów cech: %s" % wrong_types)

    return run_model(question_data)


def verify_output_type_and_range(output):
    if not isinstance(output, float):
        raise ValueError("Błędny typ danych wyjściowych: %s, %s" % (output, type(output)))
    if not 0 < output < 1:
        raise ValueError("Dane wyjściowe spoza zakresu: %s, %s" % output)


def validate_and_correct_output(question_data, model_output):
    # Sprawdzenie typu i zakresu wartości, a następnie zgłoszenie błędu w razie potrzeby.
    try:
        # Zgłoszenie błędu, jeżeli wynik modelu jest niepoprawny.
        verify_output_type_and_range(model_output)
    except ValueError:
        # Uruchomienie heurystyki. Można również uruchomić inny model.
        run_heuristic(question_data["text_len"])

    # Jeżeli nie został zgłoszony błąd, można zwrócić wynik modelu.
    return model_output
