package de.kif.backend.route

import de.kif.backend.authenticate
import de.kif.backend.authenticateOrRedirect
import de.kif.backend.util.Backup
import de.kif.backend.repository.TrackRepository
import de.kif.backend.repository.WorkGroupRepository
import de.kif.backend.route.api.error
import de.kif.backend.util.WikiImporter
import de.kif.backend.view.MainTemplate
import de.kif.backend.view.MenuTemplate
import de.kif.backend.view.respondMain
import de.kif.common.RepositoryType
import de.kif.common.model.Permission
import io.ktor.application.call
import io.ktor.html.respondHtmlTemplate
import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode
import io.ktor.http.content.PartData
import io.ktor.http.content.forEachPart
import io.ktor.http.content.streamProvider
import io.ktor.request.receiveMultipart
import io.ktor.request.receiveParameters
import io.ktor.response.respondRedirect
import io.ktor.response.respondText
import io.ktor.routing.Route
import io.ktor.routing.get
import io.ktor.routing.post
import io.ktor.util.toMap
import kotlinx.html.*
import mu.KotlinLogging

private val logger = KotlinLogging.logger {}

fun Route.account() {
    get("/account") {
        authenticateOrRedirect { user ->

            val tracks = TrackRepository.all()
            val wikiSections = WikiImporter.loadSections()

            respondMain {
                menuTemplate {
                    this.user = user
                    active = MenuTemplate.Tab.ACCOUNT
                }
                content {
                    h1 { +"Account" }
                    div {
                        +"Welcome ${user.username}!"
                        br {}
                        +"You have the following rights: ${user.permissions}"
                        br {}
                        a("/logout") {
                            button(classes = "form-btn") {
                                +"Logout"
                            }
                        }
                    }

                    div("account-backup") {
                        if (user.checkPermission(Permission.ROOM)) {
                            a("/account/backup/rooms.json", classes = "form-btn") {
                                attributes["download"] = "rooms-backup.json"
                                +"Create room backup"
                            }
                        }
                        if (user.checkPermission(Permission.USER)) {
                            a("/account/backup/users.json", classes = "form-btn") {
                                attributes["download"] = "users-backup.json"
                                +"Create user backup"
                            }
                        }
                        if (user.checkPermission(Permission.POST)) {
                            a("/account/backup/posts.json", classes = "form-btn") {
                                attributes["download"] = "posts-backup.json"
                                +"Create post backup"
                            }
                        }
                        if (user.checkPermission(Permission.WORK_GROUP)) {
                            a("/account/backup/work-groups.json", classes = "form-btn") {
                                attributes["download"] = "work-groups-backup.json"
                                +"Create work group backup"
                            }
                        }
                        if (
                            user.checkPermission(Permission.WORK_GROUP) &&
                            user.checkPermission(Permission.ROOM) &&
                            user.checkPermission(Permission.SCHEDULE)
                        ) {
                            a("/account/backup/schedules.json", classes = "form-btn") {
                                attributes["download"] = "schedules-backup.json"
                                +"Create schedule backup"
                            }
                        }

                        if (user.checkPermission(Permission.ADMIN)) {
                            a("/account/backup.json", classes = "form-btn") {
                                attributes["download"] = "backup.json"
                                +"Create backup"
                            }
                        }
                    }

                    if (user.checkPermission(Permission.ADMIN)) {
                        div("account-import") {
                            form(
                                action = "/account/import",
                                method = FormMethod.post,
                                encType = FormEncType.multipartFormData
                            ) {
                                div("form-group") {
                                    label {
                                        htmlFor = "backup"
                                        +"Backup image"
                                    }
                                    input(
                                        name = "backup",
                                        classes = "form-btn",
                                        type = InputType.file
                                    ) {
                                        id = "backup"
                                        value = "Select backup image"
                                        accept = ".json"
                                    }
                                }

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

                                div("form-group") {
                                    button(type = ButtonType.submit, classes = "form-btn btn-primary") {
                                        +"Import"
                                    }
                                }
                            }
                        }
                    }

                    if (user.checkPermission(Permission.ADMIN)) {
                        div("account-import-wiki") {
                            span { +"Import work group data from the kif wiki" }

                            form(action = "/account/import-wiki", method = FormMethod.post) {
                                for ((index, section) in wikiSections.withIndex()) {
                                    div("form-group") {
                                        label {
                                            htmlFor = "section-$index-track"
                                            +section
                                        }
                                        select(
                                            classes = "form-control"
                                        ) {
                                            name = "section-$index-track"

                                            option {
                                                selected = false
                                                value = "-1"
                                                +"Do not import"
                                            }
                                            option {
                                                selected = true
                                                value = "null"
                                                +"None"
                                            }
                                            for (track in tracks) {
                                                option {
                                                    selected = false
                                                    value = track.id.toString()
                                                    +track.name
                                                }
                                            }
                                        }
                                        input(type = InputType.hidden, name = "section-$index-name") {
                                            value = section
                                        }
                                    }
                                }

                                div("form-switch-group") {
                                    div("form-group form-switch") {
                                        input(
                                            name = "skip-existing",
                                            classes = "form-control",
                                            type = InputType.checkBox
                                        ) {
                                            id = "skip-existing"
                                            checked = false
                                        }
                                        label {
                                            htmlFor = "skip-existing"
                                            +"Skip existing work groups"
                                        }
                                    }
                                    div("form-group form-switch") {
                                        input(
                                            name = "delete-existing",
                                            classes = "form-control",
                                            type = InputType.checkBox
                                        ) {
                                            id = "delete-existing"
                                            checked = false
                                        }
                                        label {
                                            htmlFor = "delete-existing"
                                            +"Delete existing work groups"
                                        }
                                    }
                                }

                                button(type = ButtonType.submit, classes = "form-btn btn-primary") {
                                    +"Import wiki"
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    get("/account/backup/rooms.json") {
        authenticate(Permission.ROOM) {
            call.respondText(Backup.backup(RepositoryType.ROOM), ContentType.Application.Json, HttpStatusCode.OK)
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    get("/account/backup/users.json") {
        authenticate(Permission.USER) {
            call.respondText(Backup.backup(RepositoryType.USER), ContentType.Application.Json, HttpStatusCode.OK)
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    get("/account/backup/posts.json") {
        authenticate(Permission.POST) {
            call.respondText(Backup.backup(RepositoryType.POST), ContentType.Application.Json, HttpStatusCode.OK)
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    get("/account/backup/work-groups.json") {
        authenticate(Permission.WORK_GROUP) {
            call.respondText(Backup.backup(RepositoryType.WORK_GROUP), ContentType.Application.Json, HttpStatusCode.OK)
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    get("/account/backup/schedules.json") {
        authenticate(Permission.ROOM, Permission.WORK_GROUP, Permission.SCHEDULE) {
            call.respondText(Backup.backup(RepositoryType.SCHEDULE), ContentType.Application.Json, HttpStatusCode.OK)
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    get("/account/backup.json") {
        authenticate(Permission.ADMIN) {
            call.respondText(Backup.backup(*RepositoryType.values()), ContentType.Application.Json, HttpStatusCode.OK)
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    post("/account/import") {
        authenticate(Permission.ADMIN) {
            var reset = false
            var import = ""

            call.receiveMultipart().forEachPart { part ->
                val name = part.name ?: return@forEachPart
                when (part) {
                    is PartData.FormItem -> {
                        if (name == "reset" && part.value == "on") {
                            reset = true
                        }
                    }
                    is PartData.FileItem -> {
                        import = part.streamProvider().bufferedReader().readText()
                    }
                }
            }

            if (reset) {
                Backup.restore(import)
            } else {
                Backup.import(import)
            }

            call.respondRedirect("/account")
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }

    post("/account/import-wiki") {
        authenticate(Permission.ADMIN) {
            val params = call.receiveParameters().toMap().mapValues { (_, list) ->
                list.firstOrNull()
            }

            val skipExisting = params["skip-existing"] == "on"
            val deleteExisting = params["delete-existing"] == "on"

            val map = mutableMapOf<Int, Pair<String, Long?>>()

            for ((key, value) in params) {
                if (key.startsWith("section") && value != null) {
                    val numberedType = key.substringAfter("-")
                    val number = numberedType.substringBefore("-").toIntOrNull() ?: continue
                    val type = numberedType.substringAfter("-")
                    var pair = map.getOrElse(number) { "" to null }
                    if (type == "name") {
                        pair = value to pair.second
                    } else if (type == "track") {
                        pair = pair.first to value.toLongOrNull()
                    }
                    map[number] = pair
                }
            }

            val sections = map.values.toMap()

            var existingWorkGroups = WorkGroupRepository.all()

            if (deleteExisting) {
                for (wg in existingWorkGroups) {
                    if (wg.id != null) WorkGroupRepository.delete(wg.id)
                }
                existingWorkGroups = emptyList()
            }

            val existingWorkGroupNames = existingWorkGroups.map { it.name }.toSet()

            val importedWorkGroups = WikiImporter.import(sections = sections)

            var counter = 0
            for (workGroup in importedWorkGroups) {
                if (skipExisting && workGroup.name in existingWorkGroupNames) continue

                WorkGroupRepository.create(workGroup)
                counter++
            }

            logger.info { "Import $counter from ${importedWorkGroups.size} work groups!" }

            call.respondRedirect("/account")
        } onFailure {
            call.error(HttpStatusCode.Unauthorized)
        }
    }
}
