import sys
from calendar import month_name
from logging import exception

from nicegui import *

import ui
from definitions import *
from web_ui import  *
from users import *
from datetime import datetime

import calendar


# Überblicksseite zum Ausdrucken oder als PDF speichern
@ui.page('/api/month/{username}/{year}-{month}')
def page_overview_month(username: str, year: int, month: int):

    data = load_adminsettings()

    try:
        current_user = user(username)
        days_with_errors = current_user.archiving_validity_check(year, month)
        ui.page_title(f"Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}")
        if current_user.get_archive_status(year, month):
            with ui.column().classes('w-full items-end gap-0'):
                ui.label(f"Bericht erstellt am {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}")
                ui.label('Archiviert').classes('italic').classes('text-red text-bold text-xl')
            #ui.add_head_html('<style>body {background-color: #FFF7B1; }</style>')
        else:
            with ui.column().classes('w-full items-end gap-0'):
                ui.label(f"Bericht erstellt am {datetime.now().strftime('%d.%m.%Y %H:%M:%S')}")
        ui.markdown(f'#Bericht für {current_user.fullname} für {calendar.month_name[month]} {year}')

        pad_x = 4
        pad_y = 0

        color_weekend = "gray-100"
        color_holiday = "gray-100"

        def overview_table():
            # Timestamp in ein Array schreiben
            timestamps = current_user.get_timestamps(year, month)
            timestamps.sort()

            # Abwesenheitsdaten in ein Dict schreiben
            user_absent = current_user.get_absence(year, month)

            # Dictionary für sortierte Timestamps
            timestamps_dict = { }

            # Dictionary mit zunächst leeren Tageinträgen befüllen
            for day in range(1, monthrange(year, month)[1] + 1):
                # Jeder Tag bekommt eine leere Liste
                timestamps_dict[day] = [ ]

            # Timestamps den Monatstagen zuordnen
            for stamp in timestamps:
                day_of_month_of_timestamp = datetime.fromtimestamp(int(stamp)).day
                timestamps_dict[day_of_month_of_timestamp].append(int(stamp))

            general_saldo = 0

            bg_color = ''
            if current_user.get_archive_status(year, month):
                bg_color = ' bg-yellow-100'

            with ui.grid(columns='auto auto 1fr 1fr 1fr').classes(f'gap-0 border px-0 py-0{bg_color}'):
                ui.markdown("**Datum**").classes(f'border px-{pad_x} py-{pad_y}')
                ui.markdown("**Buchungen**").classes(f'border px-{pad_x} py-{pad_y}')
                ui.markdown("**Ist**").classes(f'border px-{pad_x} py-{pad_y}')
                ui.markdown("**Soll**").classes(f'border px-{pad_x} py-{pad_y}')
                ui.markdown("**Saldo**").classes(f'border px-{pad_x} py-{pad_y}')

                # Gehe jeden einzelnen Tag des Dictionaries für die Timestamps durch
                for day in list(timestamps_dict):
                    booking_text = ""
                    color_day = 'inherit'
                    if datetime(year, month, day).strftime('%w') in ["0", "6"]:
                        color_day = color_weekend

                    current_day_date = f"{datetime(year, month, day).strftime('%a')}, {day}.{month}.{year}"
                    with ui.link_target(day).classes(f'border px-{pad_x} py-{pad_y} bg-{color_day}'):
                        ui.markdown(current_day_date)

                    # Abwesenheitseinträge
                    booking_color = "inherit"
                    booking_text_color = "inherit"
                    try:
                        # Abwesenheitszeiten behandeln
                        for i in list(user_absent):
                            if int(i) == day:
                                booking_text += absence_entries[user_absent[i]]["name"] + "<br>"
                                booking_color = absence_entries[user_absent[i]]["color"]
                                booking_text_color = absence_entries[user_absent[i]]["text-color"]
                    except:
                        pass

                    # Buchungen behandeln
                    for i in range(0, len(timestamps_dict[day]), 2):
                        try:
                            temp_pair = [timestamps_dict[day][i], timestamps_dict[day][i + 1]]
                            booking_text = booking_text + str(datetime.fromtimestamp(temp_pair[0]).strftime('%H:%M')) + " - " + str(datetime.fromtimestamp(temp_pair[1]).strftime('%H:%M')) + "<br>"

                        except:
                            if len(timestamps_dict[day]) % 2 != 0:
                                booking_text += datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M') + " - ***Buchung fehlt!***"

                    day_notes = current_user.get_day_notes(year, month, day)
                    just_once = True
                    if len(day_notes) > 0:
                        if len(timestamps_dict[day]) > 0 or day in list(map(int, list(user_absent))):
                            booking_text += "<hr>"
                        for user_key, notes in day_notes.items():
                            if user_key == "admin":
                                booking_text += f"Administrator:<br>{notes}"
                            else:
                                booking_text += f"{current_user.fullname}:<br>{notes}"
                            if len(day_notes) > 1 and just_once:
                                booking_text += "<hr>"
                                just_once = False

                    booking_text_element = ui.markdown(booking_text).classes(f'border px-{pad_x} py-{pad_y} bg-{booking_color} text-{booking_text_color}')

                    # Ist-Zeiten berechnen
                    timestamps_of_this_day = []

                    # Suche mir alle timestamps für diesen Tag
                    for i in timestamps:
                        actual_timestamp = datetime.fromtimestamp(int(i))
                        timestamp_day = actual_timestamp.strftime('%-d')

                        if int(timestamp_day) == int(day):
                            timestamps_of_this_day.append(i)

                    timestamps_of_this_day.sort()
                    time_sum = 0
                    if len(timestamps_of_this_day) > 1:

                        if len(timestamps_of_this_day) % 2 == 0:
                            for i in range(0, len(timestamps_of_this_day), 2):
                                time_delta = int(
                                    timestamps_of_this_day[i + 1]) - int(
                                    timestamps_of_this_day[i])
                                time_sum = time_sum + time_delta
                        else:
                            for i in range(0, len(timestamps_of_this_day) - 1, 2):
                                time_delta = int(
                                    timestamps_of_this_day[i + 1]) - int(
                                    timestamps_of_this_day[i])
                                time_sum = time_sum + time_delta

                        is_time = convert_seconds_to_hours(time_sum) + " h"
                    else:
                        is_time = "Kein"

                    ui.markdown(is_time).classes(f'border px-{pad_x} py-{pad_y} text-center')
                    # Sollzeit bestimmen

                    hours_to_work = int(current_user.get_day_workhours(year, month, day))

                    if hours_to_work < 0:
                        target_time = ""
                    else:
                        target_time = f"{convert_seconds_to_hours(int(hours_to_work) * 3600)} h"
                    if int(hours_to_work) == 0:
                        booking_text = "Kein Arbeitstag"
                        date_dt = datetime(year, month, day)
                        if date_dt.strftime("%Y-%m-%d") in data["holidays"]:
                            booking_text = f'**{data["holidays"][date_dt.strftime("%Y-%m-%d")]}**'
                        booking_text_element.set_content(booking_text)

                    ui.markdown(target_time).classes(f'border px-{pad_x} py-{pad_y} text-center')

                    # Saldo für den Tag berechnen
                    day_in_list = datetime(year, month, day)
                    if time.time() > day_in_list.timestamp():

                        time_duty = int(current_user.get_day_workhours(year, month, day)) * 3600
                        if time_duty < 0:
                            saldo = 0
                            total = ""
                            booking_text = "Kein Arbeitsverhältnis"
                            booking_text_element.set_content(booking_text)
                        else:
                            saldo = int(time_sum) - int(time_duty)
                            # Nach Abwesenheitseinträgen suchen
                            try:
                                for i in list(user_absent):
                                    if int(i) == day and user_absent[i] != "UU":
                                        saldo = 0
                            except:
                                pass

                            general_saldo = general_saldo + saldo
                            total = f"{convert_seconds_to_hours(saldo)} h"

                    else:
                        total = "-"
                    if total == "-":
                        total_class = 'text-center'
                    else:
                        total_class = 'text-right'
                    ui.markdown(total).classes(total_class).classes(f'border px-{pad_x} py-{pad_y}')

                # Überstundenzusammenfassung
                ui.markdown("Überstunden aus Vormonat:").classes(f'col-span-4 text-right border px-{pad_x} py-{pad_y}')
                last_months_overtime = current_user.get_last_months_overtime(year, month)
                ui.markdown(f"{convert_seconds_to_hours(last_months_overtime)} h").classes(f'text-right border px-{pad_x} py-{pad_y}')
                ui.markdown("Überstunden diesen Monat:").classes(f'col-span-4 text-right border px-{pad_x} py-{pad_y}')
                ui.markdown(f"{convert_seconds_to_hours(general_saldo)} h").classes(f'text-right border px-{pad_x} py-{pad_y}')
                ui.markdown("**Überstunden Gesamt:**").classes(f'col-span-4 text-right border px-{pad_x} py-{pad_y}')
                global overtime_overall
                overtime_overall = last_months_overtime + general_saldo
                ui.markdown(f"**{convert_seconds_to_hours(overtime_overall)} h**").classes(f'text-right border px-{pad_x} py-{pad_y}')

        overview_table()

        def absence_table():
            absences_this_month = current_user.get_absence(year, month)
            absence_dict = { }

            for abbr in list(absence_entries):
                absence_dict[abbr] = 0

            for key, value in absences_this_month.items():
                if value in list(absence_dict):
                    absence_dict[value] += 1

            total_absence_days = 0
            for key, value in absence_dict.items():
                total_absence_days += absence_dict[key]

            if total_absence_days > 0:
                ui.markdown("###Abwesenheitstage diesen Monat:")

                with ui.grid(columns='auto 25%').classes(f'gap-0 border px-0 py-0'):

                    for key, value in absence_dict.items():
                        if value > 0:
                            ui.markdown(absence_entries[key]['name']).classes(f"border px-{pad_x} py-{pad_y}")
                            ui.markdown(str(value)).classes(f'border px-{pad_x} py-{pad_y} text-center')

        absence_table()

        def archive():
            current_year = datetime.now().year
            current_month = datetime.now().month
            archivable = False

            if current_year > year:
                if current_user.get_archive_status(year, month) == False:
                    archivable = True
            if current_year == year:
                if current_month > month:
                    if current_user.get_archive_status(year, month) == False:
                        archivable = True

            def archive_dialog():
                def do_archiving():
                    global overtime_overall
                    current_user.archive_hours(year, month, overtime_overall)
                    dialog.close()
                    ui.navigate.to(f'/api/month/{username}/{year}-{month}')

                with ui.dialog() as dialog, ui.card():
                    with ui.grid(columns='1fr 1fr'):
                        ui.markdown("Hiermit bestätigen Sie, dass die Zeitbuchungen im Montagsjournal korrekt sind.<br>Sollte dies nicht der Fall sein, wenden Sie sich für eine Korrektur an den Administrator.").classes('col-span-2')
                        ui.button("Archivieren", on_click=do_archiving)
                        ui.button("Abbrechen", on_click=dialog.close)

                dialog.open()

            if archivable == True:
                if len(days_with_errors) > 0:
                    ui.label("Es gibt Inkonsistenzen in den Buchungen. Folgende Tage müssen überprüft werden:")
                    with ui.grid(columns=len(days_with_errors)):
                        for i in days_with_errors:
                            ui.link(f"{i}.", f'#{i}')

                archive_button = ui.button("Archivieren", on_click=archive_dialog)
                if len(days_with_errors) > 0:
                    archive_button.disable()

        archive()

    except Exception as e:
        print(str(type(e).__name__) + " " + str(e))
        if type(e) == UnboundLocalError:
            ui.markdown('#Fehler')
            ui.markdown('Benutzer existiert nicht')
        else:
            ui.markdown('#Fehler')
            ui.markdown(str(type(e)))
            ui.markdown(str(e))

@ui.page('/api/vacation/{username}/{year}')
def page_overview_vacation(username: str, year: int):

    if login_is_valid(username):

        try:
            current_user = user(username)

            month = datetime.now().month
            day = datetime.now().day

            ui.page_title(f"Urlaubsanspruch für {current_user.fullname} für {year}")
            ui.label(datetime.now().strftime('%d.%m.%Y')).classes('absolute top-5 right-5')
            ui.space()
            ui.markdown(f'#Urlaubsanspruch für {current_user.fullname} für {year}')

            pad_x = 4
            pad_y = 0

            vacationclaim = int(current_user.get_vacation_claim(year, month, day))
            if vacationclaim == -1:
                ui.markdown(f"###Kein Urlaubsanspruch für {year}")
            else:

                with ui.grid(columns='auto auto').classes(f'gap-0 border px-0 py-0'):
                    ui.markdown(f"Urlaubsanspruch für {year}:").classes(f'border px-{pad_x} py-{pad_y}')
                    ui.markdown(f"{vacationclaim} Tage").classes(f'text-right border px-{pad_x} py-{pad_y}')
                    ui.markdown("Registrierte Urlaubstage").classes(f'border px-{pad_x} py-{pad_y} col-span-2')
                    vacation_counter = 0
                    try:
                        for i in range(1, 13):
                            absence_entries = current_user.get_absence(year, i)
                            for day, absence_type in absence_entries.items():
                                # print(day + "." + str(i) + " " + absence_type)
                                if absence_type == "U":
                                    day_in_list = datetime(int(year), int(i), int(day)).strftime("%d.%m.%Y")
                                    ui.markdown(day_in_list).classes(f'border px-{pad_x} py-{pad_y}')
                                    ui.markdown("-1 Tag").classes(f'border px-{pad_x} py-{pad_y} text-center')
                                    vacation_counter += 1
                    except Exception as e:
                        print(str(type(e).__name__) + " " + str(e))
                    ui.markdown("**Resturlaub:**").classes(f'border px-{pad_x} py-{pad_y}')
                    ui.markdown(f'**{str(vacationclaim - vacation_counter)} Tage**').classes(f'border px-{pad_x} py-{pad_y} text-center')


        except Exception as e:
            print(str(type(e).__name__) + " " + str(e))
            if type(e) == UnboundLocalError:
                ui.markdown('#Fehler')
                ui.markdown('Benutzer existiert nicht')
            else:
                ui.markdown('#Fehler')
                ui.markdown(str(type(e)))
                ui.markdown(str(e))
    else:
        login = login_mask(target=f'/api/vacation/{username}/{year}')

@ui.page('/api/absence/{username}/{year}')
def page_overview_absence(username: str, year: int):

    if login_is_valid(username):
        current_user = user(username)
        ui.page_title(f"Abwesenheitsübersicht für {current_user.fullname} für {year}")
        ui.label(datetime.now().strftime('%d.%m.%Y')).classes('absolute top-5 right-5')
        ui.space()
        pageheader(f"Abwesenheitsübersicht für {current_user.fullname} für {year}")

        pad_x = 2
        pad_y = 0

        def absence_calender():

            column_constructor = 'auto '
            for j in range(1, 31):
                column_constructor += "1fr "
            column_constructor += 'auto'

            with ui.grid(columns=column_constructor).classes(f'gap-0 border px-0 py-0') as calendar_grid:
                # Erste Zeile
                ui.space()
                for i in range(1, 32):
                    ui.markdown(str(i)).classes(f'border px-{pad_x} py-{pad_y} text-center')
                # Monate durchgehen
                for month in range(1, 13):
                    for column in range(0, 32):
                        if column == 0:
                            ui.markdown(month_name[month]).classes(f'border px-{pad_x} py-{pad_y} text.center')
                        else:
                            absences = current_user.get_absence(year, month)
                            if str(column) in list(absences):
                                bg_color = absence_entries[absences[str(column)]]['color']
                                text_color = absence_entries[absences[str(column)]]['text-color']
                                ui.markdown(absences[str(column)]).classes(f'border px-{pad_x} py-{pad_y} bg-{bg_color} text-{text_color} text-center')
                            else:
                                if column > monthrange(year, month)[1]:
                                    bg_color = 'gray-500'
                                elif int(current_user.get_day_workhours(year, month, column)) == 0:
                                    bg_color = 'gray-300'
                                elif int(current_user.get_day_workhours(year, month, column)) == -1:
                                    bg_color = 'gray-400'
                                else:
                                    bg_color = 'inherit'
                                ui.space().classes(f'border px-{pad_x} py-{pad_y} bg-{bg_color}')

        absence_calender()

        def absence_table():

            with ui.grid(columns='auto auto').classes(f'gap-0 px-0 py-0'):
                ui.markdown('**Summen**').classes('col-span-2 px-2')
                for type in list(absence_entries):
                    number_of_days = 0
                    ui.markdown(absence_entries[type]["name"]).classes(f'border px-{pad_x} py-{pad_y}')
                    for month in range(1, 13):
                        absences_of_month = current_user.get_absence(year, month)
                        for i in list(absences_of_month):
                            if absences_of_month[i] == type:
                                number_of_days += 1
                    ui.markdown(str(number_of_days)).classes(f'border px-{pad_x} py-{pad_y} text-center')
        absence_table()

    else:
        login = login_mask(target=f'/api/absence/{username}/{year}')

@ui.page('/api/stamp/{api_key}')
def page_api_stamp(api_key: str):
    userlist = list_users()
    user_dict = { }
    # Dictionary mit Usernamen befüllen
    for i in userlist:
        user_dict[i] = ""
    for entry in list(user_dict):
        try:
            temp_user = user(entry)
            user_dict[entry] = temp_user.api_key
        except:
            pass

    found_key = False

    ui.page_title(f'{app_title} {app_version}')

    for user_key, api_value in user_dict.items():
        if api_key == api_value:
            current_user = user(user_key)
            current_user.timestamp()
            found_key = True
            ui.label(f'Zeitstempel {datetime.now().strftime("%H:%M")} für {current_user.fullname} eingetragen')
            break

    if found_key == False:
        ui.label("Keinen passenden Benutzer gefunden")

@app.get("/api/json/{api_key}")
def json_info(api_key: str):
    userlist = list_users()
    user_dict = {}
    # Dictionary mit Usernamen befüllen
    for i in userlist:
        user_dict[i] = ""
    for entry in list(user_dict):
        try:
            temp_user = user(entry)
            user_dict[entry] = temp_user.api_key
        except:
            pass

    found_key = False

    for user_key, api_value in user_dict.items():
        if api_key == api_value:
            current_user = user(user_key)
            now_dt = datetime.now()
            year = now_dt.year
            month = now_dt.month
            day = now_dt.day

            found_key = True
            data = { }
            data["user"] = current_user.username
            if current_user.stamp_status() == status_in:
                data["status"] = 1
            else:
                data["status"] = 0
            absences = current_user.get_absence(now_dt.year, now_dt.month)
            data["absence"] = 0
            if str(now_dt.day) in list(absences):
                data["absence"] = absences[str(now_dt.day)]
            data["time"] = { }
            data["time"]["today"] = current_user.get_worked_time(now_dt.year, now_dt.month, now_dt.day)[0]

            # Arbeitszeit berechnen
            months_time_sum = 0
            for checkday in range(1, day + 1):
                months_time_sum += (int(current_user.get_worked_time(year, month, checkday)[0]) - int(current_user.get_day_workhours(year, month, checkday))*3600)

            time_saldo = months_time_sum + current_user.get_last_months_overtime(year, month)

            data["time"]["overall"] = time_saldo
            data["vacation"] = { }
            data["vacation"]["claim"] = current_user.get_vacation_claim(now_dt.year, now_dt.month, now_dt.day)
            data["vacation"]["used"] = current_user.count_vacation_days(now_dt.year)
            data["vacation"]["remaining"] = data["vacation"]["claim"] - data["vacation"]["used"]
            return data
            break

    if not found_key:
        return { "data": "none"}