from datetime import datetime
import json


def readfile(filename):
    with open(module_path + filename) as f:
        return f.read()


# global constants
# Accusative - znahidnyj
WEEKDAYS_ACCUSATIVE = ["понеділок", "вівторок", "середу", "четвер", "п'ятницю", "суботу", "неділю"]
# Genitive - rodovyj
WEEKDAYS_GENITIVE_NEXT = ["наступного понеділка", "наступного вівторка", "наступної середи", "наступного четверга",
                          "наступної п'ятниці", "наступної суботи", "наступної неділі"]

WEEKDAYS_GENITIVE_THIS = ["цього понеділка", "цього вівторка", "цієї середи", "цього четверга", "цієї п'ятниці",
                          "цієї суботи", "цієї неділі"]

# global variables
module_path = ""


def get_human_readable_date(start_datetime, end_datetime,
                            current_day, current_week):
    human_readable_date = ""
    if ((current_day + 2) == int(start_datetime.strftime("%u"))) or \
            ((current_day == 6) and (start_datetime.strftime("%u") == "1")):
        human_readable_date += "завтра "
    elif current_week != int(start_datetime.strftime("%W")) % 2:
        human_readable_date += f"{WEEKDAYS_GENITIVE_NEXT[int(start_datetime.strftime('%u')) - 1]} "
    elif current_day != (int(start_datetime.strftime("%u")) - 1):
        human_readable_date += f"{WEEKDAYS_GENITIVE_THIS[int(start_datetime.strftime('%u')) - 1]} "
    else:
        human_readable_date += "сьогодні "

    human_readable_date += "з "
    human_readable_date += start_datetime.strftime("%H:%M")

    human_readable_date += " до "
    human_readable_date += end_datetime.strftime("%H:%M")

    return human_readable_date


def generate_lesson_description(lesson, start_datetime, end_datetime, current_day, current_week, overrides={}):
    output_settings = {"name": True, "date": True, "teacher": True, "link": True}
    output_settings.update(overrides)

    result = ""

    if output_settings['name']:
        result += f"{lesson['name']}\n"

    if output_settings['date']:
        human_readable_date = get_human_readable_date(start_datetime, end_datetime,
                                                      current_day, current_week)
        result += f"*Дата*: {human_readable_date}\n"

    if output_settings['teacher']:
        result += f"*Викладач*: {lesson['teacher']}\n"

    if output_settings['link']:
        result += f"*Посилання*: {lesson['link']}"

    return result


def get_schedule_data_from(filename):
    raw_schedule = json.loads(readfile(filename))

    baked_schedule = {}

    for day_number, lesson_times in enumerate(raw_schedule):
        for lesson_time in lesson_times:
            timestamp = day_number * 86400 + int(lesson_time.split(":")[0]) * 3600 \
                        + int(lesson_time.split(":")[1]) * 60

            new_record = dict(raw_schedule[day_number][lesson_time])
            new_record["source"] = filename.split(".json")[0]
            baked_schedule[timestamp] = new_record

    return baked_schedule


def process_arguments(args, base_day):
    selected_day = int(base_day)
    preferences = {}

    for arg in args:
        if arg[0] == "-":
            if arg[1:].isdigit():
                selected_day -= int(arg[1:])
            else:
                preferences[arg[1:]] = False

        elif arg[0] == "+":
            if arg[1:].isdigit():
                selected_day += int(arg[1:])
            else:
                preferences[arg[1:]] = True

    selected_day = selected_day % 14

    return preferences, selected_day


def get_lesson_description(schedule, reference_time, lesson_time, current_day, current_week, overrides={}):
    lesson_record = schedule[lesson_time]

    lesson_start_datetime = datetime.fromtimestamp(reference_time + lesson_time)
    lesson_end_datetime = datetime.fromtimestamp(reference_time + lesson_time + 5400)

    return generate_lesson_description(lesson_record, lesson_start_datetime, lesson_end_datetime, current_day,
                                       current_week, overrides=overrides)


def process(message, path):
    message_text = message["text"]
    full_command = message_text.split()

    # there is no need to check if the full_command list if empty as it
    # never will be - Telegram requires all messages to have at least
    # one printable symbol, so this is already protected
    base_command = full_command[0].lower()

    if base_command not in ["!пара", "!пари"]:
        return ""

    global module_path
    module_path = path

    schedule = get_schedule_data_from("schedule.json")
    schedule.update(get_schedule_data_from("additions.json"))

    current_time = datetime.now()

    current_week = current_time.isocalendar()[1] % 2
    current_day = current_time.weekday()

    current_seconds = current_week * 604800 + current_day * 86400 + current_time.hour * 3600 + current_time.minute \
                      * 60 + current_time.second

    reference_time = int(current_time.strftime("%s")) - current_seconds

    if base_command == "!пара":
        study_begin_ts = int(datetime(year=2023, month=9, day=4).strftime("%s"))
        current_ts = int(datetime.now().strftime("%s"))

        if -3600*4 < study_begin_ts - current_ts < 0:
            return "Навчання незабаром розпочнеться!"
        elif 0 <= study_begin_ts - current_ts < 1209600:
            return f"До навчання залишилося {study_begin_ts - current_ts} секунд..."
        elif study_begin_ts - current_ts >= 1209600:
            return "Ви маєте законне право відпочити, пари почнуться не скоро"

        upcoming_lessons = [timestamp for timestamp in schedule if timestamp > current_seconds - 5400]

        if len(upcoming_lessons) > 0:
            closest_lesson_time = min(upcoming_lessons)
        else:
            closest_lesson_time = min(schedule)

        return "*Актуальна пара*: " + get_lesson_description(schedule, reference_time, closest_lesson_time, current_day,
                                                           current_week)

    elif base_command == "!пари":
        base_day = current_week * 7 + current_day

        if len(full_command) >= 2:
            args = [i for i in full_command[1:] if len(i) > 1]
            preferences, selected_day = process_arguments(args, base_day)
        else:
            preferences = {}
            selected_day = base_day

        lesson_list = [i for i in schedule if selected_day * 86400 <= i < (selected_day + 1) * 86400]

        lesson_descriptions_list = ["*Назва*: " + get_lesson_description(schedule, reference_time, lesson_time,
                                                                       current_day, current_week, overrides=preferences)
                                    for lesson_time in lesson_list]

        return f"__Пари у {WEEKDAYS_ACCUSATIVE[selected_day % 7]}__:\n" + "\n\n".join(lesson_descriptions_list)