package de.kif.frontend.views.calendar

import de.kif.frontend.iterator
import de.kif.frontend.launch
import de.kif.frontend.repository.ScheduleRepository
import de.westermann.kwebview.View
import org.w3c.dom.*
import kotlin.browser.document
import kotlin.browser.window


class Calendar(calendar: HTMLElement) : View(calendar) {
    var calendarEntries: List<CalendarEntry> = emptyList()
    var calendarCells: List<CalendarCell> = emptyList()

    val day: Int

    val htmlTag = document.body as HTMLElement
    val calendarTable = calendar.getElementsByClassName("calendar-table")[0] as HTMLElement

    fun scrollVerticalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
        htmlTag.scrollBy(ScrollToOptions(0.0, pixel, scrollBehavior))
    }

    fun scrollHorizontalBy(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
        calendarTable.scrollBy(ScrollToOptions(pixel, 0.0, scrollBehavior))
    }

    fun scrollVerticalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
        htmlTag.scrollTo(ScrollToOptions(0.0, pixel, scrollBehavior))
    }

    fun scrollHorizontalTo(pixel: Double, scrollBehavior: ScrollBehavior = ScrollBehavior.SMOOTH) {
        calendarTable.scrollTo(ScrollToOptions(pixel, 0.0, scrollBehavior))
    }

    init {
        val editable = calendar.dataset["editable"]?.toBoolean() ?: false
        day = calendar.dataset["day"]?.toIntOrNull() ?: -1

        calendarEntries = document.getElementsByClassName("calendar-entry")
            .iterator().asSequence().map { CalendarEntry(this, it) }.onEach { it.editable = editable }.toList()

        calendarCells = document.getElementsByClassName("calendar-cell")
            .iterator().asSequence().filter { it.dataset["time"] != null }.map(::CalendarCell).toList()

        if (editable) {
            CalendarEdit(this, calendar.querySelector(".calendar-edit") as HTMLElement)
        }

        ScheduleRepository.onCreate {
            launch {
                val schedule = ScheduleRepository.get(it) ?: throw  NoSuchElementException()
                calendarEntries += CalendarEntry.create(this, schedule).also { it.editable = editable }
            }
        }
        ScheduleRepository.onUpdate {
            launch {
                val schedule = ScheduleRepository.get(it) ?: throw  NoSuchElementException()
                var found = false
                for (entry in calendarEntries) {
                    if (entry.scheduleId == it) {
                        entry.load(schedule)
                        found = true
                    }
                }
                if (!found) {
                    calendarEntries += CalendarEntry.create(this, schedule).also { it.editable = editable }
                }
            }
        }
        ScheduleRepository.onDelete {
            for (entry in calendarEntries) {
                if (entry.scheduleId == it) {
                    entry.html.remove()
                    calendarEntries -= entry
                }
            }
        }

        (document.getElementById("calendar-check-constraints") as? HTMLElement)?.let { wrap(it) }?.onClick?.addListener {
            launch {
                val errors = ScheduleRepository.checkConstraints()

                println(errors)

                for ((s, l) in errors.map) {
                    for (entry in calendarEntries) {
                        if (entry.scheduleId == s) {
                            entry.error = l.isNotEmpty()
                        }
                    }
                }
            }
        }

        onWheel {
            val multiplier = when (it.deltaMode) {
                1 -> 16.0
                2 -> window.innerHeight.toDouble()
                else -> 1.0
            }

            scrollHorizontalBy(it.deltaX * multiplier, ScrollBehavior.INSTANT)
            scrollVerticalBy(it.deltaY * multiplier, ScrollBehavior.INSTANT)

            it.preventDefault()
        }
    }
}

fun initCalendar() {
    Calendar(document.getElementsByClassName("calendar")[0] as? HTMLElement ?: return)
}