package de.kif.backend.route


import de.kif.backend.authenticateOrRedirect
import de.kif.backend.hashPassword
import de.kif.backend.repository.UserRepository
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.Permission
import de.kif.common.model.User
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.component1
import kotlin.collections.component2
import kotlin.collections.set

fun Route.user() {
    get("/users") { param ->
        authenticateOrRedirect(Permission.USER) { user ->
            val search = call.parameters["search"] ?: ""
            val list = UserRepository.all()
            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.USER
                }
                content {
                    insert(TableTemplate()) {
                        searchValue = search

                        action {
                            a("/user/new") {
                                button(classes = "form-btn btn-primary") {
                                    +"Add user"
                                }
                            }
                        }

                        header {
                            th {
                                +"Username"
                            }
                            th {
                                +"Permissions"
                            }
                            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()
                                td {
                                    +u.username
                                }
                                td {
                                    +u.permissions.joinToString(", ") { it.toString().toLowerCase() }
                                }
                                td(classes = "action") {
                                    a("/user/${u.id}") {
                                        i("material-icons") { +"edit" }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    get("/user/{id}") {
        authenticateOrRedirect(Permission.USER) { user ->
            val userId = call.parameters["id"]?.toLongOrNull() ?: return@get
            val editUser = UserRepository.get(userId) ?: return@get
            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.USER
                }
                content {
                    h1 { +"Edit user" }
                    form(method = FormMethod.post) {
                        div("form-group") {
                            label {
                                htmlFor = "username"
                                +"Username"
                            }
                            input(
                                name = "username",
                                classes = "form-control"
                            ) {
                                id = "username"
                                placeholder = "Username"
                                value = editUser.username
                            }
                        }

                        div("form-switch-group") {
                            for (permission in Permission.values()) {
                                val name = permission.toString().toLowerCase()
                                div("form-group form-switch") {
                                    input(
                                        name = "permission-$name",
                                        classes = "form-control",
                                        type = InputType.checkBox
                                    ) {
                                        id = "permission-$name"
                                        checked = permission in editUser.permissions

                                        if (!user.checkPermission(permission)) {
                                            readonly = true
                                        }
                                    }
                                    label {
                                        htmlFor = "permission-$name"
                                        +name.capitalize()
                                    }
                                }
                            }
                        }

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

    post("/user/{id}") {
        authenticateOrRedirect(Permission.USER) { user ->
            val userId = call.parameters["id"]?.toLongOrNull() ?: return@post
            val params = call.receiveParameters().toMap().mapValues { (_, list) ->
                list.firstOrNull()
            }

            var editUser = UserRepository.get(userId) ?: return@post

            params["username"]?.let { editUser = editUser.copy(username = it) }

            val permissions = Permission.values().filter { permission ->
                val name = permission.toString().toLowerCase()
                user.checkPermission(permission) && params["permission-$name"] == "on"
            }.toSet()
            editUser = editUser.copy(permissions = permissions)

            UserRepository.update(user)

            call.respondRedirect("/users")
        }
    }

    get("/user/new") {
        authenticateOrRedirect(Permission.USER) { user ->
            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.USER
                }
                content {
                    h1 { +"Create user" }
                    form(method = FormMethod.post) {
                        div("form-group") {
                            label {
                                htmlFor = "username"
                                +"Username"
                            }
                            input(
                                name = "username",
                                classes = "form-control"
                            ) {
                                id = "username"
                                placeholder = "Username"
                                value = ""
                            }
                        }
                        div("form-group") {
                            label {
                                htmlFor = "password"
                                +"Password"
                            }
                            input(
                                name = "password",
                                classes = "form-control",
                                type = InputType.password
                            ) {
                                id = "password"
                                placeholder = "Password"
                                value = ""
                            }
                        }

                        div("form-switch-group") {
                            for (permission in Permission.values()) {
                                val name = permission.toString().toLowerCase()
                                div("form-group form-switch") {
                                    input(
                                        name = "permission-$name",
                                        classes = "form-control",
                                        type = InputType.checkBox
                                    ) {
                                        id = "permission-$name"
                                        checked = false

                                        if (!user.checkPermission(permission)) {
                                            readonly = true
                                        }
                                    }
                                    label {
                                        htmlFor = "permission-$name"
                                        +name.capitalize()
                                    }
                                }
                            }
                        }

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

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

            val username = params["username"] ?: return@post
            val password = params["password"] ?: return@post

            val permissions = Permission.values().mapNotNull { permission ->
                if (user.checkPermission(permission) && params["permission-${permission.toString().toLowerCase()}"] == "on")
                    permission
                else
                    null
            }.toSet()

            val newUser = User(null, username, hashPassword(password), permissions)

            UserRepository.create(newUser)

            call.respondRedirect("/users")
        }
    }

    get("/user/{id}/delete") {
        authenticateOrRedirect(Permission.USER) { user ->
            val userId = call.parameters["id"]?.toLongOrNull() ?: return@get
            val deleteUser = UserRepository.get(userId) ?: return@get

            if (user.checkPermission(Permission.USER) &&
                (Permission.ADMIN !in deleteUser.permissions || Permission.ADMIN in user.permissions)
            ) {
                UserRepository.delete(userId)
            }

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