package de.kif.backend.route

import de.kif.backend.authenticateOrRedirect
import de.kif.backend.repository.TrackRepository
import de.kif.backend.repository.WorkGroupRepository
import de.kif.backend.view.MainTemplate
import de.kif.backend.view.MenuTemplate
import de.kif.backend.view.TableTemplate
import de.kif.backend.view.respondMain
import de.kif.common.Search
import de.kif.common.model.*
import io.ktor.application.call
import io.ktor.html.insert
import io.ktor.html.respondHtmlTemplate
import io.ktor.request.receiveParameters
import io.ktor.response.respondRedirect
import io.ktor.routing.Route
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.util.toMap
import kotlinx.css.CSSBuilder
import kotlinx.css.Display
import kotlinx.html.*
import kotlin.collections.set

fun Route.workGroup() {
    get("workgroups") {
        authenticateOrRedirect(Permission.WORK_GROUP) { user ->
            val search = call.parameters["search"] ?: ""
            val list = WorkGroupRepository.all()
            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.WORK_GROUP
                }
                content {
                    insert(TableTemplate()) {
                        searchValue = search

                        action {
                            a("/tracks") {
                                button(classes = "form-btn") {
                                    +"Edit tracks"
                                }
                            }
                            a("/workgroup/new") {
                                button(classes = "form-btn btn-primary") {
                                    +"Add work group"
                                }
                            }
                        }

                        header {
                            th {
                                +"Name"
                            }
                            th {
                                +"Length"
                            }
                            th {
                                +"Interested"
                            }
                            th {
                                +"Track"
                            }
                            th {
                                +"Projector"
                            }
                            th {
                                +"Resolution"
                            }
                            th {
                                +"Language"
                            }
                            th(classes = "action") {
                                +"Action"
                            }
                        }

                        for (u in list) {
                            val s = u.createSearch()
                            entry {
                                attributes["style"] = CSSBuilder().apply {
                                    display = if (Search.match(search, s)) Display.tableRow else Display.none
                                }.toString()
                                attributes["data-search"] = s.stringify()
                                attributes["data-edit"] = "workgroup"
                                attributes["data-id"] = u.id.toString()

                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-name"

                                        +u.name
                                    }
                                }
                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-length"

                                        +u.length.toString()
                                    }
                                }
                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-interested"

                                        +u.interested.toString()
                                    }
                                }
                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-track"

                                        +(u.track?.name ?: "")
                                    }
                                }
                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-projector"

                                        +u.projector.toString()
                                    }
                                }
                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-resolution"

                                        +u.resolution.toString()
                                    }
                                }
                                td {
                                    span {
                                        attributes["data-edit-type"] = "workgroup-language"

                                        +u.language.localeName
                                    }
                                }
                                td(classes = "action") {
                                    a("/workgroup/${u.id}") {
                                        i("material-icons") { +"edit" }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    get("/workgroup/{id}") {
        authenticateOrRedirect(Permission.WORK_GROUP) { user ->
            val workGroupId = call.parameters["id"]?.toLongOrNull() ?: return@get
            val editWorkGroup = WorkGroupRepository.get(workGroupId) ?: return@get
            val tracks = TrackRepository.all()

            val workGroups = editWorkGroup.constraints.mapNotNull {
                when (it.type) {
                    ConstraintType.NotAtSameTime -> it.number
                    ConstraintType.OnlyAfterWorkGroup -> it.number
                    else -> null
                }
            }.distinct().associateWith {
                WorkGroupRepository.get(it)!!
            }

            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.WORK_GROUP
                }
                content {
                    h1 { +"Edit work group" }
                    form(method = FormMethod.post) {
                        div("form-group") {
                            label {
                                htmlFor = "name"
                                +"Name"
                            }
                            input(
                                name = "name",
                                classes = "form-control"
                            ) {
                                id = "name"
                                placeholder = "Name"
                                value = editWorkGroup.name
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "description"
                                +"Description"
                            }
                            textArea(rows = "10", classes = "form-control") {
                                name = "description"
                                id = "description"

                                +editWorkGroup.description
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "interested"
                                +"Interested"
                            }
                            input(
                                name = "interested",
                                classes = "form-control",
                                type = InputType.number
                            ) {
                                id = "interested"
                                value = editWorkGroup.interested.toString()

                                min = "0"
                                max = "1337"
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "track"
                                +"Track"
                            }
                            select(
                                classes = "form-control"
                            ) {
                                name = "track"

                                option {
                                    selected = (editWorkGroup.track?.id ?: -1) < 0
                                    value = "-1"
                                    +"None"
                                }
                                for (track in tracks) {
                                    option {
                                        selected = editWorkGroup.track?.id == track.id
                                        value = track.id.toString()
                                        +track.name
                                    }
                                }
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "length"
                                +"Length"
                            }
                            input(
                                name = "length",
                                classes = "form-control",
                                type = InputType.number
                            ) {
                                id = "length"
                                value = editWorkGroup.length.toString()

                                min = "0"
                                max = "1440"
                                step = "5"
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "language"
                                +"Language"
                            }
                            select(
                                classes = "form-control"
                            ) {
                                name = "language"

                                for (language in Language.values()) {
                                    option {
                                        selected = editWorkGroup.language == language
                                        value = language.code
                                        +language.localeName
                                    }
                                }
                            }
                        }

                        div("form-switch-group") {
                            div("form-group form-switch") {
                                input(
                                    name = "projector",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "projector"
                                    checked = editWorkGroup.projector
                                }
                                label {
                                    htmlFor = "projector"
                                    +"Projector"
                                }
                            }
                            div("form-group form-switch") {
                                input(
                                    name = "resolution",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "resolution"
                                    checked = editWorkGroup.resolution
                                }
                                label {
                                    htmlFor = "resolution"
                                    +"Resolution"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "internet",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "internet"
                                    checked = editWorkGroup.internet
                                }
                                label {
                                    htmlFor = "internet"
                                    +"Internet"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "whiteboard",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "whiteboard"
                                    checked = editWorkGroup.whiteboard
                                }
                                label {
                                    htmlFor = "whiteboard"
                                    +"Whiteboard"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "blackboard",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "blackboard"
                                    checked = editWorkGroup.blackboard
                                }
                                label {
                                    htmlFor = "blackboard"
                                    +"Blackboard"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "accessible",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "accessible"
                                    checked = editWorkGroup.accessible
                                }
                                label {
                                    htmlFor = "accessible"
                                    +"Accessible"
                                }
                            }
                        }

                        div("form-group work-group-constraints") {
                            label {
                                +"Constraints"
                            }
                            span("form-btn work-group-constraints-add") {
                                i("material-icons") { +"add" }
                            }
                            div("work-group-constraints-add-list") {

                            }
                            for ((index, constraint) in editWorkGroup.constraints.withIndex()) {
                                div("input-group") {
                                    when (constraint.type) {
                                        ConstraintType.OnlyOnDay -> {
                                            span("form-btn") {
                                                +"On day"
                                            }
                                            input(
                                                name = "constraint-only-on-day-$index",
                                                classes = "form-control",
                                                type = InputType.number
                                            ) {
                                                value = constraint.number.toString()

                                                min = "-1337"
                                                max = "1337"
                                            }
                                        }
                                        ConstraintType.OnlyAfterTime -> {
                                            span("form-btn") {
                                                +"After time"
                                            }
                                            input(
                                                name = "constraint-only-after-time-$index",
                                                classes = "form-control",
                                                type = InputType.number
                                            ) {
                                                value = constraint.number.toString()

                                                min = "-1337"
                                                max = "133700"
                                            }
                                        }
                                        ConstraintType.NotAtSameTime -> {
                                            span("form-btn") {
                                                +"Not with"
                                            }
                                            select(
                                                classes = "form-control"
                                            ) {
                                                name = "constraint-not-at-same-time-$index"

                                                option {
                                                    selected = true
                                                    value = constraint.number.toString()
                                                    +(workGroups[constraint.number]?.name ?: "")
                                                }
                                            }
                                        }
                                        ConstraintType.OnlyAfterWorkGroup -> {
                                            span("form-btn") {
                                                +"After AK"
                                            }
                                            select(
                                                classes = "form-control"
                                            ) {
                                                name = "constraint-only-after-work-group-$index"

                                                option {
                                                    selected = true
                                                    value = constraint.number.toString()
                                                    +(workGroups[constraint.number]?.name ?: "")
                                                }
                                            }
                                        }
                                    }

                                }
                            }
                        }

                        div("form-group") {
                            a("/workgroup") {
                                button(classes = "form-btn") {
                                    +"Cancel"
                                }
                            }
                            button(type = ButtonType.submit, classes = "form-btn btn-primary") {
                                +"Save"
                            }
                        }
                    }
                    a("/workgroup/${editWorkGroup.id}/delete") {
                        button(classes = "form-btn btn-danger") {
                            +"Delete"
                        }
                    }
                }
            }
        }
    }

    post("/workgroup/{id}") {
        authenticateOrRedirect(Permission.WORK_GROUP) { user ->
            val workGroupId = call.parameters["id"]?.toLongOrNull() ?: return@post
            val params = call.receiveParameters().toMap().mapValues { (_, list) ->
                list.firstOrNull()
            }
            var editWorkGroup = WorkGroupRepository.get(workGroupId) ?: return@post

            params["name"]?.let { editWorkGroup = editWorkGroup.copy(name = it) }
            params["description"]?.let { editWorkGroup = editWorkGroup.copy(description = it) }
            params["interested"]?.toIntOrNull()?.let { editWorkGroup = editWorkGroup.copy(interested = it) }
            params["track"]?.toLongOrNull()?.let {
                val track = TrackRepository.get(it)
                editWorkGroup = editWorkGroup.copy(track = track)
            }
            params["projector"]?.let { editWorkGroup = editWorkGroup.copy(projector = it == "on") }
            params["resolution"]?.let { editWorkGroup = editWorkGroup.copy(resolution = it == "on") }
            params["internet"]?.let { editWorkGroup = editWorkGroup.copy(internet = it == "on") }
            params["whiteboard"]?.let { editWorkGroup = editWorkGroup.copy(whiteboard = it == "on") }
            params["blackboard"]?.let { editWorkGroup = editWorkGroup.copy(blackboard = it == "on") }
            params["accessible"]?.let { editWorkGroup = editWorkGroup.copy(accessible = it == "on") }

            params["length"]?.toIntOrNull()?.let { editWorkGroup = editWorkGroup.copy(length = it) }
            params["language"]?.let {
                editWorkGroup =
                    editWorkGroup.copy(language = Language.values().find { l -> l.code == it } ?: Language.GERMAN)
            }

            val constraints = params.mapNotNull { (key, value)  ->
                when {
                    key.startsWith("constraint-only-on-day") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyOnDay, it) }
                    }
                    key.startsWith("constraint-only-after-time") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterTime, it) }
                    }
                    key.startsWith("constraint-not-at-same-time") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.NotAtSameTime, it) }
                    }
                    key.startsWith("constraint-only-after-work-group") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterWorkGroup, it) }
                    }
                    else -> null
                }
            }

            editWorkGroup = editWorkGroup.copy(constraints = constraints)

            WorkGroupRepository.update(editWorkGroup)

            call.respondRedirect("/workgroups")
        }
    }

    get("/workgroup/new") {
        authenticateOrRedirect(Permission.WORK_GROUP) { user ->
            val tracks = TrackRepository.all()
            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.WORK_GROUP
                }
                content {
                    h1 { +"Create work group" }
                    form(method = FormMethod.post) {
                        div("form-group") {
                            label {
                                htmlFor = "name"
                                +"Name"
                            }
                            input(
                                name = "name",
                                classes = "form-control"
                            ) {
                                id = "name"
                                placeholder = "Name"
                                value = ""
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "description"
                                +"Description"
                            }
                            textArea(rows = "10", classes = "form-control") {
                                name = "description"
                                id = "description"

                                +""
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "interested"
                                +"Interested"
                            }
                            input(
                                name = "interested",
                                classes = "form-control",
                                type = InputType.number
                            ) {
                                id = "interested"
                                value = "0"

                                min = "0"
                                max = "1337"
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "track"
                                +"Track"
                            }
                            select(
                                classes = "form-control"
                            ) {
                                name = "track"

                                option {
                                    selected = true
                                    value = "-1"
                                    +"None"
                                }
                                for (track in tracks) {
                                    option {
                                        value = track.id.toString()
                                        +track.name
                                    }
                                }
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "length"
                                +"Length"
                            }
                            input(
                                name = "length",
                                classes = "form-control",
                                type = InputType.number
                            ) {
                                id = "length"
                                value = "0"

                                min = "0"
                                max = "1440"
                                step = "5"
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "language"
                                +"Language"
                            }
                            select(
                                classes = "form-control"
                            ) {
                                name = "language"

                                for (language in Language.values()) {
                                    option {
                                        selected = language == Language.GERMAN
                                        value = language.code
                                        +language.localeName
                                    }
                                }
                            }
                        }

                        div("form-switch-group") {
                            div("form-group form-switch") {
                                input(
                                    name = "projector",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "projector"
                                    checked = false
                                }
                                label {
                                    htmlFor = "projector"
                                    +"Projector"
                                }
                            }
                            div("form-group form-switch") {
                                input(
                                    name = "resolution",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "resolution"
                                    checked = false
                                }
                                label {
                                    htmlFor = "resolution"
                                    +"Resolution"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "internet",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "internet"
                                    checked = false
                                }
                                label {
                                    htmlFor = "internet"
                                    +"Internet"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "whiteboard",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "whiteboard"
                                    checked = false
                                }
                                label {
                                    htmlFor = "whiteboard"
                                    +"Whiteboard"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "blackboard",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "blackboard"
                                    checked = false
                                }
                                label {
                                    htmlFor = "blackboard"
                                    +"Blackboard"
                                }
                            }

                            div("form-group form-switch") {
                                input(
                                    name = "accessible",
                                    classes = "form-control",
                                    type = InputType.checkBox
                                ) {
                                    id = "accessible"
                                    checked = false
                                }
                                label {
                                    htmlFor = "accessible"
                                    +"Accessible"
                                }
                            }
                        }

                        div("form-group work-group-constraints") {
                            label {
                                +"Constraints"
                            }
                            span("form-btn work-group-constraints-add") {
                                i("material-icons") { +"add" }
                            }
                            div("work-group-constraints-add-list") {

                            }
                        }

                        div("form-group") {
                            a("/workgroup") {
                                button(classes = "form-btn") {
                                    +"Cancel"
                                }
                            }
                            button(type = ButtonType.submit, classes = "form-btn btn-primary") {
                                +"Create"
                            }
                        }
                    }
                }
            }
        }
    }

    post("/workgroup/new") {
        authenticateOrRedirect(Permission.WORK_GROUP) { user ->
            val params = call.receiveParameters().toMap().mapValues { (_, list) ->
                list.firstOrNull()
            }

            val name = params["name"] ?: return@post
            val description = params["description"] ?: return@post
            val interested = (params["interested"] ?: return@post).toIntOrNull() ?: 0
            val track = (params["track"] ?: return@post).toLongOrNull()?.let { TrackRepository.get(it) }
            val projector = params["projector"] == "on"
            val resolution = params["resolution"] == "on"
            val length = (params["length"] ?: return@post).toIntOrNull() ?: 0
            val language = (params["language"] ?: return@post).let {
                Language.values().find { l -> l.code == it } ?: Language.GERMAN
            }

            val internet = params["internet"] == "on"
            val whiteboard = params["whiteboard"] == "on"
            val blackboard = params["blackboard"] == "on"
            val accessible = params["accessible"] == "on"

            val constraints = params.mapNotNull { (key, value)  ->
                when {
                    key.startsWith("constraint-only-on-day") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyOnDay, it) }
                    }
                    key.startsWith("constraint-only-after-time") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterTime, it) }
                    }
                    key.startsWith("constraint-not-at-same-time") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.NotAtSameTime, it) }
                    }
                    key.startsWith("constraint-only-after-work-group") -> {
                        value?.toLongOrNull()?.let { Constraint(ConstraintType.OnlyAfterWorkGroup, it) }
                    }
                    else -> null
                }
            }

            val workGroup = WorkGroup(
                null,
                name = name,
                description = description,
                interested = interested,
                track = track,
                projector = projector,
                resolution = resolution,
                internet = internet,
                whiteboard = whiteboard,
                blackboard = blackboard,
                accessible = accessible,
                length = length,
                language = language,
                constraints = constraints
            )

            WorkGroupRepository.create(workGroup)

            call.respondRedirect("/workgroups")
        }
    }

    get("/workgroup/{id}/delete") {
        authenticateOrRedirect(Permission.WORK_GROUP) { user ->
            val workGroupId = call.parameters["id"]?.toLongOrNull() ?: return@get

            WorkGroupRepository.delete(workGroupId)

            call.respondRedirect("/workgroups")
        }
    }
}
