from datetime import datetime

import dateutil.easter
from dateutil.easter import *

from nicegui import ui, app, events

from users import *
from definitions import *
from calendar import monthrange
from web_ui import *

import os.path
import os
from stat import S_IREAD, S_IRWXU
import hashlib
import calendar
import locale
import segno

@ui.page('/admin')
def page_admin():
    ui.page_title(f"{app_title} {app_version}")
    data = load_adminsettings()

    try:
        browser_cookie = app.storage.user['admin_authenticated']
    except:
        browser_cookie = False

    # Adminseite
    if browser_cookie:
        pageheader("Administration")

        def admin_logout():
            app.storage.user.pop("admin_authenticated", None)
            ui.navigate.to("/")

        ui.button("Logout", on_click=admin_logout)

        with ui.tabs() as tabs:

            time_overview = ui.tab('Zeitübersichten')
            settings = ui.tab('Einstellungen')
            users = ui.tab('Benutzer')

        userlist = [ ]

        def update_userlist():
            nonlocal userlist
            userlist = list_users()

        update_userlist()

        with (((ui.tab_panels(tabs, value=time_overview)))):

            with ui.tab_panel(time_overview):
                ui.markdown("##Übersichten")

                # Tabelle konstruieren
                with ui.card():

                    with ui.row() as timetable_header:
                        year_binder = ValueBinder()
                        month_binder = ValueBinder()

                        def update_months():
                            current_user = user(time_user.value)
                            available_months = current_user.get_months(year_binder.value)
                            available_months_dict = { }

                            for element in available_months:
                                available_months_dict[element] = calendar.month_name[int(element)]

                            select_month.clear()
                            select_month.set_options(available_months_dict)
                            select_month.value = list(available_months)[0]

                        def update_user():
                            current_user = user(time_user.value)
                            available_years = current_user.get_years()
                            try:
                                select_year.clear()
                                select_year.set_options(available_years)

                                try:
                                    select_year.value = str(datetime.datetime.now().year)
                                except:
                                    select_year.value = list(available_years)[0]
                                try:
                                    select_month.value = datetime.datetime.now().month
                                except:
                                    select_month.value = list(available_months)[0]
                            except NameError:
                                pass

                        ui.markdown("Benutzer:")

                        time_user = ui.select(options=userlist, on_change=update_user)
                        time_user.value = userlist[0]
                        user_to_select_for_start = userlist[0]

                        current_year = datetime.datetime.now().year
                        current_month = datetime.datetime.now().month
                        current_user = user(user_to_select_for_start)
                        available_years = current_user.get_years()
                        available_months = current_user.get_months(current_year)
                        available_months_dict = { }

                        for element in available_months:
                            available_months_dict[element] = calendar.month_name[int(element)]

                        if current_month in available_months:
                            set_month = current_month
                        else:
                            set_month = available_months[0]

                        if str(current_year) in available_years:
                            set_year = str(current_year)
                        else:
                            set_year = (available_years[0])

                        select_month = ui.select(options=available_months_dict, value=set_month).bind_value_to(month_binder, 'value')
                        select_year = ui.select(options=available_years, value=set_year, on_change=update_months).bind_value_to(year_binder, 'value')

                    month_header = ui.markdown(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")

                    # Tabelle aufbauen
                    @ui.refreshable
                    def timetable():
                        with ui.card() as calendar_card:
                            def update_month_and_year():
                                current_user = user(time_user.value)
                                # Archivstatus
                                days_with_errors = current_user.archiving_validity_check(int(select_year.value), int(select_month.value))
                                with ui.grid(columns='auto auto auto 1fr 1fr 1fr 1fr') as table_grid:
                                    if int(select_month.value) > 1:
                                        archive_status = current_user.get_archive_status(int(select_year.value),
                                                                                         int(select_month.value))
                                    else:
                                        archive_status = current_user.get_archive_status(int(select_year.value) - 1, 12)

                                    def revoke_archive_status():
                                        def revoke_status():
                                            filestring = f"{current_user.userfolder}/{int(select_year.value)}-{int(select_month.value)}"
                                            filename = f"{filestring}.txt"
                                            os.chmod(filename, S_IRWXU)
                                            filename = f"{filestring}.json"
                                            os.chmod(filename, S_IRWXU)
                                            with open(filename, 'r') as json_file:
                                                data = json.load(json_file)
                                            data["archived"] = 0

                                            json_dict = json.dumps(data)

                                            with open(filename, "w") as outputfile:
                                                outputfile.write(json_dict)
                                            timetable.refresh()
                                            dialog.close()

                                        with ui.dialog() as dialog, ui.card():
                                            ui.label("Soll der Archivstatus für den aktuellen Monat aufgehoben werden, damit Änderungen vorgenommen werden können?")
                                            with ui.grid(columns=2):
                                                ui.button("Ja", on_click=revoke_status)
                                                ui.button("Nein", on_click=dialog.close)
                                        dialog.open()

                                    if archive_status == True:
                                        with ui.row().classes('text-right col-span-7 justify-center'):
                                            ui.button("Archiviert", on_click=revoke_archive_status).classes('bg-transparent text-black')
                                            ui.separator()
                                            calendar_card.classes('bg-yellow')
                                    else:
                                        calendar_card.classes('bg-white')
                                    # Überschriften
                                    ui.markdown("**Datum**")
                                    ui.markdown("**Buchungen**")
                                    ui.space()
                                    ui.markdown("**Ist**")
                                    ui.markdown("**Soll**")
                                    ui.markdown("**Saldo**")
                                    ui.space()

                                    timestamps = current_user.get_timestamps(year=select_year.value, month=select_month.value)
                                    user_absent = current_user.get_absence(year=select_year.value, month=select_month.value)
                                    # Dictionary für sortierte Timestamps
                                    timestamps_dict = { }
                                    # Dictionary mit zunächst leeren Tageinträgen befüllen
                                    for day in range(1, monthrange(int(select_year.value), int(select_month.value))[1] + 1):
                                        # Jeder Tag bekommt eine leere Liste
                                        timestamps_dict[day] = [ ]

                                    # Alle Timestamps durchgehen und sie den Dictionaryeinträgen zuordnen:
                                    for stamp in timestamps:
                                        day_of_month_of_timestamp = int(datetime.datetime.fromtimestamp(int(stamp)).strftime("%-d"))
                                        timestamps_dict[day_of_month_of_timestamp].append(int(stamp))

                                    general_saldo = 0

                                    for day in list(timestamps_dict):
                                        # Datum für Tabelle konstruieren
                                        day_in_list = datetime.datetime(int(select_year.value), int(select_month.value), day)
                                        class_content = ""
                                        if day_in_list.date() == datetime.datetime.now().date():
                                            class_content = 'font-bold text-red-700 uppercase'
                                        ui.markdown(f"{day_in_list.strftime('%a')}., {day}. {calendar.month_name[int(select_month.value)]}").classes(class_content)

                                        # Buchungen

                                        with ui.row():
                                            def delete_absence(day, absence_type):
                                                def execute_deletion():
                                                    current_user.del_absence(select_year.value, select_month.value, day)
                                                    calendar_card.clear()
                                                    update_month_and_year()
                                                    dialog.close()
                                                    ui.notify("Abwesenheitseintrag gelöscht")
                                                with ui.dialog() as dialog, ui.card():
                                                    ui.markdown(f'''Soll der Eintrag **{absence_type}** für den **{day}. {calendar.month_name[int(select_month.value)]} {select_year.value}** gelöscht werden?
    
Dies kann nicht rückgängig gemacht werden!''')
                                                    with ui.grid(columns=3):
                                                        ui.button("Ja", on_click=execute_deletion)
                                                        ui.space()
                                                        ui.button("Nein", on_click=dialog.close)
                                                dialog.open()

                                            try:
                                                for i in list(user_absent):
                                                    if int(i) == day:
                                                        absence_button = ui.button(absence_entries[user_absent[i]]["name"], on_click=lambda i=i, day=day: delete_absence(day, absence_entries[user_absent[i]]["name"])).props(f'color={absence_entries[user_absent[i]]["color"]}')
                                                        if archive_status:
                                                            absence_button.disable()
                                            except:
                                                pass

                                            day_type = ui.markdown("Kein Arbeitstag")
                                            day_type.set_visibility(False)

                                            # Hier werden nur die Tage mit Timestamps behandelt
                                            if len(timestamps_dict[day]) > 0:
                                                timestamps_dict[day].sort()

                                                def edit_entry(t_stamp, day):

                                                    with ui.dialog() as edit_dialog, ui.card():
                                                        ui.markdown("**Eintrag bearbeiten**")
                                                        timestamp = datetime.datetime.fromtimestamp(int(t_stamp))
                                                        input_time = ui.time().props('format24h now-btn').classes('w-full justify-center')

                                                        input_time.value = timestamp.strftime('%H:%M')

                                                        def save_entry(day):
                                                            nonlocal t_stamp
                                                            t_stamp = f"{t_stamp}\n"
                                                            position = timestamps.index(t_stamp)
                                                            new_time_stamp = datetime.datetime(int(select_year.value),
                                                                                               int(select_month.value), day,
                                                                                               int(input_time.value[:2]),
                                                                                               int(input_time.value[-2:]))
                                                            timestamps[position] = str(
                                                                int(new_time_stamp.timestamp())) + "\n"

                                                            current_user = user(time_user.value)
                                                            current_user.write_edited_timestamps(timestamps,
                                                                                                 select_year.value,
                                                                                                 select_month.value)
                                                            edit_dialog.close()
                                                            calendar_card.clear()
                                                            update_month_and_year()
                                                            month_header.set_content(
                                                                f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
                                                            ui.notify("Eintrag gespeichert")

                                                        def del_entry():
                                                            nonlocal t_stamp
                                                            t_stamp = f"{t_stamp}\n"
                                                            timestamps.remove(t_stamp)
                                                            timestamps.sort()
                                                            current_user = user(time_user.value)
                                                            current_user.write_edited_timestamps(timestamps,
                                                                                                 select_year.value,
                                                                                                 select_month.value)
                                                            edit_dialog.close()
                                                            calendar_card.clear()
                                                            update_month_and_year()
                                                            month_header.set_content(
                                                                f"###Buchungen für {calendar.month_name[int(select_month.value)]} {select_year.value}")
                                                            ui.notify("Eintrag gelöscht")

                                                        with ui.row():
                                                            ui.button("Speichern",
                                                                      on_click=lambda day=day: save_entry(day))
                                                            ui.button("Löschen", on_click=del_entry)
                                                            ui.button("Abbrechen", on_click=edit_dialog.close)

                                                    edit_dialog.open()
                                                for i in range(0, len(timestamps_dict[day]), 2):
                                                    try:
                                                        temp_pair = [ timestamps_dict[day][i] , timestamps_dict[day][i+1] ]
                                                        with ui.card().classes('bg-inherit'):
                                                            with ui.row():
                                                                for j in temp_pair:
                                                                    timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(j)).strftime('%H:%M'), on_click=lambda t_stamp=j, day=day: edit_entry(t_stamp, day))
                                                                    if archive_status:
                                                                        timestamp_button.disable()
                                                    except Exception as e:
                                                        if len(timestamps_dict[day]) % 2 != 0:
                                                            with ui.card().classes('bg-inherit'):
                                                                timestamp_button = ui.button(datetime.datetime.fromtimestamp(int(timestamps_dict[day][i])).strftime('%H:%M'), on_click=lambda t_stamp=timestamps_dict[day][i], day=day: edit_entry(t_stamp, day))
                                                                if archive_status:
                                                                    timestamp_button.disable()
                                        with ui.row():
                                            # Fehlerhinweis
                                            if day in days_with_errors:
                                                ui.icon('warning', color='red').tooltip("Keine Schlussbuchung").classes('text-2xl')

                                            # Notizen anzeigen
                                            days_notes = current_user.get_day_notes(select_year.value, select_month.value, day)
                                            if days_notes != { }:
                                                with ui.icon('o_description').classes('text-2xl'):
                                                    with ui.tooltip():
                                                        with ui.grid(columns='auto auto'):
                                                            for username, text in days_notes.items():
                                                                admins_name = load_adminsettings()["admin_user"]
                                                                if username == admins_name:
                                                                    ui.markdown('Administrator:')
                                                                else:
                                                                    ui.markdown(current_user.fullname)
                                                                ui.markdown(text)
                                            else:
                                                ui.space()

                                        # Arbeitszeit Ist bestimmen

                                        timestamps_of_this_day = []

                                        # Suche mir alle timestamps für diesen Tag
                                        for i in timestamps:
                                            actual_timestamp = datetime.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

                                            ui.markdown(convert_seconds_to_hours(time_sum)).classes('text-right')
                                        else:
                                            ui.markdown("Kein")

                                        # Arbeitszeitsoll bestimmen

                                        hours_to_work = int(current_user.get_day_workhours(select_year.value, select_month.value, day))
                                        if hours_to_work < 0:
                                            ui.space()
                                            day_type.content="Kein Arbeitsverhältnis"
                                            day_type.set_visibility(True)
                                        else:
                                            ui.markdown(f"{convert_seconds_to_hours(int(hours_to_work) * 3600)}").classes('text-right')
                                        if int(hours_to_work) == 0:
                                            day_type.content = "**Kein Arbeitstag**"
                                            day_type.set_visibility(True)

                                        if day_in_list.strftime("%Y-%m-%d") in data["holidays"]:
                                            day_type.content = f'**{data["holidays"][day_in_list.strftime("%Y-%m-%d")]}**'

                                        # Saldo für den Tag berechnen

                                        if time.time() > day_in_list.timestamp():

                                            time_duty = int(current_user.get_day_workhours(select_year.value, select_month.value, day)) * 3600
                                            if time_duty < 0:
                                                ui.space()
                                            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
                                                ui.markdown(convert_seconds_to_hours(saldo)).classes('text-right')
                                        else:
                                            ui.markdown("-").classes('text-center')

                                        def add_entry(day):
                                            with ui.dialog() as add_dialog, ui.card():
                                                ui.markdown("###Eintrag hinzufügen")
                                                input_time = ui.time().classes('w-full justify-center')

                                                def add_entry_save():
                                                    if input_time.value == None:
                                                        ui.notify("Bitte eine Uhrzeit auswählen.")
                                                        return

                                                    new_time_stamp = datetime.datetime(int(year_binder.value),
                                                                                       int(month_binder.value), day,
                                                                                       int(input_time.value[:2]),
                                                                                       int(input_time.value[-2:])).timestamp()
                                                    current_user = user(time_user.value)
                                                    current_user.timestamp(stamptime=int(new_time_stamp))
                                                    calendar_card.clear()
                                                    update_month_and_year()
                                                    add_dialog.close()
                                                    ui.notify("Eintrag hinzugefügt")
                                                with ui.grid(columns=3):
                                                    ui.button("Speichern", on_click=add_entry_save)
                                                    ui.space()
                                                    ui.button("Abbrechen", on_click=add_dialog.close)
                                            add_dialog.open()
                                            add_dialog.move(calendar_card)

                                        def add_absence(absence_type, day):
                                            with ui.dialog() as dialog, ui.card().classes('w-[350px]'):
                                                ui.markdown(f'Für welchen Zeitraum soll *{absence_entries[absence_type]["name"]}* eingetragen werden?').classes('w-full')
                                                absence_dates = ui.date().props('range today-btn').classes('w-full justify-center')
                                                absence_dates._props['locale'] = {'daysShort': ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'],
                                                                                  'months': ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
                                                                                  'monthsShort': ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']}
                                                absence_dates._props['title'] = absence_entries[absence_type]["name"]
                                                absence_dates._props['minimal'] = True

                                                if day < 10:
                                                    day = f"0{str(day)}"
                                                else:
                                                    day = str(day)
                                                if int(select_month.value) < 10:
                                                    month = f"0{select_month.value}"
                                                else:
                                                    month = select_month.value
                                                absence_dates.value = f"{select_year.value}-{month}-{day}"

                                                def add_absence_save():
                                                    # Bei nur einem Datum, direkt schreiben
                                                    if isinstance(absence_dates.value, str):
                                                        absence_date = absence_dates.value.split("-")
                                                        current_user.update_absence(absence_date[0], absence_date[1], absence_date[2], absence_type)
                                                        current_sel_month = select_month.value
                                                        current_sel_year = select_year.value
                                                        update_user()
                                                        update_months()
                                                        select_year.value = current_sel_year
                                                        select_month.value = current_sel_month
                                                        calendar_card.clear()
                                                        update_month_and_year()

                                                    # Bei Zeitbereich, aufteilen
                                                    elif isinstance(absence_dates.value, dict):
                                                        start_date = absence_dates.value["from"]
                                                        end_date = absence_dates.value["to"]
                                                        start_date = start_date.split("-")
                                                        end_date = end_date.split("-")

                                                        start_year = int(start_date[0])
                                                        end_year = int(end_date[0])
                                                        start_month = int(start_date[1])
                                                        end_month = int(end_date[1])
                                                        start_day = int(start_date[2])
                                                        end_day = int(end_date[2])

                                                        start_date = datetime.datetime(start_year, start_month, start_day)
                                                        end_date = datetime.datetime(end_year, end_month, end_day)
                                                        actual_date = start_date

                                                        while actual_date <= end_date:
                                                            absences = current_user.get_absence(actual_date.year, actual_date.month)

                                                            if str(actual_date.day) in list(absences):
                                                                current_user.del_absence(actual_date.year, actual_date.month, actual_date.day)
                                                                ui.notify(f"Eintrag {absence_entries[absences[str(actual_date.day)]]['name']} am {actual_date.day}.{actual_date.month}.{actual_date.year} überschrieben.")
                                                            current_user.update_absence(actual_date.year, actual_date.month, actual_date.day, absence_type)

                                                            actual_date = actual_date + datetime.timedelta(days=1)
                                                        clear_card()
                                                        ui.notify("Einträge vorgenomomen")
                                                    dialog.close()


                                                with ui.grid(columns=3).classes('w-full justify-center'):
                                                    ui.button("Speichern", on_click=add_absence_save)
                                                    ui.space()
                                                    ui.button("Abbrechen", on_click=dialog.close)

                                                dialog.open()
                                                dialog.move(calendar_card)

                                        def edit_notes(day):
                                            notes = current_user.get_day_notes(select_year.value, select_month.value, day)
                                            def del_note_entry(user):
                                                del(notes[user])
                                                username_labels[user].delete()
                                                note_labels[user].delete()
                                                del_buttons[user].delete()

                                            def save_notes():
                                                if not note_labels["admin"].is_deleted:
                                                    notes["admin"] = note_labels["admin"].value
                                                current_user.write_notes(select_year.value, select_month.value, day, notes)
                                                timetable.refresh()
                                                dialog.close()

                                            with ui.dialog() as dialog, ui.card():
                                                # Notizen
                                                username_labels = { }
                                                note_labels = { }
                                                del_buttons = { }

                                                ui.markdown(f'**Notizen für {day}.{current_month}.{current_year}**')
                                                with ui.grid(columns='auto auto auto'):
                                                    admin_settings = load_adminsettings()
                                                    # Beschreibungsfeld für Admin
                                                    username_labels["admin"] = ui.markdown("Administrator:")
                                                    # Textarea für Admin
                                                    note_labels["admin"] = ui.textarea()
                                                    del_buttons["admin"] = ui.button(icon='remove', on_click=lambda user="admin": del_note_entry(user))

                                                    for name, text in notes.items():
                                                        if name != "admin":
                                                            username_labels["user"] = ui.markdown(current_user.fullname)
                                                            note_labels["user"] = ui.markdown(text)
                                                            del_buttons["user"] = ui.button(icon='remove', on_click=lambda user="user": del_note_entry(user))

                                                with ui.row():
                                                    ui.button("OK", on_click=save_notes)
                                                    ui.button("Abbrechen", on_click=dialog.close)
                                            dialog.open()
                                            dialog.move(calendar_card)

                                        with ui.button(icon='menu') as menu_button:
                                            with ui.menu() as menu:
                                                menu_item = ui.menu_item("Zeiteintrag hinzufügen", lambda day=day: add_entry(day))
                                                if archive_status:
                                                    menu_item.disable()
                                                if datetime.datetime.now().day < day:
                                                    menu_item.disable()
                                                    menu_item.tooltip("Kann keine Zeiteinträge für die Zukunft vornehmen.")
                                                ui.separator()
                                                menu_item = ui.menu_item("Notizen bearbeiten", lambda day=day: edit_notes(day))
                                                if archive_status:
                                                    menu_item.disable()
                                                ui.separator()
                                                for i in list(absence_entries):
                                                    menu_item = ui.menu_item(f"{absence_entries[i]['name']} eintragen", lambda absence_type=i, day=day: add_absence(absence_type, day))
                                                    if archive_status:
                                                        menu_item.disable()
                                                    if str(day) in list(user_absent):
                                                        menu_item.disable()
                                        if archive_status:
                                            menu_button.disable()

                                        #ui.button("Eintrag hinzufügen", on_click=lambda day=day: add_entry(day))

                                    #4x leer und dann Gesamtsaldo
                                    ui.space().classes('col-span-5')
                                    ui.markdown(f"{convert_seconds_to_hours(general_saldo)}").classes('text-right')
                                    ui.markdown("Stunden aus Vormonat").classes('col-span-5 text-right')
                                    last_months_overtime = current_user.get_last_months_overtime(select_year.value, select_month.value)
                                    ui.markdown(f"{convert_seconds_to_hours(last_months_overtime)}").classes('text-right')
                                    ui.markdown("Gesamtsaldo").classes('col-span-5 text-right')
                                    ui.markdown(f"**<ins>{convert_seconds_to_hours(general_saldo + last_months_overtime)}</ins>**").classes('text-right')

                                table_grid.move(calendar_card)

                            update_month_and_year()

                            def clear_card():
                                calendar_card.clear()
                                button_update.delete()
                                update_month_and_year()
                                current_user = user(time_user.value)
                                month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")

                            month_header.set_content(f"###Buchungen für **{current_user.fullname}** für **{calendar.month_name[int(select_month.value)]} {select_year.value}**")
                    timetable()
                    button_update = ui.button("Aktualisieren", on_click=timetable.refresh)
                    button_update.move(timetable_header)

            with ui.tab_panel(settings):
                with ui.card():
                    ui.markdown("**Administrationsbenutzer:**")
                    with ui.grid(columns=2):
                        def save_admin_settings():
                            output_dict = { }
                            output_dict["admin_user"] = admin_user.value
                            if admin_password.value != "":
                                output_dict["admin_password"] = hash_password(admin_password.value)
                            else:
                                output_dict["admin_password"] = data["admin_password"]
                            output_dict["port"] = port.value
                            output_dict["secret"] = secret
                            output_dict["holidays"] = data["holidays"]
                            json_dict = json.dumps(output_dict, indent=4)
                            with open(f"{scriptpath}/{usersettingsfilename}", "w") as outputfile:
                                outputfile.write(json_dict)
                            if int(old_port) != int(port.value):
                                with ui.dialog() as dialog, ui.card():
                                    ui.markdown("Damit die Porteinstellungen wirksam werden, muss der Server neu gestartet werden.")
                                    ui.button("OK", on_click=lambda: dialog.close())
                                dialog.open()
                            ui.notify("Einstellungen gespeichert")
                            timetable.refresh()


                        ui.markdown("Benutzername des Adminstrators")
                        admin_user = ui.input()
                        admin_user.value = data["admin_user"]
                        ui.markdown("Passwort des Administrators")
                        admin_password = ui.input(password=True)

                        secret = data["secret"]

                with ui.card():
                    ui.markdown("**Systemeinstellungen:**")
                    with ui.grid(columns=2):

                        ui.markdown("Port:")
                        port = ui.input()
                        old_port = data["port"]
                        port.value = old_port

                def holiday_section():
                    with ui.card():
                        ui.markdown('**Feiertage:**')

                        reset_visibility = ValueBinder()
                        reset_visibility.value = False

                        def new_holiday_entry():
                            def add_holiday_to_dict():
                                year_from_picker = int(datepicker.value.split("-")[0])
                                month_from_picker = int(datepicker.value.split("-")[1])
                                day_from_picker = int(datepicker.value.split("-")[2])
                                for i in range(0, int(repetition.value)):
                                    repetition_date_dt = datetime.datetime(year_from_picker + i, month_from_picker, day_from_picker)
                                    date_entry = repetition_date_dt.strftime('%Y-%m-%d')
                                    data["holidays"][date_entry] = description.value
                                    holiday_buttons_grid.refresh()
                                reset_visibility.value = True
                                dialog.close()

                            with ui.dialog() as dialog, ui.card():
                                with ui.grid(columns='auto auto'):
                                    ui.markdown('Geben Sie den neuen Feiertag ein:').classes('col-span-2')
                                    datepicker = ui.date(value=datetime.datetime.now().strftime('%Y-%m-%d')).classes('col-span-2')
                                    description = ui.input('Beschreibung').classes('col-span-2')
                                    repetition = ui.number('Für Jahre wiederholen', value=1, min=1, precision=0).classes('col-span-2')
                                    ui.button("OK", on_click=add_holiday_to_dict)
                                    ui.button('Abbrechen', on_click=dialog.close)
                            dialog.open()

                        @ui.refreshable
                        def holiday_buttons_grid():

                            holidays = list(data["holidays"])
                            holidays.sort()

                            year_list = []

                            # Jahresliste erzeugen
                            for i in holidays:
                                i_split = i.split("-")
                                year = int(i_split[0])
                                year_list.append(year)

                            year_list = list(set(year_list))
                            year_dict = {}

                            # Jahresdictionary konstruieren
                            for i in year_list:
                                year_dict[i] = []

                            for i in holidays:
                                i_split = i.split("-")
                                year = int(i_split[0])
                                month = int(i_split[1])
                                day = int(i_split[2])
                                date_dt = datetime.datetime(year, month, day)
                                year_dict[year].append(date_dt)

                            def del_holiday_entry(entry):
                                del(data['holidays'][entry.strftime('%Y-%m-%d')])
                                reset_visibility.value = True
                                holiday_buttons_grid.refresh()

                            def defined_holidays():
                                with ui.dialog() as dialog, ui.card():
                                    ui.markdown("Bitte wählen Sie aus, welche Feiertage eingetragen werden sollen. Vom Osterdatum abhängige Feiertage werden für die verschiedenen Jahre berechnet.:")
                                    with ui.grid(columns='auto auto'):
                                        with ui.column().classes('gap-0'): # Auswahlen für Feiertage

                                            checkbox_classes = 'py-0'

                                            new_year = ui.checkbox("Neujahr (1. Januar)").classes(checkbox_classes)
                                            heilige_drei_koenige = ui.checkbox("Heilige Drei Könige (6. Januar)").classes(checkbox_classes)
                                            womens_day = ui.checkbox("Internationaler Frauentag (8. März)").classes(checkbox_classes)
                                            gruendonnerstag = ui.checkbox("Gründonnerstag (berechnet)").classes(checkbox_classes)
                                            karfreitag = ui.checkbox("Karfreitag (berechnet").classes(checkbox_classes)
                                            easter_sunday = ui.checkbox("Ostersonntag (berechnet)").classes(checkbox_classes)
                                            easter_monday = ui.checkbox("Ostermontag (berechnet)").classes(checkbox_classes)
                                            first_of_may = ui.checkbox("Tag der Arbeit (1. Mai)").classes(checkbox_classes)
                                            liberation_day = ui.checkbox("Tag der Befreiung (8. Mai)").classes(checkbox_classes)
                                            ascension_day = ui.checkbox("Christi Himmelfahrt (berechnet)").classes(checkbox_classes)
                                            whitsun_sunday = ui.checkbox("Pfingssonntag (berechnet)").classes(checkbox_classes)
                                            whitsun_monday = ui.checkbox("Pfingsmontag (berechnet)").classes(checkbox_classes)
                                            fronleichnam = ui.checkbox("Fronleichnam (berechnet)").classes(checkbox_classes)
                                            peace_party = ui.checkbox("Friedensfest (Augsburg - 8. August)").classes(checkbox_classes)
                                            mary_ascension = ui.checkbox("Mariä Himmelfahrt (15. August)").classes(checkbox_classes)
                                            childrens_day = ui.checkbox("Weltkindertag (20. September)").classes(checkbox_classes)
                                            unity_day = ui.checkbox("Tag der deutschen Einheit (3. Oktober)").classes(checkbox_classes)
                                            reformation_day = ui.checkbox("Reformationstag (30. Oktober)").classes(checkbox_classes)
                                            all_hallows = ui.checkbox("Allerheiligen (1. November)").classes(checkbox_classes)
                                            praying_day = ui.checkbox("Buß- und Bettag (berechnet)").classes(checkbox_classes)
                                            christmas_day = ui.checkbox("1. Weihnachtsfeiertag (25. Dezember)").classes(checkbox_classes)
                                            boxing_day = ui.checkbox("2. Weihnachtsfeiertag (26. Dezember)").classes(checkbox_classes)

                                        def enter_holidays():

                                            for year in range (int(starting_year.value), int(end_year.value) + 1):
                                                ostersonntag = dateutil.easter.easter(year)
                                                if new_year.value:
                                                    data["holidays"][f"{year}-01-01"] = f"Neujahr"
                                                if heilige_drei_koenige.value:
                                                    data["holidays"][f"{year}-01-06"] = f"Hl. Drei Könige"
                                                if womens_day.value:
                                                    data["holidays"][f"{year}-03-08"] = f"Intern. Frauentag"
                                                if gruendonnerstag.value:
                                                    datum_dt = ostersonntag - datetime.timedelta(days=3)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Gründonnerstag"
                                                if karfreitag.value:
                                                    datum_dt = ostersonntag - datetime.timedelta(days=2)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Karfreitag"
                                                if easter_sunday.value:
                                                    datum_dt = ostersonntag
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = "Ostersonntag"
                                                if easter_monday.value:
                                                    datum_dt = ostersonntag + datetime.timedelta(days=1)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = "Ostermontag"
                                                if first_of_may.value:
                                                    data["holidays"][f"{year}-05-01"] = f"Tag der Arbeit"
                                                if liberation_day.value:
                                                    data["holidays"][f"{year}-05-08"] = f"Tag der Befreiung"
                                                if ascension_day.value:
                                                    datum_dt = ostersonntag + datetime.timedelta(days=39)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Christi Himmelfahrt"
                                                if whitsun_sunday.value:
                                                    datum_dt = ostersonntag + datetime.timedelta(days=49)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Pfingssonntag"
                                                if whitsun_monday.value:
                                                    datum_dt = ostersonntag + datetime.timedelta(days=49)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Pfingstmontag"
                                                if fronleichnam.value:
                                                    datum_dt = ostersonntag + datetime.timedelta(days=60)
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Fronleichnam"
                                                if peace_party.value:
                                                    data["holidays"][f"{year}-08-08"] = f"Friedensfest"
                                                if mary_ascension.value:
                                                    data["holidays"][f"{year}-08-15"] = f"Mariä Himmelfahrt"
                                                if childrens_day.value:
                                                    data["holidays"][f"{year}-09-20"] = f"Intern. Kindertag"
                                                if unity_day.value:
                                                    data["holidays"][f"{year}-10-03"] = f"Tag der deutschen Einheit"
                                                if reformation_day.value:
                                                    data["holidays"][f"{year}-10-30"] = f"Reformationstag"
                                                if all_hallows.value:
                                                    data["holidays"][f"{year}-11-01"] = f"Allerheiligen"
                                                if praying_day.value:
                                                    starting_day = datetime.datetime(year, 11 ,23)
                                                    for i in range(1, 8):
                                                        test_day = starting_day - datetime.timedelta(days=-i)
                                                        if test_day.weekday() == 2:
                                                            datum_dt = test_day
                                                            break
                                                    datum = datum_dt.strftime("%Y-%m-%d")
                                                    data["holidays"][f"{datum}"] = f"Bu0- und Bettag"
                                                if christmas_day.value:
                                                    data["holidays"][f"{year}-12-25"] = f"1. Weihnachtsfeiertag"
                                                if boxing_day.value:
                                                    data["holidays"][f"{year}-12-26"] = f"2. Weihnachtsfeiertag"
                                                reset_visibility.value = True
                                                dialog.close()
                                                holiday_buttons_grid.refresh()

                                        with ui.column():
                                            starting_year = ui.number(value=datetime.datetime.now().year, label="Startjahr")
                                            end_year = ui.number(value=starting_year.value, label="Endjahr")
                                        with ui.row():
                                            ui.button("Anwenden", on_click=enter_holidays)
                                            ui.button("Abbrechen", on_click=dialog.close)
                                dialog.open()

                            def reset_holidays():
                                old_data = load_adminsettings()
                                data["holidays"] = old_data["holidays"]
                                reset_visibility.value = False
                                holiday_buttons_grid.refresh()

                            with ui.grid(columns='auto auto'):
                                ui.space()
                                with ui.row():
                                    ui.button("Gesetzliche Feiertage eintragen", on_click=defined_holidays)
                                    ui.button("Eigener Eintrag", on_click=new_holiday_entry)
                                    ui.button("Zurücksetzen", icon="undo", on_click=reset_holidays).bind_visibility_from(reset_visibility, 'value').classes('bg-red')

                                ui.separator().classes('col-span-2')
                                for year_entry in year_list:
                                    ui.markdown(f"{str(year_entry)}:")
                                    with ui.row():
                                        for entry in year_dict[year_entry]:
                                            date_label = entry.strftime("%d.%m.")
                                            ui.button(f"{data['holidays'][entry.strftime('%Y-%m-%d')]} ({date_label})", on_click=lambda entry=entry: del_holiday_entry(entry)).classes('text-sm')
                        holiday_buttons_grid()

                holiday_section()

                ui.button("Speichern", on_click=save_admin_settings)

            with ui.tab_panel(users):
                ui.markdown("###Benutzerverwaltung")
                workhours = [ ]

                with ui.row():

                    def user_selection_changed():
                        try:
                            if user_selection.value != None:
                                current_user = user(user_selection.value)
                                username_input.value = current_user.username
                                fullname_input.value = current_user.fullname
                                #password_input.value = current_user.password
                                usersettingscard.visible = True

                                api_key_input.value = current_user.api_key

                                api_link_column.clear()
                                for i in app.urls:
                                    with ui.row() as link_row:
                                        link_string = f'{i}/api/stamp/{api_key_input.value}'
                                        link = ui.link(f'{i}/api/stamp/"API-Schlüssel"', link_string).tooltip(("ACHTUNG: Klick auf den Link löst Stempelaktion aus!"))
                                        qr = segno.make_qr(link_string).svg_data_uri()
                                        with ui.image(qr).classes('w-1/3'):
                                            with ui.tooltip().classes('bg-white border'):
                                                ui.image(qr).classes('w-64')

                                    link_row.move(api_link_column)

                                workhours_select.clear()
                                workhour_list = list(current_user.workhours)
                                workhour_list.sort()
                                workhours_select.set_options(workhour_list)
                                workhours_select.value = workhour_list[0]
                                workinghourscard.visible = True

                                user_photo.set_source(current_user.photofile)
                                user_photo.force_reload()

                                user_photo.set_visibility(os.path.exists(current_user.photofile))
                                delete_button.set_visibility(os.path.exists(current_user.photofile))

                        except:
                            pass

                        # workhours_selection_changed(list(current_user.workhours)[0])

                    def workhours_selection_changed():
                        if workhours_select.value != None:
                            current_user = user(user_selection.value)
                            selected_workhours = current_user.workhours[workhours_select.value]

                            for key, hours in selected_workhours.items():
                                try:
                                    days[int(key)-1].value = hours
                                except:
                                    if key == 0:
                                        days[6].value = hours
                                    elif key == "vacation":
                                        vacation_input.value = hours

                    def save_user_settings():
                        def save_settings():
                            current_user = user(user_selection.value)
                            current_user.username = username_input.value
                            current_user.fullname = fullname_input.value
                            current_user.password = hash_password(password_input.value)
                            current_user.api_key = api_key_input.value
                            current_user.write_settings()
                            password_input.value = ""
                            userlist = list_users()
                            userlist.sort()
                            user_selection.clear()
                            user_selection.set_options(userlist)
                            user_selection.value = current_user.username
                            user_selection_changed()
                            dialog.close()
                            ui.notify("Einstellungen gespeichert")

                        with ui.dialog() as dialog, ui.card():
                            if user_selection.value != username_input.value:
                                ui.markdown("**Benutzername wurde geändert.**")
                                ui.markdown(f"Benutzerdaten werden in den neuen Ordner {username_input.value}")
                            ui.markdown("Sollen die Einstellungen gespeichert werden?")
                            with ui.row():
                                ui.button("Speichern", on_click=save_settings)
                                ui.button("Abbrechen", on_click=dialog.close)
                        dialog.open()

                    def del_user():
                        current_user = user(user_selection.value)

                        def del_definitely():
                            if current_user.username == time_user.value:
                                if userlist.index(current_user.username) == 0:
                                    time_user.value = userlist[1]
                                else:
                                    time_user.value = userlist[0]
                            current_user.del_user()
                            #userlist = list_users()
                            #userlist.sort()
                            #user_selection.clear()
                            #user_selection.set_options(userlist)
                            #user_selection.value = userlist[0]
                            update_userlist()
                            time_user.set_options(userlist)
                            user_ui.refresh()
                            dialog.close()
                            ui.notify("Benutzer gelöscht")

                        with ui.dialog() as dialog, ui.card():
                            ui.markdown(f"Soll der Benutzer *{current_user.username}* gelöscht werden?")
                            ui.markdown("**Dies kann nicht rückgängig gemacht werden?**")
                            with ui.row():
                                ui.button("Löschen", on_click=del_definitely)
                                ui.button("Abbrechen", on_click=dialog.close)

                        dialog.open()

                    def save_workhours():
                        def save_settings():
                            current_user = user(user_selection.value)
                            construct_dict = { }
                            for i in range(7):
                                if i < 7:
                                    construct_dict[i+1] = days[i].value
                                elif i == 7:
                                    construct_dict[0] = days[i].value

                            construct_dict["vacation"] = vacation_input.value
                            current_user.workhours[workhours_select.value] = construct_dict
                            current_user.write_settings()
                            dialog.close()
                            ui.notify("Einstellungen gespeichert")

                        with ui.dialog() as dialog, ui.card():
                            ui.markdown("Sollen die Änderungen an den Arbeitsstunden und/oder Urlaubstagen gespeichert werden?")
                            with ui.row():
                                ui.button("Speichern", on_click=save_settings)
                                ui.button("Abrrechen", on_click=dialog.close)
                        dialog.open()

                    def delete_workhour_entry():
                        def delete_entry():
                            current_user = user(user_selection.value)
                            del current_user.workhours[workhours_select.value]
                            current_user.write_settings()
                            workhour_list = list(current_user.workhours)
                            workhours_select.clear()
                            workhours_select.set_options(workhour_list)
                            workhours_select.set_value(workhour_list[-1])

                            #workhours_selection_changed(current_user.workhours[0])
                            dialog.close()
                            ui.notify("Eintrag gelöscht"
                                      "")
                        with ui.dialog() as dialog, ui.card():
                            current_user = user(user_selection.value)
                            if len(current_user.workhours) > 1:
                                ui.markdown(f"Soll der Eintrag *{workhours_select.value}* wirklich gelöscht werden?")
                                ui.markdown("**Dies kann nicht rückgängig gemacht werden.**")
                                with ui.row():
                                    ui.button("Löschen", on_click=delete_entry)
                                    ui.button("Abbrechen", on_click=dialog.close)
                            else:
                                ui.markdown("Es gibt nur einen Eintrag. Dieser kann nicht gelöscht werden.")
                                ui.button("OK", on_click=dialog.close)
                        dialog.open()

                    def dialog_new_user():
                        def create_new_user():
                            if user_name_input.validate():

                                new_user(user_name_input.value)
                                update_userlist()
                                time_user.set_options(userlist)
                                user_ui.refresh()
                                dialog.close()
                            else:
                                ui.notify("Ungültiger Benutzername")

                        with ui.dialog() as dialog, ui.card():
                            ui.markdown("Geben Sie den Benutzernamen für das neue Konto an:")
                            user_name_input = ui.input(label="Benutzername", validation={'Leerer Benutzername nicht erlaubt': lambda value: len(value) != 0,
                                                                                         'Leerzeichen im Benutzername nicht erlaubt': lambda value: " " not in value})
                            with ui.row():
                                ui.button("OK", on_click=create_new_user)
                                ui.button("Abbrechen", on_click=dialog.close)
                        dialog.open()

                    @ui.refreshable
                    def user_ui():
                        userlist = list_users()
                        userlist.sort()

                        with ui.column():
                            global user_selection
                            user_selection = ui.select(options=userlist, with_input=True, on_change=user_selection_changed)
                            user_selection.value = userlist[0]
                            ui.button("Neu", on_click=dialog_new_user)
                    user_ui()

                    with ui.column():
                        @ui.refreshable
                        def usersettings_card():
                            global usersettingscard
                            with ui.card() as usersettingscard:
                                ui.markdown("**Benutzereinstellungen**")
                                with ui.grid(columns="auto 1fr") as usersettingsgrid:

                                    ui.markdown("Benutzername:")
                                    global username_input
                                    username_input = ui.input()
                                    ui.markdown("Voller Name:")
                                    global fullname_input
                                    fullname_input = ui.input()
                                    ui.markdown("Passwort")
                                    global password_input
                                    password_input = ui.input(password=True)
                                    password_input.value = ""
                                    ui.markdown("API-Schlüssel:")
                                    with ui.row():
                                        global api_key_input
                                        api_key_input = ui.input().props('size=37')
                                        def new_api_key():
                                            api_key_input.value = hashlib.shake_256(bytes(f'{username_input.value}_{datetime.datetime.now().timestamp()}', 'utf-8')).hexdigest(20)

                                        ui.button("Neu", on_click=new_api_key).tooltip("Neuen API-Schlüssel erzeugen. Wird erst beim Klick auf Speichern übernommen und entsprechende Links und QR-Codes aktualisiert")
                                    ui.markdown('Aufruf zum Stempeln:')
                                    global api_link_column
                                    with ui.column().classes('gap-0') as api_link_column:
                                        global stamp_link
                                        stamp_link = [ ]
                                        for i in app.urls:
                                            stamp_link.append(ui.link(f'{i}/api/stamp/"API-Schüssel"'))


                                with ui.grid(columns=2):
                                    ui.button("Speichern", on_click=save_user_settings).tooltip("Klicken Sie hier um die Änderungen zu speichern.")
                                    ui.button("Löschen", on_click=del_user)

                        usersettings_card()

                        with ui.card() as photocard:
                            ui.markdown('**Foto**')
                            current_user = user(user_selection.value)
                            user_photo = ui.image(current_user.photofile)

                            def handle_upload(e: events.UploadEventArguments):
                                picture = e.content.read()
                                current_user = user(user_selection.value)
                                with open(current_user.photofile, 'wb') as outoutfile:
                                    outoutfile.write(picture)
                                uploader.reset()
                                user_selection_changed()


                            def del_photo():
                                current_user = user(user_selection.value)
                                current_user.delete_photo()
                                user_selection_changed()

                            uploader = ui.upload(label="Foto hochladen", on_upload=handle_upload).props('accept=.jpg|.jpeg').classes('max-w-full')
                            delete_button = ui.button("Löschen", on_click=del_photo)


                        with ui.card() as workinghourscard:
                            workhours = []
                            ui.markdown("**Arbeitszeiten**")

                            with ui.card():

                                def calculate_weekhours():
                                    sum = 0
                                    for i in range(7):
                                        try:
                                            sum = float(days[i].value) + sum
                                        except:
                                            pass
                                    workhours_sum.set_content(str(sum))

                                with ui.grid(columns=2):
                                    ui.markdown("gültig ab:")
                                    workhours_select = ui.select(options=workhours, on_change=workhours_selection_changed)

                                    days = [ ]
                                    weekdays = ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag"]
                                    counter = 0
                                    for day in weekdays:
                                        ui.markdown(f"{day}:")
                                        days.append(ui.input(on_change=calculate_weekhours))
                                        counter = counter + 1
                                    ui.separator().classes('col-span-full')
                                    ui.markdown("**Summe:**")
                                    workhours_sum = ui.markdown()

                            with ui.card():
                                with ui.grid(columns=2):
                                    ui.markdown("Urlaubstage")
                                    vacation_input = ui.input()
                            with ui.row():
                                ui.button("Speichern", on_click=save_workhours)
                                ui.button("Löschen", on_click=delete_workhour_entry)

                            def new_workhours_entry():
                                current_user = user(user_selection.value)

                                def add_workhours_entry():
                                    workhours_dict = { }
                                    for i in range(7):
                                        workhours_dict[i] = 0
                                    workhours_dict["vacation"] = 0
                                    current_user.workhours[date_picker.value] = workhours_dict
                                    current_user.write_settings()

                                    workhours_select.clear()
                                    workhours_list = list(current_user.workhours)
                                    workhours_list.sort()
                                    workhours_select.set_options(workhours_list)
                                    workhours_select.value = date_picker.value

                                    dialog.close()
                                    ui.notify("Eintrag angelegt")

                                with ui.dialog() as dialog, ui.card():
                                    ui.markdown("Geben Sie das Gültigkeitsdatum an, ab wann die Einträge gültig sein sollen.")
                                    date_picker = ui.date()

                                    with ui.row():
                                        ui.button("OK", on_click=add_workhours_entry)
                                        ui.button("Abbrechen", on_click=dialog.close)
                                dialog.open()
                            ui.button("Neu", on_click=new_workhours_entry)
                user_selection_changed()

    # Alternativ zur Loginseite navigieren
    else:
        login = login_mask()
        #ui.navigate.to("/login")