<script setup lang="ts">

import {computed, onMounted, reactive, ref, toRaw, watch} from "vue";
import TablePlan from "@/components/TablePlan.vue";
import {API, UnauthorizedError} from "@/services/api";
import type {Gottesdienst, GottesdienstGroup, Mark, SimplifiedMinistrant} from "@/models/models";
import MobilePlan from "@/components/MobilePlan.vue";
import ListView from "@/components/ListView.vue";
import PlanActionBar from "@/components/PlanActionBar.vue";
import {Auth} from "@/services/auth";
import GroupView from "@/components/GroupView.vue";
import {Dialogs} from "@/services/DialogService";
import ConfirmDialog from "@/components/dialog/ConfirmDialog.vue";
import CreatePlanDialog from "@/components/dialog/CreatePlanDialog.vue";
import CreateGottesdienstDialog from "@/components/dialog/CreateGottesdienstDialog.vue";
import CreateMinistrantDialog from "@/components/dialog/CreateMinistrantDialog.vue";
import {useRoute, useRouter} from "vue-router";
import debounce from "underscore/modules/debounce.js"
import SavingIndicator from "@/components/SavingIndicator.vue";
import ImportZelebrationsplanDialog from "@/components/dialog/ImportZelebrationsplanDialog.vue";
import {LoginService} from "@/services/LoginService";

const MAX_WIDTH_MOBILE = 600;

const router = useRouter()
const route = useRoute()

const plan = reactive<{
    gottesdienste: Gottesdienst[],
    ministranten: SimplifiedMinistrant[],
    marks: Mark[],
    editable: string[],
    groups: GottesdienstGroup[]
}>({
    gottesdienste: [],
    ministranten: [],
    marks: [],
    editable: [],
    groups: []
})
const mobile = ref(window.innerWidth <= MAX_WIDTH_MOBILE)
const viewMode = ref<"table" | "list">("table")
const currentUsername = ref("")
const editedMarks = reactive<Mark[]>([]);
const editPlanAdmin = ref(false)
const planId = ref(parseInt(route.params.id as string))
const isSaving = ref(false)


onMounted(async () => {
    const groups = await API.getPlans()
    console.log("Groups", groups)
    plan.groups = groups
    loadPlan()
})

watch(() => route.params.id, async (value, oldValue) => {
    planId.value = parseInt(value as string)
    await loadPlan()
})

async function loadPlan() {
    try {
        const { ministranten, gottesdienste, marks} = await API.getPlan(planId.value)
        plan.ministranten = ministranten
        plan.gottesdienste = gottesdienste
        plan.marks = marks
        Auth.checkForToken()
    } catch (e: any) {
        if(e instanceof UnauthorizedError) {
            LoginService.showLoginPopup()
            let subscription = Auth.loggedInSubject.subscribe((loggedIn) => {
                subscription.unsubscribe()
                if(loggedIn) {
                    loadPlan()
                }
            })
        }
    }
}

Auth.loggedInSubject.subscribe(async (loggedIn) => {
    console.log("logged in " + loggedIn)
    if (loggedIn) {
        currentUsername.value = Auth.getUser()
        plan.editable = Auth.getPrivileges()
        if (Auth.getUser() == "admin") {
            editPlanAdmin.value = true
            plan.ministranten = await API.getMinistranten();
            console.log("Plan", plan.ministranten)
        }
    } else {
        currentUsername.value = ""
        editPlanAdmin.value = false
        plan.editable = []
    }
})

window.addEventListener("resize", (ev) => {
    mobile.value = window.innerWidth <= MAX_WIDTH_MOBILE
})


const sortedGottesdienste = computed(() => {
    return plan.gottesdienste.sort((a, b) => {
        return a.date - b.date
    })
})

async function createGottesdienst(gottesdienstId?: number){
    let gottesdienstRef = plan.gottesdienste.find(gottesdienst => gottesdienst.id == gottesdienstId)
    let gottesdienst = gottesdienstRef ? Object.assign({}, toRaw(gottesdienstRef)) : null;
    Dialogs.createDialog(CreateGottesdienstDialog, {
        onPositive() {},
        onNegative() {},
        onDismiss() {}
    }, {
        gottesdienst,
        planId: parseInt(planId.value as unknown),
        async onCreate(godi: Gottesdienst) {
            if(godi.id == -1) {
                const newGodi = await API.addGottesdienstNew(godi)
                godi.id = newGodi.id
                plan.gottesdienste.push(godi)
            } else {
                await API.updateGottesdienst(godi)
                const index = plan.gottesdienste.findIndex(g => g.id == godi.id)
                plan.gottesdienste.splice(index, 1)
                plan.gottesdienste.push(godi)
            }
        },
        onDelete: gottesdienst ? () => deleteGottedienst(gottesdienst.id) : undefined
    })
}

async function addGodi(data, validate) {
    console.log("Test")
    console.log(data)
    let date = Date.parse(data.date + "T" + data.time);
    let attendance = data.attendance && data.attendance != ""
        ? Date.parse(data.date + "T" + data.attendance)
        : (date - 1000 * 60 * 30)
    console.log(date, attendance, data.date + "T" + data.attendance)
    let newGodi = await API.addGottesdienst(
        data.name,
        new Date(date),
        new Date(attendance),
        parseInt(planId.value as string)
    )
    console.log(newGodi)
    plan.gottesdienste.push(newGodi);
    validate()
}

async function deleteGottedienst(id) {
    let deleted = await API.deleteGottesdienst(id)
    if (deleted) {
        let index = plan.gottesdienste.findIndex(godi => godi.id == id)
        plan.gottesdienste.splice(index, 1)
    }
}


function getMarks(): Mark[] {
    return plan.marks.filter((mark: Mark) => {
        let difMark = editedMarks.find((m: Mark) => m.gid == mark.gid && m.mid == mark.mid)
        return !difMark
    }).concat(editedMarks);
}

function getDif(): Mark[] {
    return editedMarks.filter((mark: Mark) => {
        let sameMark = plan.marks.find((m: Mark) => m.gid == mark.gid && m.mid == mark.mid)
        return (!sameMark && mark.value != 0) || (sameMark && mark.value != sameMark.value)
    })
}


const saveChanges = debounce(saveChangesFunc, 600)

async function saveChangesFunc() {
    const saved = await API.setMarks(getDif())
    if (saved) {
        isSaving.value = false
    }
}

async function resetPassword(username: string) {
    const result = await API.resetPassword(username)
    alert("Neues Passwort für " + username + "\n\n" + result.password)
    console.log(result)
}

function canEdit(username: string) {
    return plan.editable.includes(username)
}


function toggleMark(gid, mid) {
    // TODO: track changes
    const username = plan.ministranten.find(m => m.id == mid)?.username
    if (!canEdit(username)) return;

    let mark = editedMarks.find(m => m.mid == mid && m.gid == gid);
    if(!mark) {
        let markFromPlan = plan.marks.find(m => m.gid == gid && m.mid == mid)
        if(markFromPlan) {
            mark = {
                ...markFromPlan
            }
            editedMarks.push(mark)
        }
    }
    console.log(mark, editedMarks, plan.marks)
    if (mark) {
        mark.value = ((mark.value + 2) % 3) - 1
    } else {
        mark = {
            gid, mid, value: 1
        }
        editedMarks.push(mark)
    }

    isSaving.value = true
    saveChanges()
}


async function createNewPlan() {
    Dialogs.createDialog(CreatePlanDialog, {
        onPositive: () => {},
        onNegative: () => {},
        onDismiss: () => {},
    }, {
        onCreate: async (group: GottesdienstGroup) => {
            const newPlan = await API.createPlan(new Date(group.from).getTime(), new Date(group.to).getTime());
            plan.groups = [newPlan].concat(toRaw(plan.groups))
            router.replace("/" + newPlan.id)
        }
    })
}

async function deletePlan(id) {
    if(!confirm("Möchtest du den Plan wirklich löschen?")) return
    await API.deletePlan(id)
    location.reload()
    plan.groups.splice(plan.groups.findIndex(g => g.id == id), 1)
}

async function editPlan(id) {
    const group = Object.assign({}, toRaw(plan.groups.find(g => g.id == id)))
    group.from = new Date(group.from).toISOString().substring(0,10)
    group.to = new Date(group.to).toISOString().substring(0,10)
    Dialogs.createDialog(CreatePlanDialog, {
        onPositive() {},
        onNegative() {},
        onDismiss() {}
    }, {
        group,
        async onCreate(group) {
            group.from = new Date(group.from).getTime()
            group.to = new Date(group.to).getTime()
            await API.updatePlan(group)
            location.reload()
        }
    })
}

async function createMinistrant(ministrantId?: number) {
    let ministrantRef = plan.ministranten.find(ministrant => ministrant.id == ministrantId)
    const ministrant = ministrantRef ? Object.assign({}, toRaw(ministrantRef)) : null;
    console.log("Found mini ref?", ministrant)
    Dialogs.createDialog(CreateMinistrantDialog, {
        onPositive() {},
        onNegative() {},
        onDismiss() {}
    }, {
        ministrant,
        async onCreate(ministrant) {
            ministrant.birthday = ministrant.birthday.getTime()
            if(ministrant.id == -1) {
                const newMinistrant = await API.createMinistrant(ministrant)
                ministrant.id = newMinistrant.id
                plan.ministranten.push(ministrant)
            }else {
                await API.updateMinistrant(ministrant)
                const index = plan.ministranten.findIndex(m => m.id == ministrant.id)
                plan.ministranten.splice(index, 1)
                plan.ministranten.push(ministrant)
            }
        },
        async onDelete(id) {
            let deleted = await API.deleteMinistrant(id)
            if (deleted) {
                let index = plan.ministranten.findIndex(godi => godi.id == id)
                plan.ministranten.splice(index, 1)
            }
        }
    })
}

async function importZelebrationsplan() {
    Dialogs.createDialog(ImportZelebrationsplanDialog, {
        onPositive() {},
        onNegative() {},
        onDismiss() {}
    }, {
        planId: planId.value,
        async onImport(godis: Gottesdienst[]) {
            plan.gottesdienste.push(...godis)
        }
    })
}


</script>

<template>
    <main>

        <div class="container" :class="{
            'mobile-view': mobile && viewMode === 'table'
        }">

            <GroupView :groups="plan.groups" :admin="editPlanAdmin"
                       @new="createNewPlan" @delete="deletePlan" @edit="editPlan" class="no-print"/>


            <ListView
                :gottesdienste="sortedGottesdienste"
                :ministranten="plan.ministranten"
                :marks="getMarks()"
                :editable="plan.editable"
                :current-username="currentUsername"
                :admin="editPlanAdmin"
                @toggle-mark="toggleMark"
                @add-gottesdienst="createGottesdienst()"
                @add-ministrant="createMinistrant()"
                @edit-ministrant="(id) => createMinistrant(id)"
                @edit-gottesdienst="(id) => createGottesdienst(id)"
                @import-zelebrationsplan="importZelebrationsplan()"
                class="plan list"
                v-if="viewMode === 'list'">

            </ListView>

            <template v-if="viewMode === 'table'">

                <PlanActionBar
                    class="action-bar no-print"
                    :save="getDif().length > 0"
                    :plan="false"
                    :godi="true"
                    @save="saveChanges()"
                    @add-godi="createGottesdienst()"
                    @add-mini="createMinistrant()"
                    @import-zelebrationsplan="importZelebrationsplan()"
                    v-if="editPlanAdmin"
                />
                
                <TablePlan
                    :gottesdienste="sortedGottesdienste"
                    :ministranten="plan.ministranten"
                    :marks="getMarks()"
                    :editable="plan.editable"
                    :edit="editPlanAdmin"
                    :small-mode="editPlanAdmin"
                    @added="addGodi"
                    @delete="deleteGottedienst"
                    @edit="createGottesdienst"
                    @toggle-mark="toggleMark"
                    @end-edit="editPlanAdmin = false"
                    @reset-password="resetPassword"
                    @create-ministrant="createMinistrant"
                    @edit-ministrant="createMinistrant"
                    class="plan table"
                    v-if="!mobile">

                </TablePlan>

                <MobilePlan
                    :gottesdienste="sortedGottesdienste"
                    :ministranten="plan.ministranten"
                    :marks="getMarks()"
                    :editable="plan.editable"
                    @toggle-mark="toggleMark"
                    class="plan mobile"
                    v-else>

                </MobilePlan>
            </template>

            <div class="view-toggle no-print" v-if="plan.gottesdienste.length > 0">
                <button
                    class="flat"
                    :class="{ active: viewMode === 'table' }"
                    @click="viewMode = 'table'"
                ><i>table_rows</i> Tabelle</button>
                <button
                    class="flat"
                    :class="{ active: viewMode === 'list' }"
                    @click="viewMode = 'list'"
                ><i>list</i> Liste</button>
            </div>

            <SavingIndicator :visible="isSaving"/>
        </div>
    </main>
</template>


<style scoped lang="less">

.container {
    width: 100%;
    overflow-x: auto;

    @media print {
        overflow-x: unset;
    }
}

.plan {
    padding-bottom: 24px;
}

.plan.table {
    //width: 100%;
}

.container .view-toggle {
    display: flex;
    justify-content: center;
    gap: 4px;
    padding: 8px 12px;

    button {
        font-size: 14px;
        padding: 6px 14px;

        i {
            font-size: 18px;
        }

        &.active {
            background: #e0e0e0;
            border-color: #c4c4c4;
        }
    }
}

.container.mobile-view {
    .plan.list {
        flex: 1;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
}

.action-bar {
    position: sticky;
    top: 0;
    z-index: 100;
}
</style>
